data.table v1.15.2按列子集行后调用shift()赋值报错问题
data.table版本间代码失效原因解析
在data.table v1.14.2里,你用data[to.keep == TRUE, (mycols) := shift(value, n = 1:3, type = 'lag'), by = Species]能顺利按筛选后的行分组生成滞后列,但到了v1.15.2就报「提供16个元素要分配给lag.1列的11个项」的错,核心原因是版本间分组计算的行匹配逻辑变了:
- v1.14.2中,用
i参数(也就是to.keep == TRUE)筛选行后,by分组是基于筛选后的子集来做的,shift只会计算每个组内筛选后的行,生成的结果长度和当前组的筛选后行数一致,赋值自然没问题。 - v1.15.2里,
by分组是基于整个原始数据集的分组,哪怕你用i筛了行,shift还是会对每个组的所有原始行计算滞后值,结果长度是该组的原始总行数,而你要赋值的只有筛选后的那部分行,两者长度不匹配就报错了。
举个实际场景:假设某个Species组原始有16行,其中11行符合to.keep == TRUE。旧版本里shift只处理这11行,出11个值;新版本处理全组16行,出16个值,要塞到11行的列里,自然就冲突了。
你说的在j里重复筛选的方法确实能解决,比如:
data[to.keep == TRUE, (mycols) := shift(value[to.keep == TRUE], n = 1:3, type = 'lag'), by = Species]
或者先把筛选后的数据集单独拎出来处理,再合并回去,逻辑更清晰:
filtered_dt <- data[to.keep == TRUE] filtered_dt[, (mycols) := shift(value, n = 1:3, type = 'lag'), by = Species] data[filtered_dt, on = .(Species, your_unique_id), (mycols) := mget(mycols)]
这个调整属于data.table内部逻辑的优化,没单独在shift的文档里提,而是包含在版本更新的整体行为变更里。
内容的提问来源于stack exchange,提问作者aattp
相关产品推荐
相关产品推荐

