Data.table: ¿Totales incorrectos al agregar y agrupar por la misma columna?

Creado en 10 oct. 2018  ·  4Comentarios  ·  Fuente: Rdatatable/data.table

Hola. Estoy confundido por el comportamiento de data.table al agregar y agrupar en la misma columna. Parece realizar el agregado (por ejemplo, la suma) de los datos agrupados, en lugar de los datos no agrupados. No estoy diciendo necesariamente que esto esté mal, pero es diferente a otras herramientas y me preguntaba cuál es la explicación o si estoy haciendo algo mal (o si posiblemente esto sea un error). He incluido una comparación con dplyr, que funciona más como yo esperaría (y más como SQL). NB: Intenté buscar los problemas, stackoverflow, etc., según lo solicitado, pero la naturaleza de este escenario (agrupar y agregar la misma columna) es un poco única y no encontré ninguna coincidencia.

# Minimal reproducible example

Compare la columna Total en los dos ejemplos siguientes. Por ejemplo, hay tres filas con el valor tres, por lo que esperaría que el Total sea 9, no 3.

tabla de datos

library(data.table)
df <- data.frame(SomeNumber=c(1,2,3,1,2,3,1,2,3))
dt <- data.table(df)
r <- dt[, .(.N, Total=sum(SomeNumber)), by=SomeNumber]

Resultado (r):

   SomeNumber N Total
1:          1 3     1
2:          2 3     2
3:          3 3     3

dplyr

library(dplyr)
df <- data.frame(SomeNumber=c(1,2,3,1,2,3,1,2,3))
r <- df %>% group_by(SomeNumber) %>% 
  summarise(N=n(), Total=sum(SomeNumber)) %>%
  ungroup()

Resultado (r):

   SomeNumber N Total
1:          1 3     3
2:          2 3     6
3:          3 3     9

# Output of sessionInfo()
R versión 3.5.1 (2018-07-02)
Plataforma: x86_64-w64-mingw32 / x64 (64 bits)
Ejecutando bajo: Windows> = 8 x64 (compilación 9200)

Productos Matrix: predeterminado

lugar:
[1] LC_COLLATE = English_United Kingdom.1252 LC_CTYPE = English_United Kingdom.1252 LC_MONETARY = English_United Kingdom.1252
[4] LC_NUMERIC = C LC_TIME = English_United Kingdom.1252

paquetes base adjuntos:
[1] estadísticas gráficas grDevices utils base de métodos de conjuntos de datos

otros paquetes adjuntos:
[1] dplyr_0.7.6 data.table_1.11.8 openxlsx_4.1.0 bindrcpp_0.2.2 pivottabler_0.4.0.9000

cargado a través de un espacio de nombres (y no adjunto):
[1] Rcpp_0.12.19 rstudioapi_0.8 bindr_0.1.1 magrittr_1.5 tidyselect_0.2.4 R6_2.3.0 rlang_0.2.2 fansi_0.3.0 tools_3.5.1
[10] utf8_1.1.4 cli_1.0.1 htmltools_0.3.6 yaml_2.2.0 aseveraque_0.2.0 digest_0.6.17 tibble_1.4.2 crayon_1.3.4 zip_1.0.0
[19] purrr_0.2.5 htmlwidgets_1.3 pegamento_1.3.0 compilador_3.5.1 pillar_1.3.0 jsonlite_1.5 pkgconfig_2.0.2

bug question

Comentario más útil

Gracias @ franknarf1 y @jangorecki por la respuesta y el puntero a las preguntas frecuentes.
Después de leer la respuesta a las preguntas frecuentes y hacer un poco más de pruebas, parece que debe tener mucho cuidado con la forma en que usa las variables de agrupación, ya que agregar en diferentes columnas con datos idénticos puede dar como resultado resultados diferentes, dependiendo de lo que se usó para la agrupación. Todavía lo encuentro extraño y un poco incómodo, pero tal vez sea algo a lo que necesito acostumbrarme.

Ejemplos:

library(data.table)
df <- data.frame(SomeNumberA=c(1,1,1),SomeNumberB=c(1,1,1))
dt <- data.table(df)
r <- dt[, .(.N, TotalA=sum(SomeNumberA)), by=SomeNumberA]

