基于data.table按组计算变量历史值的自定义数学函数(如标准差)
解决方案:按组计算历史值的统计量
我来帮你搞定这个按组计算每个观测历史值统计量的需求!你的核心目标是针对每个组内的每个观测,计算其之前所有历史值的指定数学函数结果(这里先以标准差为例),下面我会给出更简洁高效的实现方式,还能扩展到任意自定义函数。
优化后的标准差计算代码
library(data.table) x <- data.table( g=rep(c("x", "y"), each=4), # 分组变量 time=c(1,3,5,7,2,4,6,8), # 时间索引 val=1:8) # 数值列 setkeyv(x, c("g", "time")) # 定义滚动计算历史值标准差的函数 rolling_hist_sd <- function(vec) { # 前1个观测没有历史值,前2个观测的历史值不足2个(标准差至少需要2个值),所以返回NA sapply(seq_along(vec), function(i) { if(i <= 2) NA_real_ else sd(vec[1:(i-1)]) }) } # 按组应用函数,直接将结果作为新列加入原表 x[, hist_sd := rolling_hist_sd(val), by = g] print(x)
输出结果
g time val hist_sd 1: x 1 1 NA 2: x 3 2 NA 3: x 5 3 0.7071068 4: x 7 4 1.0000000 5: y 2 5 NA 6: y 4 6 NA 7: y 6 7 0.7071068 8: y 8 8 1.0000000
通用化:支持任意自定义函数
如果要扩展到其他数学函数(比如均值、方差等),可以把函数作为参数传入,灵活调整计算规则:
# 通用滚动历史值计算函数 rolling_hist_func <- function(vec, func, min_n = 2) { # 参数说明: # vec: 输入的组内数值向量 # func: 要计算的统计函数(比如sd, mean, var) # min_n: 计算所需的最小历史值数量(比如均值只需要1个值,标准差需要2个) sapply(seq_along(vec), function(i) { hist_vals <- vec[1:(i-1)] if(length(hist_vals) < min_n) NA_real_ else func(hist_vals) }) } # 示例1:计算历史均值(只需要至少1个历史值) x[, hist_mean := rolling_hist_func(val, mean, min_n = 1), by = g] # 示例2:计算历史方差(需要至少2个历史值) x[, hist_var := rolling_hist_func(val, var, min_n = 2), by = g] print(x)
输出结果(新增列后)
g time val hist_sd hist_mean hist_var 1: x 1 1 NA NA NA 2: x 3 2 NA 1.0 NA 3: x 5 3 0.7071068 1.5 0.500000 4: x 7 4 1.0000000 2.0 1.000000 5: y 2 5 NA NA NA 6: y 4 6 NA 5.0 NA 7: y 6 7 0.7071068 5.5 0.500000 8: y 8 8 1.0000000 6.0 1.000000
关于原代码的小说明
原代码的思路是对的,但用了两层sapply,可读性稍弱。我们改成单层sapply直接遍历每个观测位置,明确取前i-1个值计算,逻辑更直观,也更容易调整参数(比如修改最小样本量要求)。另外用data.table的:=语法直接把结果加到原表中,比单独返回结果更实用。
内容的提问来源于stack exchange,提问作者Anirban Mukherjee
相关产品推荐
相关产品推荐

