R data.table按ID分组处理:年份列满足条件时仅保留最大值其余置零
data.table分组按条件修改列值实现方案
不需要嵌套for循环,直接用data.table原生的分组+列迭代语法即可高效实现需求,代码如下:
完整代码
library(data.table) # 构造示例数据 data = data.table( ID = c("a1", "a2", "a2", "a1", "a2", "a1", "a1"), "2018" = c(3,5,11,3,9,22,6), "2019" = c(3,5,6,21,1,4,0), "2020" = c(0,4,13,9,16,7,9), "2021" = c(4,0,3,8,5,4,6) ) # 提取所有年份列(排除ID分组列) year_cols <- setdiff(names(data), "ID") # 按ID分组处理每一列 data[, (year_cols) := lapply(.SD, function(x) { col_max <- max(x) # 存在≥10的数值时仅保留最大值,其余置0,否则不修改 fifelse(col_max >= 10, fifelse(x == col_max, x, 0), x) }), by = ID, .SDcols = year_cols] # 验证结果和预期一致 solution <- data.table( ID = c("a1", "a2", "a2", "a1", "a2", "a1", "a1"), "2018" = c(0,0,11,0,0,22,0), "2019" = c(0,5,6,21,1,0,0), "2020" = c(0,0,0,9,16,7,9), "2021" = c(4,0,3,8,5,4,6) ) identical(data, solution) # 返回TRUE
逻辑说明
- 先用
setdiff提取所有需要处理的年份列,避免硬编码列名 - 按
ID字段分组,通过.SDcols指定仅对年份列做操作 - 对每个分组的每一列单独处理:
- 先计算当前列的最大值,判断是否≥10
- 若满足条件,用
fifelse把所有不等于最大值的元素置0,仅保留最大值 - 若不满足条件,直接返回原列数据
特殊场景适配
如果同一个ID、同一年份列下存在多个相等的最大值且≥10,上述代码会保留所有最大值。如果仅需要保留第一个出现的最大值,可把函数内的判断逻辑修改为:
fifelse(col_max >= 10, fifelse(x == col_max & cumsum(x == col_max) == 1, x, 0), x)
内容的提问来源于stack exchange,提问作者fjurt
相关产品推荐
相关产品推荐

