将多个函数应用于data.table中的多个列

pal*_*czy 27 r data.table

我正在尝试将多个函数应用于a的多个列data.table.例:

DT <- data.table("a"=1:5,
                 "b"=2:6,
                 "c"=3:7)
Run Code Online (Sandbox Code Playgroud)

比方说,我想要得到的平均值和列的中位数ab.这有效:

stats <- DT[,.(mean_a=mean(a),
               median_a=median(a),
               mean_b=mean(b),
               median_b=median(b))]
Run Code Online (Sandbox Code Playgroud)

但这太重复了.有没有一种很好的方法来使用.SDcols和获得类似的结果lapply

edd*_*ddi 29

我通常这样做:

my.summary = function(x) list(mean = mean(x), median = median(x))

DT[, unlist(lapply(.SD, my.summary)), .SDcols = c('a', 'b')]
#a.mean a.median   b.mean b.median 
#     3        3        4        4 
Run Code Online (Sandbox Code Playgroud)

  • 你也可以简化为`my.summary = function(x)c(mean = mean(x),median = median(x)); DT [,sapply(.SD,my.summary),. SDcols = a:b]` (8认同)
  • 但是,如果我按类别DT [,as.list(unlist(lapply(.SD,my.summary))),= category,.SDcols = c('a',')添加一个组,这似乎非常慢b')]`这比单独完成每个摘要然后加入要花费更长的时间.有没有更快的方法呢?我在类别列@akrun中有大约150万个组 (3认同)
  • 我认为带有`by`的代码为:`as.list(unlist(lapply(...`? (3认同)
  • 我有一个类似的想法,但认为OP需要data.table输出而不是向量`DT [,as.list(unlist(lapply(.SD,my.summary))),.SDcols = c('a', 'b')]` (2认同)
  • 值得一提的是,如果添加`by`分组,输出将完全不同(很长)!那你该怎么办? (2认同)

Col*_*vel 11

这有点笨拙,但做的工作是data.table:

funcs = c('median', 'mean', 'sum')

m = DT[, lapply(.SD, function(u){
        sapply(funcs, function(f) do.call(f,list(u)))
     })][, t(.SD)]
colnames(m) = funcs

#  median mean sum
#a      3    3  15
#b      4    4  20
#c      5    5  25
Run Code Online (Sandbox Code Playgroud)


Ist*_*sta 5

其他答案显示了如何执行此操作,但是没有人愿意去解释基本原理。基本规则是,j表达式返回的列表元素构成结果的列data.table。任何j产生列表的表达式都可以使用,该列表的每个元素都对应于结果中所需的列。考虑到这一点,我们可以使用

DT[, c(mean = lapply(.SD, mean),
       median = lapply(.SD, median)),
  .SDcols = c('a', 'b')]
##    mean.a mean.b median.a median.b
## 1:      3      4        3        4
Run Code Online (Sandbox Code Playgroud)

要么

DT[, unlist(lapply(.SD,
                   function(x) list(mean = mean(x),
                                    median = median(x))),
            recursive = FALSE),
   .SDcols = c('a', 'b')]
##    a.mean a.median b.mean b.median
## 1:      3        3      4        4
Run Code Online (Sandbox Code Playgroud)

取决于所需的顺序。

重要的是,只要如上所述将结果排列到列表中,我们就可以使用想要产生期望结果的任何方法。例如,

library(matrixStats)
DT[, c(mean = as.list(colMeans(.SD)),
       median = setNames(as.list(colMedians(as.matrix(.SD))), names(.SD))),
   .SDcols = c('a', 'b')]
##    mean.a mean.b median.a median.b
## 1:      3      4        3        4
Run Code Online (Sandbox Code Playgroud)

也可以。

  • 我认为第一个示例不会重命名列,但除此之外,这是一个非常有用的答案。谢谢! (2认同)