我在Matlab中错过的一个条件调试标志是:dbstop if infnan
在此处描述。如果设置了这个条件,当遇到Inf
或NaN
时,代码执行将停止(如果我没记错的话,Matlab没有NA)。
我如何在R中实现这一点,比测试每个赋值操作后的所有对象更有效率呢?
目前,我看到的唯一方法是通过以下方式进行黑客攻击:
- 在可能遇到这些值的所有地方手动插入测试(例如,除法,其中可能会发生除以0)。测试将使用
is.finite()
,在此Q&A中描述,应用于每个元素。 - 使用
body()
修改代码,调用单独的函数,在每个操作或可能只在每个分配之后测试所有对象(可能是所有环境中的所有对象)。 - 修改R的源代码(?!)
- 尝试使用
tracemem
识别已更改的变量,并仅检查其中的错误值。 - (新 - 请参见注释2)使用某种调用处理程序/回调来调用测试函数。
目前,我正在进行第一项操作。这很繁琐,因为我无法保证我已经检查了所有内容。第二个选项将测试所有内容,即使对象没有更新。那是浪费时间的巨大浪费。第三个选择涉及修改NA、NaN和无限值(+/- Inf)的分配,以便产生一个错误。这似乎最好留给R Core。第四个选项类似于第二个选项-我需要调用一个列出所有内存位置的单独的函数,只是为了标识那些已更改的内存位置,然后检查其值;我甚至不确定这会对所有对象起作用,因为程序可能会执行原地修改,这似乎不会调用duplicate
函数。
我是否错过了更好的方法?也许是马克·布拉温顿(Mark Bravington)、卢克·蒂尔尼(Luke Tierney)或类似于options()
参数或编译R时的标志等相对基本的聪明工具?
示例代码 这里是一些非常简单的示例代码,用于测试,包括Josh O'Brien提出的addTaskCallback
函数。代码没有中断,但在第一种情况下发生了错误,而在第二种情况下未发生错误(即badDiv(0,0,FALSE)
不会中止)。我仍在调查回调,因为这看起来很有前途。
badDiv <- function(x, y, flag){
z = x / y
if(flag == TRUE){
return(z)
} else {
return(FALSE)
}
}
addTaskCallback(stopOnNaNs)
badDiv(0, 0, TRUE)
addTaskCallback(stopOnNaNs)
badDiv(0, 0, FALSE)
注意1:我会满足于使用标准的 R 操作来解决问题,但我的许多计算涉及通过 data.table
或 bigmemory
使用的对象(即基于磁盘的内存映射矩阵)。这些似乎具有与标准矩阵和数据框操作不同的内存行为。
注意2:回调函数的想法似乎更有前途,因为这不需要我编写可以改变 R 代码的函数,例如通过 body()
的想法。
注意3:我不知道是否存在一些简单的方法来测试非有限值的存在,例如有关对象的元信息,索引 NA、Inf 等存储在对象中的位置,还是这些信息存储在原地。到目前为止,我尝试了 Simon Urbanek 的 inspect
包,并没有找到一种方式来确定非数值值的存在。
后续:Simon Urbanek 在评论中指出,这样的信息作为对象的元信息是不可用的。
注意4:我仍在测试所提出的想法。正如 Simon 建议的那样,检测非有限值的存在应该在 C/C++ 中是最快的;这应该比编译后的 R 代码还要快,但我对任何方法都持开放态度。对于大型数据集,例如在 10-50GB 的量级上,这应该比复制数据节省时间。通过使用多个内核,可以获得进一步的改进,但那需要更高级的技能。
sin(Inf)
。也许这是你可以探索的内容。 - Brandon Bertelsenis.infinite
和/或is.nan
对可疑变量进行更好的信息获取。 - Carl Witthoft