tutorial - data.table: Suma por todas las combinaciones existentes en la tabla
shiny datatable (1)
Tengo un archivo de datos como este (en realidad es mucho más grande):
out <- code weights group
1: 2 0.387 1
2: 1 0.399 1
3: 2 1.610 1
4: 3 1.323 2
5: 2 0.373 2
6: 1 0.212 2
7: 3 0.316 3
8: 2 0.569 3
9: 1 0.120 3
10: 1 0.354 3
Tiene 3 grupos con diferentes códigos (columna 1). En el grupo # 1, el código 3 no aparece, mientras que en el otro aparece.
Entonces, quiero sumar los pesos para cada combinación de grupo y código. Lo logro con este comando:
sum.dt <- out[,.(sum(weights)), by=list(code,group)][order(-V1)]
Esto funciona bien pero no tiene la combinación del Grupo 1 con el Código 3 porque no está en la tabla de out
. Me gustaría tener todas las combinaciones posibles en sum.dt
, y si la combinación no ocurre en la tabla fuente, debe sumar hasta 0, lo que significa que la columna V1
debe ser 0 en esta fila.
¿Alguna idea de cómo podría lograr esto?
Usando CJ
(combinación cruzada) puede agregar las combinaciones faltantes:
library(data.table)
setkey(out, code, group)
out[CJ(code,group,unique=TRUE)
][, lapply(.SD, sum), by=.(code,group)
][is.na(weights), weights := 0]
da:
code group weights
1: 1 1 0.399
2: 1 2 0.212
3: 1 3 0.474
4: 2 1 1.997
5: 2 2 0.373
6: 2 3 0.569
7: 3 1 0.000
8: 3 2 1.323
9: 3 3 0.316
O con xtabs
como @alexis_laz mostró en los comentarios:
xtabs(weights ~ group + code, out)
lo que da:
code
group 1 2 3
1 0.399 1.997 0.000
2 0.212 0.373 1.323
3 0.474 0.569 0.316
Si desea obtener este resultado en un marco de datos de formato largo, puede ajustar el código xtabs
en la función de melt
del paquete reshape2 (o data.table ):
library(reshape2)
res <- melt(xtabs(weights ~ group + code, out))
lo que da:
> class(res)
[1] "data.frame"
> res
group code value
1 1 1 0.399
2 2 1 0.212
3 3 1 0.474
4 1 2 1.997
5 2 2 0.373
6 3 2 0.569
7 1 3 0.000
8 2 3 1.323
9 3 3 0.316
También podría hacer esto con una combinación de dplyr y tidyr :
library(dplyr)
library(tidyr)
out %>%
complete(code, group, fill = list(weights=0)) %>%
group_by(code, group) %>%
summarise(sum(weights))