在R中识别两数据框的额外观测:setdiff返回空的解决方法
如何识别两个数据框的额外观测(setdiff返回空的情况)
这种情况我之前排查过好多次,明明行数差了2条,但dplyr::setdiff()却返回空结果,大概率是因为重复行或者肉眼不可见的细微差异(比如数据类型、隐形字符)在搞鬼。给你几个逐步排查的实用方法:
先检查重复行
setdiff()的逻辑是找唯一存在于某一个数据框的行,如果d2多出来的2行是d1里本来就有的重复行,那setdiff()就抓不到差异。可以用计数的方式查看重复情况:library(dplyr) # 查看d1中所有重复的行及出现次数 d1 %>% count(across(everything())) %>% filter(n > 1) # 查看d2中所有重复的行及出现次数 d2 %>% count(across(everything())) %>% filter(n > 1)对比两者的计数结果,如果某一行在d2中的计数比d1多1,那多出来的就是重复的观测。
统一列的数据类型
有时候两个数据框的列名完全一致,但数据类型不同(比如d1某列是integer,d2对应列是numeric;或者字符串列和因子列混用),R会认为这些行是不同的,但肉眼很难发现。先查看列类型:str(d1) str(d2)然后把d2的列类型统一成和d1一致:
d2 <- d2 %>% mutate(across(names(d1), ~type.convert(as.character(.), as.is = TRUE)))之后再尝试
setdiff(d2, d1)和setdiff(d1, d2)。清理字符串列的隐形字符
字符串列里的空格、换行符、全角/半角差异等隐形字符,会让R判定行不同,但肉眼无法识别。可以用stringr包统一清理:library(stringr) # 清理d1的字符串列:去除前后空格、统一换行符 d1_clean <- d1 %>% mutate(across(where(is.character), ~str_squish(str_replace_all(., "\\r\\n|\\r|\\n", " ")))) # 同样清理d2 d2_clean <- d2 %>% mutate(across(where(is.character), ~str_squish(str_replace_all(., "\\r\\n|\\r|\\n", " ")))) # 再对比差异 setdiff(d2_clean, d1_clean) setdiff(d1_clean, d2_clean)用
anti_join替代setdiffsetdiff()会自动去重,而anti_join()会返回所有在x中但不在y中的行(包括重复行),更适合找数量差异:# 找d2中有但d1中没有的所有行(含重复) anti_join(d2, d1, by = names(d1)) # 找d1中有但d2中没有的所有行(含重复) anti_join(d1, d2, by = names(d1))用行哈希值精准对比
如果上面的方法都没找到差异,可以用digest包给每行生成唯一哈希值,精准匹配内容:library(digest) # 给d1每行生成哈希 d1$row_hash <- apply(d1, 1, digest) # 给d2每行生成哈希 d2$row_hash <- apply(d2, 1, digest) # 提取d2中哈希不在d1里的行 d2_extra <- d2[!d2$row_hash %in% d1$row_hash, ] # 提取d1中哈希不在d2里的行 d1_extra <- d1[!d1$row_hash %in% d2$row_hash, ]这个方法能捕捉到任何细微的内容差异,几乎不会漏过问题。
内容的提问来源于stack exchange,提问作者Navya
相关产品推荐
相关产品推荐

