which()与match()在R语言降序序列中无法匹配元素的问题
浮点数精度误差导致的匹配失败问题
这是典型的浮点数精度误差问题,R使用二进制格式存储浮点数,像0.1这类十进制小数无法被二进制精确表示,累加或累减操作会让误差累积,最终导致严格匹配失效。
具体原因分析
- 升序序列
seq(.1, 10, .1)中,0.2是两次0.1的累加,虽然单个0.1有精度误差,但两次累加后的结果与直接输入的0.2二进制存储刚好处于严格相等的范围,所以match和%in%能正常匹配。 - 降序序列
seq(10, .1, -.1)中,0.2是10连续减去99次0.1得到的,累积的精度误差让test[99]的实际存储值和你输入的0.2并不完全相等:
test <- seq(10, .1, -.1) # 打印精确到20位的数值 sprintf("%.20f", test[99]) # 输出 0.20000000000000222045 sprintf("%.20f", 0.2) # 输出 0.20000000000000001110
而match、%in%和==都是基于严格相等的比较,所以无法匹配到0.2。
验证与解决办法
可以用all.equal()做带容忍度的比较来验证:
all.equal(test[99], 0.2) # 返回TRUE,说明数值在统计意义上相等 test[99] == 0.2 # 返回FALSE,严格相等不成立
解决这个问题的两种常用方法:
- 用带容忍度的匹配替代严格匹配:
which(sapply(test, function(x) isTRUE(all.equal(x, 0.2))))
- 避免浮点数累加/累减,用整数转换生成序列:
# 先生成整数序列再除以10,彻底避免精度误差 test <- rev(1:100 / 10) match(c(0.1, 0.2, 4, 7), test) # 输出 [1] 100 99 61 31 which(test %in% c(0.1, 0.2, 4, 7)) # 输出 [1] 31 61 99 100
内容的提问来源于stack exchange,提问作者Lucia
相关产品推荐
相关产品推荐

