如何在忽略NA值(NA与值视为匹配)的情况下检测重复项
如何在R中忽略NA值检测重复项(NA与对应非NA值视为匹配)
问题描述
需要检测数据集中的重复项,规则是当某列的一个值与NA比较时,二者视为匹配。例如以下数据集:
dt <- data.table(col1 = c("A", "B", NA, "A", "C", "C"), col2 = c("Z", "Y", "Z", NA, "X", "X"), col3 = c(1, 2, 1, 1, 3, 3))
期望结果:
- 第5、6行完全重复,需标记为重复对
- 第1行(
col1=A, col2=Z, col3=1)与第4行(col1=A, col2=NA, col3=1)需标记为重复(因col1和col3值一致,col2的NA与Z视为匹配)
但常规的duplicated()或分组方法仅能标记完全重复的第5、6行,无法识别第1、4行这类含NA的重复。
现有方法的局限
使用常规分组或duplicated()函数的结果如下:
方法1:dplyr分组
library(dplyr) dupes_flagged <- dt %>% group_by(pick(1:3)) %>% mutate(dupe_group = cur_group_id())
结果:
col1 col2 col3 dupe_group 1: A Z 1 1 2: B Y 2 3 3: <NA> Z 1 5 4: A <NA> 1 2 5: C X 3 4 6: C X 3 4
第1、4行被分到不同组,未识别为重复。
方法2:data.table的duplicated()
library(data.table) dt <- as.data.table(dt) dup = duplicated(dt, by = c("col1", "col2", "col3")) dt[, dupe_group := dup | c(tail(dup, -1), FALSE)]
结果:
col1 col2 col3 dupe_group 1: A Z 1 FALSE 2: B Y 2 FALSE 3: <NA> Z 1 FALSE 4: A <NA> 1 FALSE 5: C X 3 TRUE 6: C X 3 TRUE
仅第5、6行被标记为重复。
解决方案
方法1:模糊分组(NA与任意值视为匹配)
使用fuzzyjoin包的fuzzy_group_by函数,自定义匹配规则:两列值相等,或其中一个为NA时视为匹配。
install.packages("fuzzyjoin") library(fuzzyjoin) library(dplyr) dt %>% fuzzy_group_by( across(everything()), match_fun = ~ .x == .y | is.na(.x) | is.na(.y) ) %>% mutate( dupe_group = cur_group_id(), is_dupe = n() > 1 ) %>% ungroup()
结果:
col1 col2 col3 dupe_group is_dupe 1: A Z 1 1 TRUE 2: B Y 2 2 FALSE 3: <NA> Z 1 1 TRUE 4: A <NA> 1 1 TRUE 5: C X 3 3 TRUE 6: C X 3 3 TRUE
此方法会将第1、3、4行都标记为同一重复组,符合“NA与任意值匹配”的规则。
方法2:仅匹配非NA列的交集(精准匹配用户示例需求)
如果仅希望当两个行的所有非NA列值完全一致时视为重复(即NA等价于“忽略该列”),可以通过生成每行的非NA键来实现:
library(dplyr) library(data.table) dt %>% rowwise() %>% # 生成由非NA列名和值组成的有序字符串键 mutate( key = paste(sort(names(.)[!is.na(c_across(everything()))]), sort(c_across(everything())[!is.na(c_across(everything()))]), sep = ":", collapse = ", ") ) %>% ungroup() %>% group_by(key) %>% mutate( dupe_group = cur_group_id(), is_dupe = n() > 1 ) %>% select(-key)
结果:
col1 col2 col3 dupe_group is_dupe 1: A Z 1 1 TRUE 2: B Y 2 2 FALSE 3: <NA> Z 1 3 FALSE 4: A <NA> 1 1 TRUE 5: C X 3 4 TRUE 6: C X 3 4 TRUE
此方法精准匹配用户示例需求:第1、4行因非NA列(col1、col3)值一致被标记为重复,第3行因非NA列(col2、col3)与其他行无匹配,未被标记。
内容的提问来源于stack exchange,提问作者Sean Ryan
相关产品推荐
相关产品推荐

