R语言使用dplyr按条件删除分组内指定行的方法
问题说明
现有如下结构的数据集,其中Sequ为分组变量:
df <- data.frame( Sequ = c(1,1,1,1, 2,2,2, 3,3,3, 4,4,4,4, 5,5,5, 6,6,6,6), Speaker = c("A","B",NA,"A", "B",NA,"C", "A",NA,"A", "A","C",NA,"A", "A",NA,"C", "B","A",NA,"C") )
需求规则:按Sequ分组后,若分组内第2行的Speaker取值不为NA,则删除该行。
使用如下代码尝试实现时,会错误删除整个Sequ分组的全部数据,无法得到目标结果:
library(dplyr) df %>% group_by(Sequ) %>% filter(!is.na(nth(Speaker,2)))
预期输出结果如下:
Sequ Speaker 1 1 A 2 1 <NA> 3 1 A 4 2 B 5 2 <NA> 6 2 C 7 3 A 8 3 <NA> 9 3 A 10 4 A 11 4 <NA> 12 4 A 13 5 A 14 5 <NA> 15 5 C 16 6 B 17 6 <NA> 18 6 C
错误原因
原代码的筛选逻辑存在偏差:nth(Speaker,2)会在每个分组内返回单个常量值(即该组第2个Speaker的取值),因此筛选条件会对整组生效:若该值非NA则保留整组所有行,若该值为NA则删除整组所有行,完全没有针对单行做定位判断,自然无法实现仅删除目标行的效果。
正确实现代码
通过row_number()生成组内行序号,精准定位每个分组的第2行再做判断即可:
library(dplyr) df %>% group_by(Sequ) %>% # 生成组内行序号临时列 mutate(group_row_id = row_number()) %>% # 筛选规则:排除「是组内第2行 且 该行Speaker非NA」的记录 filter(!(group_row_id == 2 & !is.na(Speaker))) %>% # 移除临时生成的行号列 select(-group_row_id) %>% ungroup()
运行上述代码即可得到和预期完全一致的结果。
内容的提问来源于stack exchange,提问作者Chris Ruehlemann
相关产品推荐
相关产品推荐

