Trabajar con un marco de datos similar a este:
set.seed(100)
df <- data.frame(cat = c(rep("aaa", 5), rep("bbb", 5), rep("ccc", 5)), val = runif(15))
df <- df[order(df$cat, df$val), ]
df
cat val
1 aaa 0.05638315
2 aaa 0.25767250
3 aaa 0.30776611
4 aaa 0.46854928
5 aaa 0.55232243
6 bbb 0.17026205
7 bbb 0.37032054
8 bbb 0.48377074
9 bbb 0.54655860
10 bbb 0.81240262
11 ccc 0.28035384
12 ccc 0.39848790
13 ccc 0.62499648
14 ccc 0.76255108
15 ccc 0.88216552
Estoy tratando de agregar una columna con numeración dentro de cada grupo. Hacerlo de esta manera obviamente no está usando los poderes de R:
df$num <- 1
for (i in 2:(length(df[,1]))) {
if (df[i,"cat"]==df[(i-1),"cat"]) {
df[i,"num"]<-df[i-1,"num"]+1
}
}
df
cat val num
1 aaa 0.05638315 1
2 aaa 0.25767250 2
3 aaa 0.30776611 3
4 aaa 0.46854928 4
5 aaa 0.55232243 5
6 bbb 0.17026205 1
7 bbb 0.37032054 2
8 bbb 0.48377074 3
9 bbb 0.54655860 4
10 bbb 0.81240262 5
11 ccc 0.28035384 1
12 ccc 0.39848790 2
13 ccc 0.62499648 3
14 ccc 0.76255108 4
15 ccc 0.88216552 5
¿Cuál sería una buena manera de hacer esto?
Respuestas:
Uso
ave
,ddply
,dplyr
odata.table
:o:
o:
o (la memoria más eficiente, ya que se asigna por referencia dentro
DT
):fuente
ave
da un flotador en lugar de un int aquí. Alternativamente, podría cambiardf$val
aseq_len(nrow(df))
. Me encontré con esto por aquí: stackoverflow.com/questions/42796857/…data.table
solución parece ser más rápida que usarfrank
:library(microbenchmark); microbenchmark(a = DT[, .(val ,num = frank(val)), by = list(cat)] ,b =DT[, .(val , id = seq_len(.N)), by = list(cat)] , times = 1000L)
dplyr
solucion es buena. Pero si, como yo, seguiste recibiendo errores extraños al probar este enfoque, asegúrate de no tener conflictosplyr
y,dplyr
como se explica en esta publicación , se puede evitar llamando explícitamentedplyr::mutate(...)
data.table
método essetDT(df)[, id:=rleid(val), by=.(cat)]
library(plyr)
ylibrary(dplyr)
responder para hacer la columna val de clasificación en orden descendente?Por hacer esto r-faqpregunta más completa, una alternativa base R con
sequence
yrle
:que da el resultado deseado:
Si
df$cat
es una variable de factor,as.character
primero debe envolverla :fuente
cat
columna para ser ordenado?cat
Aquí hay una opción que usa un
for
bucle por grupos en lugar de por filas (como lo hizo OP)fuente
Aquí hay un pequeño truco de mejora que permite ordenar 'val' dentro de los grupos:
fuente
Me gustaría agregar una
data.table
variante usando larank()
función que proporciona la posibilidad adicional de cambiar el orden y, por lo tanto, la hace un poco más flexible que laseq_len()
solución y es bastante similar a las funciones row_number en RDBMS.fuente
Otra
dplyr
posibilidad podría ser:fuente
1:n()
usarseq_len(n())
es más seguro, en el caso de que en su secuencia de operaciones tenga una situación en la quen()
podría regresar0
, porque1:0
le da un vector de longitud dos mientras queseq_len(0)
da un vector de longitud cero, evitando así un error de desajuste de longitud conmutate()
.Usando la
rowid()
función endata.table
:fuente