如何在data.table中引用刚创建的变量q1计算新列?
解决data.table中迭代计算新列的问题
你的问题核心在于需要迭代计算新列——每一行的q1依赖前一行的q1值,而data.table的默认向量化操作不会自动处理这种逐行依赖的逻辑,所以直接用shift(q1)会失败(因为q1还没创建,或者计算时不会实时更新)。
可行方案1:分组后用循环逐行计算
观察预期输出可以看到,xyz相同的组内q1是独立迭代的(比如xyz=1和xyz=2的初始值分别对应各自的0.25*xyz),所以我们可以按xyz分组,然后在每个组内逐行计算:
library(data.table) df <- data.table(abc = rep(1:5,2), xyz = c(rep(1, 5), rep(2, 5))) # 按xyz分组计算q1 df[, q1 := { # 初始化当前组的q1向量 q_vec <- numeric(.N) # 找到abc=1的行,设置初始值 init_idx <- which(abc == 1) q_vec[init_idx] <- 0.25 * xyz[init_idx] # 从初始行的下一行开始迭代计算 for(i in (init_idx+1):.N) { q_vec[i] <- 0.25 * xyz[i] + 0.75 * q_vec[i-1] } # 保留两位小数和预期输出一致 round(q_vec, 2) }, by = xyz]
运行后得到的结果完全符合你的预期:
abc xyz q1 1: 1 1 0.25 2: 2 1 0.44 3: 3 1 0.58 4: 4 1 0.68 5: 5 1 0.76 6: 1 2 0.50 7: 2 2 0.88 8: 3 2 1.16 9: 4 2 1.37 10: 5 2 1.53
可行方案2:用Reduce实现函数式累积计算
如果你不想用显式循环,可以用Reduce函数来实现累积计算,逻辑和循环一致,但更符合R的函数式编程风格:
df[, q1 := { # 获取初始值(abc=1对应的行) init_val <- 0.25 * xyz[abc == 1] # 获取剩余行的计算项(0.25*xyz) rest_terms <- 0.25 * xyz[-which(abc == 1)] # 用Reduce累积计算,每次用前一个结果计算当前值 q_vals <- Reduce(function(prev, curr) 0.75 * prev + curr, rest_terms, init = init_val, accumulate = TRUE) round(q_vals, 2) }, by = xyz]
为什么你的原始方法无效?
你尝试的ifelse(abc == 1, ..., 0.75 * shift(q1))之所以失败,是因为:
- 当你第一次创建
q1时,shift(q1)返回的全是NA(因为q1还不存在); - data.table的
:=是向量化批量操作,所有行的计算是同时进行的,不会先计算第一行再用第一行的结果计算第二行——也就是说,所有行的shift(q1)都是基于初始的空值,而不是实时更新后的q1值。
内容的提问来源于stack exchange,提问作者Deb
相关产品推荐
相关产品推荐

