在`data.table`中使用dynamic列名

我想计算一个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] 。 但是,如果有很多variables,而且你需要编写所有的variables,我很快就会变得很麻烦。 因此, dtb[, list(mean(var1), mean(var2), mean(var3)), by = condition]是不理想的。 我需要列名是dynamic的,我希望最终得到像这样的东西:

  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 (特别是如果你有太多的列,你只需要对列的一个子集执行特定的操作(除了分组variables列)。

 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 

你也可以在variables中获得所有想要首先使用的列名,然后将其传递给.SDcols如下所示:

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

编辑:正如马修Dowle正确地指出,因为你需要意味着在condition分组后按其他列计算,你可以做:

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

大卫的编辑:(被拒绝):从这篇文章阅读更多关于.SD 。 我觉得这是相关的。 谢谢@David。

编辑2:假设你有一个有1000行和301列的data.table (一列用于分组和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") 

你想find列的平均值,比如251:300,

  • 您可以计算所有列的平均值,然后对这些列进行子集计算(在整个数据上计算效率不高)。

     dt.out <- dt[, lapply(.SD, mean), by=grp] dim(dt.out) # 15 * 301, not efficient. 
  • 你可以data.table过滤到这些列,然后计算平均值(这也不一定是最好的解决scheme,因为每次你需要在某些列上进行操作时,你必须创build一个额外的subset.d data.table。

     dt.sub <- dt[, c(1, 251:300), with=FALSE] 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] 

那么最好的解决scheme是什么? 答案是.SDcols

如文档所述,对于data.table x.SDcols指定包含在.SD中的列。

这基本上隐式过滤将被传递给.SD的列而不是创build一个子集(正如我们以前所做的那样),只是它非常高效和快速!

我们怎么做到这一点?

  • 通过指定列号:

     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将仅提供给我们指定的这些列。

希望这可以帮助。