R语言分组去重:按ID&Group保留非零行的高效实现求助
问题:按ID+Group分组后保留非零行(仅处理有重复的分组)
示例数据集
ID Group Value 1 z1 0 1 z1 0.81 2 z2 2.89 2 z2 1.53 3 z1 -0.23 3 z1 0 4 z3 10.75 4 z3 8.13 5 x2 0.45 5 x2 1.43
对应的R数据构造代码:
library(tibble) df <- tibble( ID = c(1, 1, 2, 2, 3, 3, 4, 4, 5, 5), Group = c("z1", "z1", "z2", "z2", "z1", "z1", "z3", "z3", "x2", "x2"), Value = c(0, 0.81, 2.89, 1.53, -0.23, 0, 10.75, 8.13, 0.45, 1.43) )
需求说明
分组后若存在重复行(即每个ID+Group组内行数>1),仅保留Value列非零的行;无重复的分组则保留全部行。预期输出移除ID1和ID3中Value为0的行,其余分组保留所有行。
原代码问题分析
你提供的两段代码存在以下问题:
- 分组列名错误:原数据列名为
Group,代码中误写为GroupID - 效率低下:使用
duplicated(.)会逐行比较整行内容,在22000行数据集上会大幅拖慢速度 - 逻辑不准确:
any(duplicated(.))仅判断分组内是否有整行重复,无法覆盖分组内多行非零的情况(如ID2、4、5的分组)
优化代码方案
方案1:dplyr高效写法
library(dplyr) df %>% group_by(ID, Group) %>% # 分组行数为1则保留所有行,否则仅保留Value非零的行 filter(n() == 1 | Value != 0) %>% ungroup()
方案2:data.table极速写法(适合大数据集)
如果数据集更大,推荐使用data.table,内存占用更低、运行速度更快:
library(data.table) # 转换为data.table格式 setDT(df) # 按ID+Group分组,逻辑同dplyr df[, if (.N == 1) .SD else .SD[Value != 0], by = .(ID, Group)]
代码说明
n()(dplyr)或.N(data.table):直接统计分组内的行数,比duplicated(.)高效数倍,无需逐行比较- 逻辑简化:通过
n() == 1判断是否为无重复分组,避免复杂的条件嵌套 - 兼容性:覆盖所有分组场景,包括分组内全非零、含零值等情况
内容的提问来源于stack exchange,提问作者Ahir Bhairav Orai
相关产品推荐
相关产品推荐

