在R data.table中按x分组、基于y计算z的滚动平均值
问题描述
现有如下R data.table数据:
library(data.table) DT <- data.table( N = 1:16, x = c(11,11,11,11,11,11,11,11,21,21,21,21,21,21,21,21), y = c(1,2,3,4,4,4,4,4,1,2,3,4,4,4,4,4), z = c(53,71,27,64,43,62,61,85,44,56,23,37,31,48,80,38) )
需要新增Roll Mean列,计算规则为:在每个x分组内,
- 当
y=1时,Roll Mean为NA; - 当
y=2时,取前1个z值的均值; - 当
y=3时,取前2个z值的均值; - 当
y=4时,第一个y=4的行取前3个z值的均值,后续y=4的行取前4个z值的均值。
预期输出如下:
N x y z Roll Mean 1 11 1 53 NA 2 11 2 71 53 3 11 3 27 62 4 11 4 64 50.33333333 5 11 4 43 53.75 6 11 4 62 51.25 7 11 4 61 49 8 11 4 85 57.5 9 21 1 44 NA 10 21 2 56 44 11 21 3 23 50 12 21 4 37 41 13 21 4 31 40 14 21 4 48 36.75 15 21 4 80 34.75 16 21 4 38 49
当前使用固定窗口的滚动均值代码,结果不符合预期:
DT[, RollingAvg := frollapply(z,4, mean), .(x)]
解决方案
原代码的问题在于使用了固定大小为4的滚动窗口,无法满足需求中动态变化的窗口规则。可以通过在x分组内标记y=4的行序号,再结合嵌套的fifelse实现动态窗口计算:
library(data.table) DT[, `Roll Mean` := { # 给每个x分组内的y=4行标记序号,第一个y=4为1,依次递增 y4_seq <- cumsum(y == 4) # 根据规则分情况计算 fifelse(y == 1, NA_real_, fifelse(y == 2, shift(z, 1), fifelse(y == 3, (shift(z, 1) + shift(z, 2)) / 2, fifelse(y4_seq == 1, (shift(z, 1) + shift(z, 2) + shift(z, 3)) / 3, (shift(z, 1) + shift(z, 2) + shift(z, 3) + shift(z, 4)) / 4)))) }, by = x] # 查看结果 print(DT)
代码解释
- 分组内标记y=4的行:使用
cumsum(y == 4)在每个x分组内为y=4的行生成递增序号,区分第一个和后续的y=4行。 - 分条件计算:
y=1:直接返回NA_real_(确保数值类型统一)y=2:用shift(z,1)取前1行的z值(单个值的均值即自身)y=3:取前2行的z值求和后除以2- 第一个
y=4行:取前3行的z值求和后除以3 - 后续
y=4行:取前4行的z值求和后除以4
运行上述代码后,即可得到符合预期的Roll Mean列。
内容的提问来源于stack exchange,提问作者zainul abid
相关产品推荐
相关产品推荐

