你是否将 == 和 != 重新分配为 isTRUE(all.equal())?

8

一个之前的帖子促使我发布了这个问题。将==重新分配为isTRUE(all.equal())(并将!=重新分配为!isTRUE(all.equal()))似乎是最佳实践。我想知道其他人是否在实践中这样做?我刚意识到我在整个代码库中使用==!=进行数字相等性比较。我的第一反应是我需要进行全面清理并转换为all.equal。但事实上,每次我使用==!=时,我都想测试相等性(无论数据类型如何)。事实上,除了相等性之外,我不确定这些操作会测试什么。我肯定错过了某些概念。有人能启发我吗?我看到的唯一反对这种方法的论点是,在某些情况下,由于all.equal的公差,两个非相同的数字将看起来是相同的。但我们被告知,实际上相同的两个数字可能由于它们在内存中的存储方式而不能通过identical()。所以,不默认使用all.equal的意义是什么呢?


那似乎是一件奇怪的事情,但我在比较帮助页面中读到了注释:“不要使用==和!=进行测试,例如在if表达式中,您必须获得单个TRUE或FALSE。除非您绝对确定不会发生任何异常情况,否则应改用identical函数。”所以也许这并不是一个荒谬的想法。 - Brian Diggs
3
不,你不应该这样做。使用"identical"代替,当对子集进行矢量化比较时保留"=="。 - joran
3
如果你开始过度使用常见的运算符,你的代码将变得非常不可移植。更好的方法是学习每个运算符或函数的作用,并选择正确的工具来完成正确的工作。 - Carl Witthoft
1
但是identical并不总是有效。来自R常见问题解答: “因此,除非它们已经通过相同的算法计算,否则两个浮点数将不可靠地相等,即使在这种情况下也不总是如此”。 基本上,这意味着即使两个数字相同,使用identical也会失败! - Suraj
1
@SFun28 是的,但那只是一个浮点数问题,在任何地方都会遇到。最好不要掩盖 ==。为什么要定义新的 ===!==,而不是使用 isTRUEall.equal 呢? - joran
joran - 我同意掩码不是一个好的解决方案。这只是一个令人沮丧的问题,因为“==”和“!=”很直观,但需要谨慎使用。 - Suraj
1个回答

8
正如@joran所暗示的,你在任何其他语言中也会遇到使用==!=时的浮点问题。它们在R中的一个重要方面是向量化部分。
最好定义一个新的函数almostEqualfuzzyEqual或类似的函数。不幸的是,没有这样的基本函数。all.equal并不是非常有效,因为它处理各种对象并返回一个描述差异的字符串,而大多数时候你只想要TRUEFALSE
下面是这样一个函数的例子。它像==一样进行向量化。
almostEqual <- function(x, y, tolerance=1e-8) {
  diff <- abs(x - y)
  mag <- pmax( abs(x), abs(y) )
  ifelse( mag > tolerance, diff/mag <= tolerance, diff <= tolerance)
}

almostEqual(1, c(1+1e-8, 1+2e-8)) # [1]  TRUE FALSE

...它比all.equal在标量值上快大约2倍,在向量方面要快得多。

x <- 1
y <- 1+1e-8
system.time(for(i in 1:1e4) almostEqual(x, y)) # 0.44 seconds
system.time(for(i in 1:1e4) all.equal(x, y))   # 0.93 seconds

汤米 - 经过一些测试,我认为这个函数存在一个错误。请考虑以下内容:matrixa = round( matrix( rnorm( 9 ) , nrow = 3 , ncol = 3 ) , 6 ) matrixb = matrixa - .001 almostEqual( matrixa , matrixb , tolerance = .001 ) - Suraj
即使这样有时也会产生假值:almostEqual( matrixa , matrixb , tolerance = .01 ) - Suraj
@SFun28 - 我认为代码是正确的。尝试使用all.equal并且你也会得到非TRUE值。这是因为它是相对容忍度。rnorm可以给出大(3.5)或小(0.0003)的数字,但你添加到matrixb的误差始终是0.001。尝试使用matrixb <- matrixa*1.001 - Tommy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接