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

时间:2015-04-14 06:42:47

标签: r data.table

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

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

我想说我想得到列ab的平均值和中位数。 这有效:

stats <- DT[,.(mean_a=mean(a),
               median_a=median(a),
               mean_b=mean(b),
               median_b=median(b))]

但这太重复了。有没有一种很好的方法可以使用.SDcolslapply来获得类似的结果?

5 个答案:

答案 0 :(得分:24)

我通常会这样做:

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 

答案 1 :(得分:8)

这有点笨拙但用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

答案 2 :(得分:3)

其他答案显示了如何执行此操作,但是没有人愿意解释基本原理。基本规则是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

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

取决于所需的顺序。

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

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

也可以。

答案 3 :(得分:1)

使用dcast

DT$dday <- 1 # add a constant column
dt <- dcast(DT, dday~dday, fun=list(sum, mean), value.var = c('a', 'b'))
# dday a_sum_1 b_sum_1 a_mean_1 b_mean_1
# 1      15      20        3        4

事实上,我们可以使用dcast实现onehot和功能工程师。

答案 4 :(得分:0)

这可能有点过分设计,但是如果您来自dplyr的summarize_at(),则可能希望获得类似的结构化结果。

首先定义一个函数lapply_at(),该函数将一个.SD和一个函数名称的字符向量作为输入。然后,您可以轻松计算所需的统计信息并获得可读的结果。

library(data.table)
iris_dt <- as.data.table(iris)

lapply_at <- function(var, funs, ...) {
  results <- sapply(var, function(var) {
    lapply(funs, do.call, list(var, ...))
  })
  names(results) <- vapply(names(var), paste, funs, sep = "_", 
                           FUN.VALUE = character(length(funs)),
                           USE.NAMES = FALSE)
  results
}

iris_dt[, lapply_at(.SD, c("mean", "sd"), na.rm = TRUE), 
        .SDcols = patterns("^Sepal"),
        by = Species]

#>       Species Sepal.Length_mean Sepal.Length_sd Sepal.Width_mean
#> 1:     setosa             5.006       0.3524897            3.428
#> 2: versicolor             5.936       0.5161711            2.770
#> 3:  virginica             6.588       0.6358796            2.974
#>    Sepal.Width_sd
#> 1:      0.3790644
#> 2:      0.3137983
#> 3:      0.3224966

reprex package(v0.2.0)于2019-07-03创建。