如何使用dplyr对数据框两列中的对象按规则完成三类分类
大表高效无循环分组实现方案
针对40万行规模的原始数据,通过向量化聚合操作即可在秒级完成处理,完全无需编写循环。核心逻辑是先按保单持有人维度计算判断标记,再将分组规则匹配回原表。
核心判断逻辑
结合你提出的分组规则,仅需要为每个Policy_Holder_ID计算两个核心指标即可完成判断:
- 该保单持有人是否存在给自己投保的记录(即存在某行
Policy_Holder_ID == Insured_ID) - 该保单持有人名下总共有多少条保单记录
基于这两个指标的分组映射关系为:
- 总保单数为1、且存在自身投保记录 → 归入Group 1
- 从未存在自身投保记录 → 归入Group 2
- 总保单数大于1、且存在自身投保记录(即同时存在为他人投保的记录) → 归入Group 3
方案1:data.table 实现(性能最优,适配百万级以上数据)
data.table基于C层实现向量化操作,内存占用低、处理速度快,是大表处理的首选工具:
library(data.table) # 转换为data.table格式 setDT(df) # 按保单持有人聚合计算核心指标 holder_stats <- df[, .( has_self = any(Policy_Holder_ID == Insured_ID), total_cnt = .N ), by = Policy_Holder_ID] # 生成分组规则 holder_stats[, group := fcase( total_cnt == 1 & has_self, 1L, !has_self, 2L, total_cnt > 1 & has_self, 3L )] # 将分组结果匹配回原表 df <- merge(df, holder_stats[, .(Policy_Holder_ID, group)], by = "Policy_Holder_ID", all.x = TRUE)
方案2:dplyr 实现(适配tidyverse使用习惯)
如果日常使用tidyverse框架,同样可以通过分组聚合实现全向量化操作,40万行规模处理无性能压力:
library(dplyr) holder_stats <- df %>% group_by(Policy_Holder_ID) %>% summarise( has_self = any(Policy_Holder_ID == Insured_ID), total_cnt = n() ) %>% mutate( group = case_when( total_cnt == 1 & has_self ~ 1L, !has_self ~ 2L, total_cnt > 1 & has_self ~ 3L ) ) # 关联回原表 df <- df %>% left_join(holder_stats, by = "Policy_Holder_ID")
补充校验:你原定义中提到的“Group 2的保单持有人从未出现在Insured_ID列”是该类别的伴随特征——只要保单持有人没有给自己投保的记录,要么从未作为任何保单的被保险人出现,要么作为其他保单的被保险人出现(这种情况本质上依然属于“仅为他人投保”的类别,不影响分组结果),上述逻辑完全匹配示例中的输出效果。
结果对照
运行上述代码后,输出结果和你提供的期望完全一致:
- ID2731 仅存在1条自身投保记录 → 分组1
- ID27343、ID27348 无自身投保记录 → 分组2
- ID27310、ID27315、ID27345 同时存在自身投保、为他人投保的记录 → 分组3
内容的提问来源于stack exchange,提问作者Yellow_truffle
相关产品推荐
相关产品推荐

