【问题标题】:R data.table - Apply function A to some columns and function B to some othersR data.table - 将函数 A 应用于某些列,将函数 B 应用于其他一些列
【发布时间】:2018-11-10 14:03:39
【问题描述】:

我想聚合数据表的行,但是聚合函数取决于列的名称。

例如,如果列名是:

  • variable1 或 variable2,然后应用 mean() 函数。
  • variable3,然后应用 max() 函数。
  • variable4,然后应用 sd() 函数。

我的数据表总是有一个datetime 列:我想按时间聚合行。 但是,“数据”列的数量可能会有所不同。

我知道如何对所有列使用相同的聚合函数(例如 mean()):

dt <- dt[, lapply(.SD, mean),
           by = .(datetime = floor_date(datetime, timeStep))]

或仅用于列的子集:

cols <- c("variable1", "variable2")    
dt <- dt[ ,(cols) := lapply(.SD, mean), 
            by = .(datetime = floor_date(datetime, timeStep)),
            .SDcols = cols]

我想做的是这样的:

colsToMean <- c("variable1", "variable2") 
colsToMax <- c("variable3")   
colsToSd <- c("variable4")   
dt <- dt[ ,{(colsToMean) := lapply(.SD???, mean),
             (colsToMax) := lapply(.SD???, max),
             (colsToSd) :=  lapply(.SD???, sd)}, 
            by = .(datetime = floor_date(datetime, timeStep)),
            .SDcols = (colsToMean, colsToMax, colsToSd)]

我查看了data.table in R - apply multiple functions to multiple columns,它给了我使用自定义函数的想法:

myAggregate <- function(x, columnName) {
   FUN = getAggregateFunction(columnName) # Return mean() or max() or sd()
   return FUN(x)
}
dt <- dt[, lapply(.SD, myAggregate, ???columName???),
           by = .(datetime = floor_date(datetime, timeStep))]

但我不知道如何将当前列名传递给myAggregate()...

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    这是使用Map 或mapply 的一种方法:

    让我们先制作一些玩具数据:

    dt <- data.table(
        variable1 = rnorm(100),
        variable2 = rnorm(100),
        variable3 = rnorm(100),
        variable4 = rnorm(100),
        grp = sample(letters[1:5], 100, replace = T)
    )
    
    colsToMean <- c("variable1", "variable2") 
    colsToMax <- c("variable3")   
    colsToSd <- c("variable4")
    

    那么,

    scols <- list(colsToMean, colsToMax, colsToSd)
    funs <- rep(c(mean, max, sd), lengths(scols))
    
    # summary
    dt[, Map(function(f, x) f(x), funs, .SD), by = grp, .SDcols = unlist(scols)]
    
    # or replace the original values with summary statistics as in OP
    dt[, unlist(scols) := Map(function(f, x) f(x), funs, .SD), by = grp, .SDcols = unlist(scols)]
    

    启用 GForce 的另一个选项:

    scols <- list(colsToMean, colsToMax, colsToSd)
    funs <- rep(c('mean', 'max', 'sd'), lengths(scols))
    
    jexp <- paste0('list(', paste0(funs, '(', unlist(scols), ')', collapse = ', '), ')')
    dt[, eval(parse(text = jexp)), by = grp, verbose = TRUE]
    
    # Detected that j uses these columns: variable1,variable2,variable3,variable4 
    # Finding groups using forderv ... 0.000sec 
    # Finding group sizes from the positions (can be avoided to save RAM) ... 0.000sec 
    # Getting back original order ... 0.000sec 
    # lapply optimization is on, j unchanged as 'list(mean(variable1), mean(variable2), max(variable3), sd(variable4))'
    # GForce optimized j to 'list(gmean(variable1), gmean(variable2), gmax(variable3), gsd(variable4))'
    # Making each group and running j (GForce TRUE) ... 0.000sec 
    

    【讨论】:

    • OP 提到了聚合,所以可能不希望 := / 覆盖。另外,我想应该有某种方法可以让 GForce 优化在这里工作,但找不到简单的方法来做到这一点。 (如果不熟悉,请参阅 ?GForce。)
    • 解决方案dt[, Map(function(f, x) f(x), funs, .SD), by = grp, .SDcols = unlist(scols)] 符合我的需求,而且效果很好。谢谢!
    • @Frank,不知道为什么,但您的评论没有出现在我的消息收件箱中。您可能会忘记它,但您之前教过我有关 data.table 优化以及如何使用 verbose = TRUE 检查执行的知识!我发现 data.table 只能识别 lapply(.SD, fun) 而不是 Map 或 mapply 所以我必须手动构造一个可优化的 j 表达式。有关详细信息,请参阅编辑后的答案。
    • 是的,我是这么想的,但我不确定我的记忆力,所以我想我会再给一次裁判。不错的解决方案! (刚刚删除了我认为是错字的地方。如果我弄错了,请恢复)
    • @Frank,感谢您的编辑。我应该再检查一次。
    猜你喜欢
    • 1970-01-01
    • 2017-05-12
    • 1970-01-01
    • 2021-02-03
    • 2016-09-24
    • 1970-01-01
    • 1970-01-01
    • 2015-07-08
    • 1970-01-01
    相关资源
    最近更新 更多