Подтвердить что ты не робот

Примените функцию к подмножеству столбцов (.SDcols), применяя другую функцию к другому столбцу (внутри групп)

Это очень похоже на вопрос, в котором подробно описывается общая функция для нескольких столбцов data.table uning .SDcols здесь.

Разница в том, что я хотел бы одновременно применять другую функцию в другом столбце, который не является частью подмножества .SD. Опубликуйте простой пример ниже, чтобы показать мою попытку решить проблему:

dt = data.table(grp = sample(letters[1:3],100, replace = TRUE),
                v1 = rnorm(100), 
                v2 = rnorm(100), 
                v3 = rnorm(100))
sd.cols = c("v2", "v3")
dt.out = dt[, list(v1 = sum(v1),  lapply(.SD,mean)), by = grp, .SDcols = sd.cols]

Устанавливает следующую ошибку:

Error in `[.data.table`(dt, , list(v1 = sum(v1), lapply(.SD, mean)), by = grp,  
: object 'v1' not found

Теперь это имеет смысл, потому что столбец v1 не включен в подмножество столбцов, которое должно быть оценено первым. Поэтому я исследовал его, включив его в мой поднабор столбцов:

sd.cols = c("v1","v2", "v3")
dt.out = dt[, list(sum(v1), lapply(.SD,mean)), by = grp, .SDcols = sd.cols]

Теперь это не вызывает ошибки, но содержит ответ, содержащий 9 строк (для 3 групп), сумма трижды повторяется в столбце v1 и средства для всех 3 столбцов (как ожидалось, но не требуется), помещенных в V2, как показано ниже:

> dt.out 
   grp        V1                  V2
1:   c -1.070608 -0.0486639841313638
2:   c -1.070608  -0.178154270921521
3:   c -1.070608  -0.137625003604012
4:   b -2.782252 -0.0794929150464099
5:   b -2.782252  -0.149529237116445
6:   b -2.782252   0.199925178109264
7:   a  6.091355   0.141659419355985
8:   a  6.091355 -0.0272192037753071
9:   a  6.091355 0.00815760216214876

Обходное решение с использованием 2 шагов

Ясно, что можно решить проблему несколькими шагами, вычислив группу mean по подмножеству столбцов и присоединив ее к sum по группе для одного столбца следующим образом:

dt.out1 = dt[, sum(v1), by = grp]
dt.out2 = dt[, lapply(.SD,mean), by = grp, .SDcols = sd.cols]
dt.out = merge(dt.out1, dt.out2, by = "grp")

> dt.out
   grp        V1         v2           v3
1:   a  6.091355 -0.0272192  0.008157602
2:   b -2.782252 -0.1495292  0.199925178
3:   c -1.070608 -0.1781543 -0.137625004

Я уверен, что это довольно простая вещь, которую я пропускаю, заблаговременно за любые рекомендации.

4b9b3361

Ответ 1

Обновление: Проблема # 495 теперь решена с помощью этой недавней фиксации, теперь мы можем сделать это просто отлично:

require(data.table) # v1.9.7+
set.seed(1L)
dt = data.table(grp = sample(letters[1:3],100, replace = TRUE),
                v1 = rnorm(100), 
                v2 = rnorm(100), 
                v3 = rnorm(100))
sd.cols = c("v2", "v3")
dt.out = dt[, list(v1 = sum(v1),  lapply(.SD,mean)), by = grp, .SDcols = sd.cols]

Однако обратите внимание, что в этом случае v2 будет возвращен как список. Это потому, что вы эффективно выполняете list(val, list()). Возможно, вы намерены сделать следующее:

dt[, c(list(v1=sum(v1)), lapply(.SD, mean)), by=grp, .SDcols = sd.cols]
#    grp        v1          v2         v3
# 1:   a -6.440273  0.16993940  0.2173324
# 2:   b  4.304350 -0.02553813  0.3381612
# 3:   c  0.377974 -0.03828672 -0.2489067

См. историю более старых ответов.

Ответ 2

Попробуйте следующее:

dt[,list(sum(v1), mean(v2), mean(v3)), by=grp]

В data.table, используя list() во втором аргументе, вы можете описать набор столбцов, которые приводят к окончательному data.table.

Для того, что стоит, .SD может быть довольно медленным [^ 1], поэтому вы можете избежать его, если вам действительно не нужны все данные, представленные в подмножестве data.table, как вы могли бы для более сложной функции.

Другой вариант, если у вас есть много столбцов для .SDcols, будет выполнять слияние в одной строке с помощью синтаксиса data.table.

Например:

dt[, sum(v1), by=grp][dt[,lapply(.SD,mean), by=grp, .SDcols=sd.cols]]

Чтобы использовать merge из data.table, вам нужно сначала использовать setkey() на вашем data.table, чтобы он знал, как совместить вещи.

Итак, сначала вам нужно:

setkey(dt, grp)

Затем вы можете использовать приведенную выше строку для получения эквивалентного результата.

[^ 1]: Я считаю, что это особенно верно, так как ваше число групп приближается к числу полных строк. Например, это может произойти, когда ваш ключ является индивидуальным идентификатором, и у многих людей есть только одно или два наблюдения.