Resultado de lo anterior: TotalA = 1

library(data.table)
df <- data.frame(SomeNumberA=c(1,1,1),SomeNumberB=c(1,1,1))
dt <- data.table(df)
r <- dt[, .(.N, TotalB=sum(SomeNumberB)), by=SomeNumberA]

Resultado de lo anterior: TotalB = 3

library(data.table)
df <- data.frame(SomeNumberA=c(1,1,1),SomeNumberB=c(1,1,1))
dt <- data.table(df)
r <- dt[, .(.N, TotalA=sum(SomeNumberA), TotalB=sum(SomeNumberB)), by=SomeNumberA]

Sin resultado, no se ejecuta con error:
Error en gsum (SomeNumberA): objeto 'SomeNumberA' no encontrado

Todos 4 comentarios

es diferente a otras herramientas y me preguntaba cuál es la explicación o si estoy haciendo algo mal (o si posiblemente esto sea un error). He incluido una comparación con dplyr, que funciona más como yo esperaría (y más como SQL)

Dentro de j de DT[, j, by] , las columnas en by tienen una longitud de 1. Puede hacer ese cálculo como .N*SomeNumber , aunque:

dt[, .(.N, Total=.N*SomeNumber), by=SomeNumber]
# or, for efficiency with GForce...
dt[, .(.N), by=SomeNumber][, Total := N*SomeNumber][]

Para una justificación, consulte la pregunta "Dentro de cada grupo, ¿por qué las variables de grupo tienen una longitud de 1?" dentro de las preguntas frecuentes en vignette("datatable-faq") o https://github.com/Rdatatable/data.table/wiki/Getting-started

Gracias @ franknarf1 y @jangorecki por la respuesta y el puntero a las preguntas frecuentes.
Después de leer la respuesta a las preguntas frecuentes y hacer un poco más de pruebas, parece que debe tener mucho cuidado con la forma en que usa las variables de agrupación, ya que agregar en diferentes columnas con datos idénticos puede dar como resultado resultados diferentes, dependiendo de lo que se usó para la agrupación. Todavía lo encuentro extraño y un poco incómodo, pero tal vez sea algo a lo que necesito acostumbrarme.

Ejemplos:

library(data.table)
df <- data.frame(SomeNumberA=c(1,1,1),SomeNumberB=c(1,1,1))
dt <- data.table(df)
r <- dt[, .(.N, TotalA=sum(SomeNumberA)), by=SomeNumberA]

Resultado de lo anterior: TotalA = 1

library(data.table)
df <- data.frame(SomeNumberA=c(1,1,1),SomeNumberB=c(1,1,1))
dt <- data.table(df)
r <- dt[, .(.N, TotalB=sum(SomeNumberB)), by=SomeNumberA]

Resultado de lo anterior: TotalB = 3

library(data.table)
df <- data.frame(SomeNumberA=c(1,1,1),SomeNumberB=c(1,1,1))
dt <- data.table(df)
r <- dt[, .(.N, TotalA=sum(SomeNumberA), TotalB=sum(SomeNumberB)), by=SomeNumberA]

Sin resultado, no se ejecuta con error:
Error en gsum (SomeNumberA): objeto 'SomeNumberA' no encontrado

El último es un error ...

No estoy seguro de si esto es un matiz del método de agrupación / agregación de data.table, pero cuando se agrupa y agrega por una sola variable, data.table no 'factoriza' la llamada de agrupación.

es decir, cuenta cada número como su propio grupo después de la agregación, por lo que, en su caso, solo le quedan 3 SomeNumber variables para sumar, en lugar de las 9 originales.

Una solución rápida y sencilla es garantizar que la factorización se lleve a cabo dentro de la llamada de agrupación inicial.

library(data.table)

df <- data.frame(SomeNumber=c(1, 2, 3, 1, 2, 3, 1, 2, 3))

dt <- data.table(df)

r <- dt[, .(.N, Total = sum(SomeNumber)), by = as.factor(SomeNumber)]

   as.factor N Total
1:         1 3     3
2:         2 3     6
3:         3 3     9
¿Fue útil esta página
0 / 5 - 0 calificaciones