Data.table: Неправильные итоги при агрегировании и группировке по одному столбцу?

Созданный на 10 окт. 2018  ·  4Комментарии  ·  Источник: Rdatatable/data.table

Здравствуйте. Меня смущает поведение data.table при агрегировании и группировке в одном столбце. Кажется, что он выполняет агрегирование (например, сумму) сгруппированных данных, а не несгруппированных данных. Я не обязательно говорю, что это неправильно - но это отличается от других инструментов, и мне было интересно, в чем объяснение, или я делаю что-то не так (или, возможно, это ошибка). Я включил сравнение с dplyr, который работает больше, чем я ожидал (и больше похож на SQL). NB: Я пробовал искать проблемы, stackoverflow и т. Д. По запросу, но характер этого сценария (группировка и агрегирование одного и того же столбца) немного уникален, и я не нашел никаких совпадений.

# Minimal reproducible example

Сравните столбец "Итого" в двух приведенных ниже примерах. Например, есть три строки со значением три, поэтому я ожидаю, что Total будет 9, а не 3.

Таблица данных

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]

Результат (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()

Результат (r):

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

# Output of sessionInfo()
R версия 3.5.1 (02.07.2018)
Платформа: x86_64-w64-mingw32 / x64 (64-бит)
Работает под: Windows> = 8 x64 (сборка 9200)

Матричные продукты: по умолчанию

локаль:
[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

прилагаемые базовые пакеты:
[1] статистика графики grDevices использует базы данных наборов данных

другие прикрепленные пакеты:
[1] dplyr_0.7.6 data.table_1.11.8 openxlsx_4.1.0 bindrcpp_0.2.2 pivottabler_0.4.0.9000

загружается через пространство имен (и не прикрепляется):
[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 Fani_0.3.0 tools_3.5.1
[10] utf8_1.1.4 cli_1.0.1 htmltools_0.3.6 yaml_2.2.0 assertthat_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 glue_1.3.0 compiler_3.5.1 pillar_1.3.0 jsonlite_1.5 pkgconfig_2.0.2

bug question

Самый полезный комментарий

Спасибо @ franknarf1 и @jangorecki за ответ и указатель на FAQ.
Прочитав ответ на часто задаваемые вопросы и выполнив еще немного тестов, кажется, вам следует быть очень осторожным с тем, как вы используете группирующие переменные, поскольку агрегирование по разным столбцам с идентичными данными может привести к разным результатам в зависимости от того, что использовалось для группировки. Я все еще нахожу это странным и немного неловким, но, возможно, это просто то, к чему мне нужно привыкнуть.

Примеры:

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]

Результат вышеуказанного: 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]

Результат вышеуказанного: 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]

Нет результата, не выполняется с ошибкой:
Ошибка в gsum (SomeNumberA): объект SomeNumberA не найден

Все 4 Комментарий

он отличается от других инструментов, и мне было интересно, каково объяснение, или я делаю что-то не так (или, возможно, это ошибка). Я включил сравнение с dplyr, которое работает больше, чем я ожидал (и больше похоже на SQL)

Внутри j из DT[, j, by] столбцы в by имеют длину 1. Вы можете сделать это вычисление, как .N*SomeNumber , однако:

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

Для обоснования см. Вопрос «Почему внутри каждой группы переменные группы имеют длину-1?» внутри FAQ по адресу vignette("datatable-faq") или https://github.com/Rdatatable/data.table/wiki/Getting-started

Спасибо @ franknarf1 и @jangorecki за ответ и указатель на FAQ.
Прочитав ответ на часто задаваемые вопросы и выполнив еще немного тестов, кажется, вам следует быть очень осторожным с тем, как вы используете группирующие переменные, поскольку агрегирование по разным столбцам с идентичными данными может привести к разным результатам в зависимости от того, что использовалось для группировки. Я все еще нахожу это странным и немного неловким, но, возможно, это просто то, к чему мне нужно привыкнуть.

Примеры:

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]

Результат вышеуказанного: 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]

Результат вышеуказанного: 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]

Нет результата, не выполняется с ошибкой:
Ошибка в gsum (SomeNumberA): объект SomeNumberA не найден

Последний баг ...

Не уверен, что это нюанс метода группировки / агрегации data.table, но при группировке и агрегировании по одной переменной data.table не «факторизует» вызов группировки.

т.е. он считает каждое число как свою собственную группу после агрегирования, поэтому в вашем случае у вас остается только 3 SomeNumber переменных для суммирования вместо исходных 9.

Быстрое и простое решение - обеспечить факторизацию в рамках первоначального группового вызова.

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
Была ли эта страница полезной?
0 / 5 - 0 рейтинги