R dataframe按部分匹配删除/覆盖重复行 保留非NA值最多的行
R 实现多列部分匹配行去重(保留非NA值最多行)
实现逻辑
无需指定匹配列,自动将所有非NA列值完全匹配的行归为一组,每组仅保留非NA值数量最多的行,适配含list列的场景。
代码实现
tidyverse 版本(推荐,支持list列)
library(tidyverse) library(jsonlite) # 你的原始数据 df <- structure(list(o1 = c(1L, 2L, 3L, 4L, 6L, 7L, 5L, 10L, 12L, 13L, 5L, 14L, 8L, 16L, 17L, 18L, 19L, 20L), o2 = c(NA, NA, NA, NA, NA, NA, 9L, NA, NA, NA, 9L, NA, 11L, NA, NA, NA, NA, NA), o3 = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 14L, NA, 15L, NA, NA, NA, NA, NA)), row.names = c(NA, -18L), class = "data.frame") df_result <- df %>% # 统计每行非NA值的数量 mutate(non_na_count = rowSums(!is.na(across(everything()))), # 生成匹配键:序列化所有非NA列的键值对,支持list类型列 match_key = pmap_chr(across(everything()), function(...) { row_vals <- list(...) non_na_vals <- row_vals[!sapply(row_vals, function(x) all(is.na(x)))] toJSON(non_na_vals, auto_unbox = TRUE) })) %>% # 按匹配键分组,组内按非NA数量降序排序 group_by(match_key) %>% arrange(desc(non_na_count), .by_group = TRUE) %>% # 每组仅保留非NA数量最多的第一行 slice_head(n = 1) %>% ungroup() %>% # 移除辅助计算列 select(-non_na_count, -match_key)
基础R版本(无额外依赖,仅支持基础类型列)
df <- structure(list(o1 = c(1L, 2L, 3L, 4L, 6L, 7L, 5L, 10L, 12L, 13L, 5L, 14L, 8L, 16L, 17L, 18L, 19L, 20L), o2 = c(NA, NA, NA, NA, NA, NA, 9L, NA, NA, NA, 9L, NA, 11L, NA, NA, NA, NA, NA), o3 = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 14L, NA, 15L, NA, NA, NA, NA, NA)), row.names = c(NA, -18L), class = "data.frame") # 统计非NA数量 df$non_na_count <- rowSums(!is.na(df)) # 生成匹配键 df$match_key <- apply(df, 1, function(row) { non_na_item <- row[!is.na(row)] paste(paste0(names(non_na_item), "=", non_na_item), collapse = "|") }) # 排序后去重,仅保留每组第一条 df <- df[order(df$match_key, -df$non_na_count), ] df_result <- df[!duplicated(df$match_key), setdiff(colnames(df), c("non_na_count", "match_key"))]
效果说明
运行上述代码后,示例数据中的第7行(仅2个非NA值)会被自动过滤,仅保留第11行(3个非NA值),和预期结果完全一致。后续新增列无需修改代码逻辑,自动适配。
内容的提问来源于stack exchange,提问作者D.J
相关产品推荐
相关产品推荐

