superponer - Numeración de filas dentro de grupos en un marco de datos
superponer graficas en r (5)
Trabajando con un marco de datos similar a esto:
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?
Aquí hay otra forma de hacerlo usando dplyr
:
library(dplyr)
df %>% group_by(cat) %>% mutate(num = 1:n())
Aquí hay una opción que usa un ciclo for
por grupos más bien por filas (como lo hizo OP)
for (i in unique(df$cat)) df$num[df$cat == i] <- seq_len(sum(df$cat == i))
Me gustaría agregar una variante de data.table
utilizando la función rank()
, que ofrece la posibilidad adicional de cambiar el orden y lo hace un poco más flexible que la solución seq_len()
y es bastante similar a las funciones row_number en RDBMS.
# Variant with ascending ordering
library(data.table)
dt <- data.table(df)
dt[, .( val
, num = rank(val))
, by = list(cat)][order(cat, num),]
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
# Variant with descending ordering
dt[, .( val
, num = rank(val))
, by = list(cat)][order(cat, num),]
Para hacer que esta pregunta de r-faq más completa, una alternativa de base R con sequence
y rle
:
df$num <- sequence(rle(df$cat)$lengths)
que da el resultado esperado:
> df cat val num 4 aaa 0.05638315 1 2 aaa 0.25767250 2 1 aaa 0.30776611 3 5 aaa 0.46854928 4 3 aaa 0.55232243 5 10 bbb 0.17026205 1 8 bbb 0.37032054 2 6 bbb 0.48377074 3 9 bbb 0.54655860 4 7 bbb 0.81240262 5 13 ccc 0.28035384 1 14 ccc 0.39848790 2 11 ccc 0.62499648 3 15 ccc 0.76255108 4 12 ccc 0.88216552 5
Si df$cat
es una variable de factor, primero debe envolverlo como as.character
.
df$num <- sequence(rle(as.character(df$cat))$lengths)
Utilice ave
, ddply
, dplyr
o data.table
:
df$num <- ave(df$val, df$cat, FUN = seq_along)
o:
library(plyr)
ddply(df, .(cat), mutate, id = seq_along(val))
o:
library(dplyr)
df %>% group_by(cat) %>% mutate(id = row_number())
o (la memoria más eficiente, como se asigna por referencia dentro de DT
):
library(data.table)
DT <- data.table(df)
DT[, id := seq_len(.N), by = cat]
DT[, id := rowid(cat)]