如何基于经纬度列找出数据框缺失记录?anti_join结果异常排查
问题分析与解决办法
首先,你遇到的anti_join结果和预期行数不符的情况,大概率是两个常见问题导致的:浮点数精度误差,或者你对“独有行数”的预期本身有误。咱们一步步拆解:
1. 先验证你的预期是否正确
你用nrow(CoastalStates_Tax) - nrow(CoastalStates)得到的4,637,029,其实不等于CoastalStates_Tax中真正独有的行数——因为两个数据集都可能存在重复的经纬度对。举个例子:
- 如果
CoastalStates里有1行经纬度是(-77.06421, 39.16937) - 但
CoastalStates_Tax里有3行完全相同的这个经纬度
那么这3行都会被anti_join排除(因为在CoastalStates里能匹配到),但行数差会把这3行都算成“差异”,这就导致了结果的偏差。
你可以用semi_join验证匹配行数:
library(dplyr) # 计算Tax中能在Coastal里匹配到的行数 matched_rows <- semi_join(CoastalStates_Tax, CoastalStates, by = c("PROPERTY LEVEL LONGITUDE", "PROPERTY LEVEL LATITUDE")) # 预期的anti_join结果行数应该是:Tax总行数 - 匹配行数 expected_anti <- nrow(CoastalStates_Tax) - nrow(matched_rows)
如果expected_anti和你实际得到的4,635,393一致,那说明你的初始预期错了,问题出在重复行上,而不是anti_join的误用。
2. 解决浮点数精度问题
经纬度是浮点型数据,计算机存储时会有微小的精度误差(比如-77.06421实际存储可能是-77.0642100001或-77.0642099999),肉眼看起来一样,但anti_join的精确匹配会认为它们是不同的——不过这通常会导致anti_join结果比预期多,而不是少,但也不能完全排除特殊情况。
解决办法是把经纬度四舍五入到足够精确的位数(比如6位,对应约0.1米的精度,完全满足地理数据需求),再做匹配:
# 给两个数据集添加四舍五入后的经纬度列 CoastalStates_Tax_clean <- CoastalStates_Tax %>% mutate( long_round = round(`PROPERTY LEVEL LONGITUDE`, 6), lat_round = round(`PROPERTY LEVEL LATITUDE`, 6) ) CoastalStates_clean <- CoastalStates %>% mutate( long_round = round(`PROPERTY LEVEL LONGITUDE`, 6), lat_round = round(`PROPERTY LEVEL LATITUDE`, 6) ) # 用四舍五入后的列做anti_join,再去掉临时列 diff_rows <- anti_join(CoastalStates_Tax_clean, CoastalStates_clean, by = c("long_round", "lat_round")) %>% select(-long_round, -lat_round)
3. 其他排查与替代方法
- 检查列名和数据类型:确认两个数据集的经纬度列名完全一致(比如有没有多余的空格、大小写差异),且都是
numeric类型:# 检查列名 names(CoastalStates_Tax)[c(2,3)] names(CoastalStates)[c(2,3)] # 检查数据类型 class(CoastalStates_Tax$`PROPERTY LEVEL LONGITUDE`) class(CoastalStates$`PROPERTY LEVEL LONGITUDE`) - 用left_join替代验证:如果
anti_join还是有问题,可以用left_join配合过滤NA的方式得到差异行:diff_rows <- left_join(CoastalStates_Tax, CoastalStates, by = c("PROPERTY LEVEL LONGITUDE", "PROPERTY LEVEL LATITUDE")) %>% filter(is.na(RecordID)) %>% # 用CoastalStates的唯一标识列判断是否匹配 select(names(CoastalStates_Tax)) # 保留Tax的原始列和索引 - 高效处理大型数据集:如果数据量极大,推荐用
data.table的fsetdiff(效率远高于dplyr):library(data.table) setDT(CoastalStates_Tax) setDT(CoastalStates) diff_rows <- fsetdiff(CoastalStates_Tax, CoastalStates, by = c("PROPERTY LEVEL LONGITUDE", "PROPERTY LEVEL LATITUDE"))
4. 关于保留索引
你提到要保留CoastalStates_Tax中的索引,只要你在操作时没有修改或删除原始索引列(比如RecordID_b),上面的所有方法都会自动保留它——因为anti_join、left_join、fsetdiff都会保留左表(也就是CoastalStates_Tax)的所有列。
内容的提问来源于stack exchange,提问作者Alissa
相关产品推荐
相关产品推荐

