分组数据集筛选:保留5列非NA匹配≥3项的首行
分组数据集去重:保留首行移除匹配列≥3的重复行
需求说明
对按指定字段(示例为Month)分组后的数据集,遍历每个分组,检查指定5列:
- 若多行在这些列中有3个及以上非NA值匹配,则仅保留该组内最早出现的首行,移除其余符合匹配条件的行
- 若两两行的匹配数<3,则全部保留
示例数据
data <- data.frame( Month = c("Jan", "Jan", "Jan", "Jan", "Feb"), A = c("apple", "apple", "banana", "cherry", "peach"), B = c("car", "car", "bike", "bike", "plane"), C = c(NA, NA, NA, "cold", NA), D = c("London", "Paris", "Tokyo", "Tokyo", "New York"), E = c("earth", "earth", "wind", "fire", NA) )
问题分析
你提供的尝试代码逻辑有误:
data_cleaned <- data %>% group_by(`Month`) %>% filter(n() == 1 | (n() > 1 & row_number() == which.min(rowSums(!is.na(select(., `A`, `B`, `C`, `D`, `E` ))) >= 3)))
这段代码计算的是每行自身的非NA列数是否≥3,然后取最小行号,完全没有实现“行与行之间的非NA值匹配数≥3”的需求,无法正确筛选目标行。
解决方案代码
使用dplyr和tidyr实现需求逻辑:
library(dplyr) library(tidyr) # 指定需要检查的匹配列 check_cols <- c("A", "B", "C", "D", "E") data_cleaned <- data %>% # 给每行分配唯一行号,用于后续标记移除项 mutate(row_id = row_number()) %>% group_by(Month) %>% # 生成分组内所有行的两两组合,用于逐对比较 expand_grid(., .) %>% ungroup() %>% rowwise() %>% # 计算两两行在指定列的非NA匹配数:非NA且值相等的列数 mutate(match_count = sum( pmap_lgl( list(check_cols), ~ !is.na(get(paste0(.x, ".x"))) & !is.na(get(paste0(.x, ".y"))) & get(paste0(.x, ".x")) == get(paste0(.x, ".y")) ) )) %>% ungroup() %>% # 筛选出匹配数≥3、且前一行出现更早的配对,收集需要移除的行号 filter(match_count >= 3 & row_id.x < row_id.y) %>% pull(row_id.y) %>% # 从原数据中移除标记的行,恢复原顺序 {data %>% mutate(row_id = row_number()) %>% filter(!row_id %in% .)} %>% select(-row_id)
代码解释
- 行号标记:给每行分配
row_id,方便后续精准定位要移除的行 - 两两组合生成:用
expand_grid生成分组内所有行的配对,确保每一行都和其他行做比较 - 匹配数计算:逐对计算指定列中“非NA且值相等”的数量,得到
match_count - 移除行筛选:找出匹配数≥3的配对中,出现较晚的行(
row_id.y),这些就是需要移除的重复行 - 数据清理:从原数据中移除标记的行,得到最终结果
验证结果
运行代码后得到的清理后数据:
> data_cleaned Month A B C D E 1 Jan apple car <NA> London earth 2 Jan banana bike <NA> Tokyo wind 3 Jan cherry bike cold Tokyo fire 4 Feb peach plane <NA> New York <NA>
可以看到Jan组中第2行已被移除,符合需求;其余行均保留。
内容的提问来源于stack exchange,提问作者newts8
相关产品推荐
相关产品推荐

