在data.table中使用roll包函数遇问题,寻求技术指导
嘿,我完全懂你现在的处境——想用roll包的高级参数来替代zoo做data.table的分组滚动计算,但要么调用出错,要么搞不清两者返回值的差异对吧?别着急,我给你拆解清楚,一步步解决。
首先,咱们先搭一个可复现的测试场景,和你用zoo实现的逻辑对齐:
library(data.table) library(zoo) # 构造测试数据:2个分组,每组5个观测 DT <- data.table( group = rep(c("A", "B"), each = 5), obs = c(1,3,5,7,9,2,4,6,8,10) ) # 用zoo实现分组滚动均值(右对齐,不足窗口填充NA) DT[, roll_mean_zoo := rollmeanr(obs, k=3, fill=NA), by=group]
你遇到的核心问题:返回向量长度不匹配
你说两者都返回数值向量,但其实默认行为下,返回长度完全不同:
zoo::rollmeanr(带r后缀的右对齐版本)默认返回和输入等长的结果,不足窗口的位置自动填充NA,刚好匹配data.table分组后的行数。roll::roll_mean默认只返回「完整窗口」的计算结果,长度为n - width + 1,如果直接在data.table里调用,会因为返回长度和分组行数不匹配而报错。
比如你可能试过这样的错误调用:
library(roll) # 错误示例:返回长度不匹配,会报错 DT[, roll_mean_roll := roll_mean(obs, width=3), by=group] # 报错提示:Supplied 3 items to be assigned to group A's 5 rows
正确调用roll包的姿势:匹配zoo行为+利用高级参数
要解决这个问题,只需要给roll_mean加上两个关键参数,同时还能用上它的高级特性:
# 正确调用:对齐zoo的等长返回,同时启用roll包的额外参数 DT[, roll_mean_roll := roll_mean( x = obs, width = 3, fill = NA, # 填充NA,让结果和输入等长 align = "right", # 和rollmeanr的右对齐一致 min_obs = 1 # roll包特有:窗口内至少1个观测就计算(可选,默认等于width) ), by=group]
利用roll包的高级参数定制逻辑
这就是roll包的优势了——比如你可以通过min_obs控制窗口内需要多少个有效观测才计算结果,而zoo很难做到这点:
# 示例:窗口内至少2个观测才计算均值,否则返回NA DT[, roll_mean_roll_min2 := roll_mean( x = obs, width = 3, fill = NA, align = "right", min_obs = 2 # 仅当窗口内有≥2个观测时计算 ), by=group]
最终结果对比
运行完上面的代码,你可以看到三种计算方式的差异:
print(DT) # group obs roll_mean_zoo roll_mean_roll roll_mean_roll_min2 # 1: A 1 NA NA NA # 2: A 3 NA NA 2.0 # 3: A 5 3.0 3.0 3.0 # 4: A 7 5.0 5.0 5.0 # 5: A 9 7.0 7.0 7.0 # 6: B 2 NA NA NA # 7: B 4 NA NA 3.0 # 8: B 6 4.0 4.0 4.0 # 9: B 8 6.0 6.0 6.0 #10: B 10 8.0 8.0 8.0
总结一下关键要点
- 用
roll包在data.table分组计算时,必须显式设置fill=NA来保证返回长度和分组行数匹配。 align参数和zoo的对齐逻辑一致,选"right"对应rollmeanr,"left"对应rollmeanl。min_obs、weights等roll包特有的参数,可以帮你实现更灵活的滚动计算规则,这是zoo做不到的。
内容的提问来源于stack exchange,提问作者GNUser
相关产品推荐
相关产品推荐

