问题描述
我正在研究与我的工作相关的类似 CART 的树的终端节点分配的布尔规则 (http://web.ccs.miami.edu/~hishwaran/ishwaran.html)
我注意到在使用 eval 和 parse of text 评估字符串的不等式时存在问题。这个问题与 R 如何评估数字的内部表示有关。
这是一个涉及数字 pi 的示例。我想检查一个向量(我称之为 x)是否小于或等于 pi。
>圆周率
> [1] 3.141593
> rule = paste0("x > 规则
> [1] "x
此规则检查对象 x 是否小于 pi,其中 pi 表示为 14 位数字。现在我将 x 分配给值 1,2,3 和 pi
> x = c(1,3,pi)
x 最多为 15 位
> 打印(x,位数=15)
> [1] 1.00000000000000 2.00000000000000 3.00000000000000 3.14159265358979
现在让我们评估一下
> eval(parse(text = rule))
> [1] 真真假
哇哦aaaaa,看起来pi不小于或等于pi。对吗?
但是现在如果我将 x 硬编码为 pi 到 14 位数字,它会起作用:
> x = c(1,3.14159265358979)
> eval(parse(text = rule))
[1] 对对对对对
显然在第一种情况下,pi 的内部表示有很多数字,因此当 R 计算表达式时,它大于浮点表示并返回 FALSE。在第二种情况下,它比较两个浮点数,因此结果为真。
但是,如何避免这种情况发生呢?我真的需要第一次评估才能恢复原状,因为我正在为基于规则的推理自动化这个过程,而且我不能每次都对一个值(这里是 pi)进行硬编码。
> tol = sqrt(.Machine$double.eps)
> rule = paste0("x > x = c(1,pi)
> eval(parse(text = rule))
> [1]对对对对对对
非常感谢任何意见和建议!
解决方法
您可以只通过 pi 名称或通过函数来代替,以防止 pi
被字符串化(这是您在这里的第一个问题)
rule <- "x <= pi"
x <- c(1,2,3,pi)
eval(parse(text = rule)) ## All TRUE
## another way might be to throw stuff you need uneval'ed into a function or a block:
my_pi <- function() {
pi
}
rule <- "x <= my_pi()"
eval(parse(text = rule)) ## All TRUE
您仍然会遇到常见的浮点问题,但不精确的字符串化将不再是您的问题。
这就是您的方法不起作用的原因:
> print( pi,digits=20 )
[1] 3.141592653589793116
> print( eval(parse(text=pi)),digits=20 )
[1] 3.1415926535897900074
字符串化的 pi 比 R 的 pi 小很多。
paste manual 表示它使用 as.character 将数字转换为字符串。这反过来说明它使用 15 个有效数字,这就是您正在观察的内容。