Ite*_*tor 11 debugging conditional r nan
我从Matlab那里得到了一个条件调试标志:dbstop if infnan
这里描述.如果设置,此条件将在遇到Inf
或NaN
遇到时停止代码执行(IIRC,Matlab没有NA).
如何在R中以比在每次赋值操作后测试所有对象更有效的方式实现此目的?
目前,我认为这样做的唯一方法是通过以下方式进行黑客攻击:
is.finite()
,在这个问答描述,每一个元件上.body()
修改代码来调用一个单独的功能,每一个操作或者可能只是每个任务,测试所有对象(也可能在所有环境中的所有对象)之后.tracemem
标识已更改的变量,并仅检查这些变量是否为错误值.第一个选项是我目前正在做的事情.这很乏味,因为我无法保证我已经检查过所有内容.第二个选项将测试所有内容,即使对象尚未更新.这是浪费大量时间.第3个选项将涉及修改NA,NaN和无限值(+/- Inf)的赋值,以便产生错误.这似乎最好留给R Core.第四个选项就像第二个选项 - 我需要调用一个单独的函数列出所有内存位置,只需要识别那些已更改的ID,然后检查值; 我甚至不确定它是否适用于所有对象,因为程序可能会进行就地修改,这似乎不会调用该duplicate
函数.
我错过了更好的方法吗?也许Mark Bravington,Luke Tierney的一些聪明的工具,或者相对基本的东西 - options()
在编译R时类似于参数或标志?
示例代码下面是一些非常简单的示例代码,可以使用addTaskCallback
Josh O'Brien提出的函数进行测试.代码不会中断,但在第一种情况下确实会发生错误,而在第二种情况下不会发生错误(即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)
Run Code Online (Sandbox Code Playgroud)
注意1.我对标准R操作的解决方案感到满意,尽管我的很多计算涉及通过data.table
或使用的对象bigmemory
(即基于磁盘的内存映射矩阵).它们似乎与标准矩阵和data.frame操作有一些不同的记忆行为.
注2:回调的想法似乎更有希望,因为这并不需要我编写改变R代码的函数,例如通过这个body()
想法.
注3.我不知道是否有一些简单的方法可以测试是否存在非有限值,例如关于对象的元信息,这些对象指的是NAs,Infs等存储在对象中的对象,或者如果是存储到位.到目前为止,我已经尝试了Simon Urbanek的inspect
软件包,并没有找到一种方法来判断非数字值的存在.
后续行动: Simon Urbanek在评论中指出,此类信息不可用作对象的元信息.
注4.我仍在测试所提出的想法.另外,正如Simon所建议的那样,在C/C++中测试非有限值的存在应该是最快的; 这应该超过编译的R代码,但我对任何事情持开放态度.对于大型数据集,例如大约10-50GB,这应该比复制数据节省大量资金.通过使用多个内核可以获得进一步的改进,但这有点先进.
我担心没有这样的捷径.在unix的理论上SIGFPE
,你可以陷入困境,但在实践中
feenableexcept
在Linux上,fp_enable_all
在AIX上等)或者需要为目标使用汇编程序中央处理器NaN
s,NA
s并单独处理它们,因此它们不会进入FP代码也就是说,如果你足够努力(禁用SSE等),你可能会破解自己的R会为你的平台和CPU捕获一些例外.我们不会考虑将其构建到R中,但出于特殊目的,它可能是可行的.
但是,除非您更改R内部代码,否则它仍然不会捕获NaN
/ NA
操作.此外,你必须检查你使用的,因为他们可以在他们的C代码使用FP操作的每一个包,还可以处理NA
/ NaN
分开.
如果你只是担心除零或上溢/下溢之类的东西,上面的方法就可以了,并且可能是最接近解决方案的东西.
只检查结果可能不太可靠,因为您不知道结果是否基于某些中间NaN
计算,这些计算更改了可能不需要的聚合值NaN
.如果您愿意丢弃此类案例,那么您可以简单地遍历结果对象或工作区.这不应该是非常低效的,因为你只需要担心REALSXP
而不是其他任何事情(除非你不喜欢NA
- 否则你会有更多的工作).
这是一个示例代码,可用于递归遍历R对象:
static int do_isFinite(SEXP x) {
/* recurse into generic vectors (lists) */
if (TYPEOF(x) == VECSXP) {
int n = LENGTH(x);
for (int i = 0; i < n; i++)
if (!do_isFinite(VECTOR_ELT(x, i))) return 0;
}
/* recurse into pairlists */
if (TYPEOF(x) == LISTSXP) {
while (x != R_NilValue) {
if (!do_isFinite(CAR(x))) return 0;
x = CDR(x);
}
return 1;
}
/* I wouldn't bother with attributes except for S4
where attributes are slots */
if (IS_S4_OBJECT(x) && !do_isFinite(ATTRIB(x))) return 0;
/* check reals */
if (TYPEOF(x) == REALSXP) {
int n = LENGTH(x);
double *d = REAL(x);
for (int i = 0; i < n; i++) if (!R_finite(d[i])) return 0;
}
return 1;
}
SEXP isFinite(SEXP x) { return ScalarLogical(do_isFinite(x)); }
# in R: .Call("isFinite", x)
Run Code Online (Sandbox Code Playgroud)
下面概述的概念(及其实现)非常不完美.我甚至犹豫不决,但是:(a)我觉得它很有趣,即使在它的丑陋中也是如此; (b)我可以想到它会有用的情况.鉴于你现在听起来像是在每次计算后手动插入支票,我希望你的情况就是其中之一.
我是一个两步黑客.首先,我定义了一个函数nanDetector()
,用于检测NaN
计算可能返回的几种对象类型中的s.然后,使用addTaskCallback()
调用函数nanDetector()
在.Last.value
每个顶级任务/计算完成后.当它NaN
在其中一个返回值中找到时,会抛出一个错误,您可以使用该错误来避免任何进一步的计算.
其缺点包括:
如果您执行类似设置的操作stop(error = recover)
,则很难确定错误被触发的位置,因为错误总是从内部抛出stopOnNaNs()
.
当它抛出错误时,stopOnNaNs()
在它返回之前终止TRUE
.因此,它将从任务列表中删除,您需要重置addTaskCallback(stopOnNaNs)
它才能再次使用它.(有关更多详细信息,请参阅?addTaskCallback的 'Arguments'部分).
不用多说,这里是:
# Sketch of a function that tests for NaNs in several types of objects
nanDetector <- function(X) {
# To examine data frames
if(is.data.frame(X)) {
return(any(unlist(sapply(X, is.nan))))
}
# To examine vectors, matrices, or arrays
if(is.numeric(X)) {
return(any(is.nan(X)))
}
# To examine lists, including nested lists
if(is.list(X)) {
return(any(rapply(X, is.nan)))
}
return(FALSE)
}
# Set up the taskCallback
stopOnNaNs <- function(...) {
if(nanDetector(.Last.value)) {stop("NaNs detected!\n")}
return(TRUE)
}
addTaskCallback(stopOnNaNs)
# Try it out
j <- 1:00
y <- rnorm(99)
l <- list(a=1:4, b=list(j=1:4, k=NaN))
# Error in function (...) : NaNs detected!
# Subsequent time consuming code that could be avoided if the
# error thrown above is used to stop its evaluation.
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3055 次 |
最近记录: |