如何基于分组大小在R语言中对DataFrame进行条件筛选?
解决分组条件筛选问题
首先明确你的需求:每个ID保留一条记录,优先按place == place1筛选;若筛选后该ID仍有多条,再按test == test1筛选,最终每个ID留一条记录。
你的原代码存在两个核心问题:
- 条件判断逻辑偏差:
if(n()>=2)是判断原分组的行数,而非place==place1筛选后的分组行数,导致筛选逻辑完全不符合预期 - 末尾
filter(n()==1)直接丢弃了筛选后仍有多行的分组,违背了你“保留一条”的核心需求
推荐解决方案(简洁版)
用优先级打分的方式标记每行的符合程度,取每个ID优先级最高的第一行:
library(dplyr) data1 %>% group_by(ID) %>% # 标记优先级:同时满足两个条件 > 只满足place条件 > 其他情况 mutate( priority = case_when( place == place1 & test == test1 ~ 3, place == place1 ~ 2, TRUE ~ 1 ) ) %>% # 按优先级降序排列,取第一行 arrange(desc(priority)) %>% slice_head(n = 1) %>% # 移除辅助的优先级列 select(-priority) %>% ungroup()
运行结果:
# A tibble: 4 × 6 ID town place place1 test test1 <dbl> <chr> <chr> <chr> <chr> <chr> 1 1 Town A A A G G 2 3 Town A B B B B 3 5 Town B A A A A 4 6 Town A B D B B
分步处理版(逻辑更直观)
如果需要严格遵循“先筛place,再筛test”的分步逻辑,用group_modify逐组处理:
library(dplyr) data1 %>% group_by(ID) %>% group_modify(function(.x, .y) { # 第一步:筛选place == place1的行 step1 <- .x %>% filter(place == place1) # 若第一步后仍有多行,执行第二步筛选 if (nrow(step1) > 1) { step2 <- step1 %>% filter(test == test1) # 第二步有结果则取第一行,否则取第一步的第一行 if (nrow(step2) > 0) { slice_head(step2, n = 1) } else { slice_head(step1, n = 1) } } else if (nrow(step1) == 0) { # 第一步无匹配结果时,取原组第一行(可根据需求调整规则) slice_head(.x, n = 1) } else { # 第一步后仅一行,直接保留 step1 } }) %>% ungroup()
这个版本和简洁版结果一致,更适合需要明确分步逻辑的场景。
内容的提问来源于stack exchange,提问作者Sulz
相关产品推荐
相关产品推荐

