R语言中数值向量使用%in%运算符出现异常行为的问题
浮点数精度导致
%in%检查不一致的问题 问题现象
生成0到1、步长0.1的序列后,部分数值用%in%检查存在性时返回异常结果:
numsequence <- seq(0,1,0.1) 0.2 %in% numsequence # 返回TRUE 0.3 %in% numsequence # 返回FALSE 0.4 %in% numsequence # 返回TRUE 0.5 %in% numsequence # 返回TRUE 0.6 %in% numsequence # 返回FALSE
自定义循环中同样出现问题:
numsequence <- seq(0,1,0.1) vectortosearch <- unique(simResults_SURU$ReusePrevBefore) # vectortosearch输出为:0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 str(vectortosearch) # num [1:11] 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 ... for(v in vectortosearch){ print(v) if (v %in% numsequence ){ print(v) } }
输出结果中,0.3、0.6、0.7未通过检查,不会重复打印;但直接遍历numsequence时,所有元素都能通过自身的%in%检查。
原因分析
这是浮点数二进制存储的精度问题:十进制的0.1无法被二进制精确表示,seq(0,1,0.1)生成的序列里的数值是0.1近似值的累加,比如numsequence[4]实际存储的是0.30000000000000004,而非精确的十进制0.3。
而vectortosearch中的数值(如0.3)可能是精确的十进制转换结果,或者是另一种近似值。%in%底层依赖==做精确相等判断,两个近似值存在微小差异时,判断结果为FALSE。
直接遍历numsequence时,是拿序列内的元素和自身比较,近似值完全一致,所以返回TRUE。
解决方案
方案1:使用近似相等判断
用all.equal()或设置容忍度代替精确比较,比如:
for(v in vectortosearch){ print(v) if (any(sapply(numsequence, function(x) all.equal(v, x)))){ print(v) } }
或者手动设置误差容忍:
for(v in vectortosearch){ print(v) if (any(abs(v - numsequence) < 1e-10)){ print(v) } }
方案2:转换为整数比较
将浮点数乘以10转为整数,避免精度问题:
numsequence_int <- seq(0, 10, 1) vectortosearch_int <- vectortosearch * 10 for(v_int in vectortosearch_int){ v <- v_int / 10 print(v) if (v_int %in% numsequence_int){ print(v) } }
方案3:使用专门的浮点数比较函数
用dplyr::near()函数,它内置了合理的容忍度:
library(dplyr) for(v in vectortosearch){ print(v) if (any(near(v, numsequence))){ print(v) } }
内容的提问来源于stack exchange,提问作者ktheyss
相关产品推荐
相关产品推荐

