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

Использование динамических имен столбцов в `data.table`

Я хочу рассчитать среднее значение для каждого из нескольких столбцов в таблице data.table, сгруппированных по другому столбцу. Мой вопрос похож на два других вопроса о SO (один и два), но я не смог применить эти по моей проблеме.

Вот пример:

library(data.table)
dtb <- fread(input = "condition,var1,var2,var3
      one,100,1000,10000
      one,101,1001,10001
      one,102,1002,10002
      two,103,1003,10003
      two,104,1004,10004
      two,105,1005,10005
      three,106,1006,10006
      three,107,1007,10007
      three,108,1008,10008
      four,109,1009,10009
      four,110,1010,10010")

dtb
#    condition var1 var2  var3
# 1:       one  100 1000 10000
# 2:       one  101 1001 10001
# 3:       one  102 1002 10002
# 4:       two  103 1003 10003
# 5:       two  104 1004 10004
# 6:       two  105 1005 10005
# 7:     three  106 1006 10006
# 8:     three  107 1007 10007
# 9:     three  108 1008 10008
# 10:     four  109 1009 10009
# 11:     four  110 1010 10010

Расчет каждого отдельного среднего легко; например для "var1": dtb[ , mean(var1), by = condition]. Но я быстро становлюсь громоздким, если есть много переменных, и вам нужно написать все. Таким образом, dtb[, list(mean(var1), mean(var2), mean(var3)), by = condition] нежелательно. Мне нужно, чтобы имена столбцов были динамическими, и я хочу получить что-то вроде этого:

   condition  var1   var2    var3
1:       one 101.0 1001.0 10001.0
2:       two 104.0 1004.0 10004.0
3:     three 107.0 1007.0 10007.0
4:      four 109.5 1009.5 10009.5
4b9b3361

Ответ 1

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

dtb[, lapply(.SD, mean), by=condition, .SDcols=2:4]

#    condition  var1   var2    var3
# 1:       one 101.0 1001.0 10001.0
# 2:       two 104.0 1004.0 10004.0
# 3:     three 107.0 1007.0 10007.0
# 4:      four 109.5 1009.5 10009.5

Вы также можете получить все имена столбцов, которые вы хотите получить в начале, в переменной, а затем передать их в .SDcols следующим образом:

keys <- setdiff(names(dtb), "condition")
# keys = var1, var2, var3
dtb[, lapply(.SD, mean), by=condition, .SDcols=keys]

Редактировать: Как правильно заметил Мэтью Доул, поскольку вам требуется вычислять среднее значение для каждого другого столбца после группировки по condition, вы можете просто сделать:

dtb[, lapply(.SD, mean), by=condition]

Дэвид редактировать: (который был отклонен): узнайте больше о .SD из этого поста. Я считаю, что это актуально здесь. Спасибо, Дэвид.

Изменить 2: Предположим, у вас есть data.table с 1000 строками и 301 столбцом (один столбец для группировки и 300 числовых столбцов):

require(data.table)
set.seed(45)
dt <- data.table(grp = sample(letters[1:15], 1000, replace=T))
m  <- matrix(rnorm(300*1000), ncol=300)
dt <- cbind(dt, m)
setkey(dt, "grp")

и вы хотели найти среднее значение столбцов, скажем, 251: 300,

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

    dt.out <- dt[, lapply(.SD, mean), by=grp]
    dim(dt.out) # 15 * 301, not efficient.
    
  • вы можете сначала отфильтровать data.table только по этим столбцам, а затем вычислить среднее значение (что опять-таки не обязательно является лучшим решением, поскольку вам нужно создавать дополнительный поднабор данных.таблицы каждый раз, когда вы хотите выполнить операции с определенными столбцами.

    dt.sub <- dt[, c(1, 251:300)]
    setkey(dt.sub, "grp")
    dt.out <- dt.sub[, lapply(.SD, mean), by=grp]
    
  • вы можете указывать каждый из столбцов один за другим, как вы это обычно делаете (но это желательно для небольших таблиц data.tables)

    # if you just need one or few columns
    dt.out <- dt[, list(m.v251 = mean(V251)), by = grp]
    

Так какое лучшее решение? Ответ .SDcols.

Как указано в документации, для data.table x .SDcols указывает столбцы, включенные в .SD.

Это в основном неявно фильтрует столбцы, которые будут переданы в .SD вместо создания подмножества (как мы делали раньше), только это ОЧЕНЬ эффективно и БЫСТРО!

Как мы можем это сделать?

  • Указав номера столбцов:

    dt.out <- dt[, lapply(.SD, mean), by=grp, .SDcols = 251:300]
    dim(dt.out) # 15 * 51 (what we expect)
    
  • Или в качестве альтернативы, указав идентификатор столбца:

    ids <- paste0("V", 251:300) # get column ids
    dt.out <- dt[, lapply(.SD, mean), by=grp, .SDcols = ids]
    dim(dt.out) # 15 * 51 (what we expect)
    

Он принимает имена столбцов и номера в качестве аргументов. В обоих случаях .SD будет предоставляться только с теми столбцами, которые мы указали.

Надеюсь это поможет.