Здравствуйте. Меня смущает поведение 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
он отличается от других инструментов, и мне было интересно, каково объяснение, или я делаю что-то не так (или, возможно, это ошибка). Я включил сравнение с 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
Самый полезный комментарий
Спасибо @ franknarf1 и @jangorecki за ответ и указатель на FAQ.
Прочитав ответ на часто задаваемые вопросы и выполнив еще немного тестов, кажется, вам следует быть очень осторожным с тем, как вы используете группирующие переменные, поскольку агрегирование по разным столбцам с идентичными данными может привести к разным результатам в зависимости от того, что использовалось для группировки. Я все еще нахожу это странным и немного неловким, но, возможно, это просто то, к чему мне нужно привыкнуть.
Примеры:
Результат вышеуказанного: TotalA = 1
Результат вышеуказанного: TotalB = 3
Нет результата, не выполняется с ошибкой:
Ошибка в gsum (SomeNumberA): объект SomeNumberA не найден