-->

对于R中调试一般建议(General suggestions for debugging in R)

2019-06-26 14:31发布

我使用,我写了一个R函数时,得到一个错误:

Warning messages:
1: glm.fit: algorithm did not converge 
2: glm.fit: algorithm did not converge 

我做了什么:

  1. 通过功能步骤
  2. 添加打印在发生什么行错误,找出表明,不应该使用两种功能glm.fit 。 他们是window()save()

我常用的方法包括增加printstop命令,并通过线通过函数线步进,直到我可以找到例外。

然而,使用其中这个错误来自于那些代码技术不是很清楚,我。 我甚至不能肯定哪个函数的代码中依赖于glm.fit 。 我该如何去诊断这个问题?

Answer 1:

我会说,调试是一种艺术形式,所以没有明确的银弹。 有在任何语言调试好的策略,这里太它们应用(如阅读这篇好文章 )。 例如,第一件事就是要重现该问题 ...如果你不能做到这一点,那么你就需要获得更多的信息(例如日志记录)。 一旦你能复制它,你需要减少下来的来源。

而不是一个“绝招”,我要说的是我最喜欢的调试程序:

  1. 当错误发生时,我通常做的第一件事是看堆栈跟踪通过调用traceback()显示你在哪里发生了错误,如果你有几个嵌套的功能,这是非常有用的。
  2. 接下来,我将设置options(error=recover) ; 这立即切换到浏览器模式,其中发生错误,这样你就可以从那里浏览该工作区。
  3. 如果我还没有足够的信息,我通常使用的debug()通过行脚本行功能和步骤。

R中2.10(与脚本文件时)最好的新诀窍是使用findLineNum()setBreakpoint()函数。

作为最后的评论:根据错误,这也是非常有帮助的设置try()tryCatch()与S4类打交道时,特别是)围绕外部函数调用语句。 这有时会提供更多的信息,同时也为您提供了错误的方式在运行时处理更多的控制。

这些相关的问题有很多的建议:

  • 调试工具R语言
  • 调试lapply / sapply电话
  • 获取变量的状态中的R在错误发生后
  • 在误差R脚本行号?


Answer 2:

到目前为止,我见过的最好的演练是:

http://www.biostat.jhsph.edu/%7Erpeng/docs/R-debug-tools.pdf

任何人都同意/不同意?



Answer 3:

正如向我指出的另一个问题 , Rprof()summaryRprof()是很好的工具, 找到你的程序的缓慢的部分可能从加快或移动到C / C ++实现中受益。 这可能适用于更多,如果你正在做的模拟工作或其他compute-或数据密集型活动。 该profr包可以帮助可视化的结果。

我在一个有点了解,有关调试踢的,所以从另一个建议另一个线程 :

  • 设置options(warn=2)以像对待错误警告

您还可以使用options给你降权到行动热的时候出现错误或警告,使用选择你最喜欢的调试功能。 例如:

  • 设置options(error=recover)运行recover()时发生错误,因为巴蒂尔注意到(并作为中记载[R调试指导 。或任何其他方便的功能,你会发现有跑有用。

而从@ Shane的彼此两种方法链接 :

  • 包裹的内部函数调用try()返回它的更多信息。
  • 为*应用的功能,使用.inform=TRUE (从plyr包)作为一个选项的应用命令

@JoshuaUlrich 还指出,采用了经典的条件能力的一个非常简洁的方式browser()命令打开/关闭调试:

  • 把里面的功能你可能要调试browser(expr=isTRUE(getOption("myDebug")))
  • 并且设置了全局选项options(myDebug=TRUE)
  • 你甚至可以换浏览器调用: myBrowse <- browser(expr=isTRUE(getOption("myDebug")))然后用调用myBrowse()因为它使用全局变量。

再就是R中2.10提供的新功能:

  • findLineNum()需要一个源文件名和行号,并返回的功能和环境。 这似乎是有帮助的,当你source()一个.R文件,并将其返回在行#N错误,但你需要知道的是位于行#N什么功能。
  • setBreakpoint()需要一个源文件名和行号,并设置一个断点

该编码工具编码工具包,特别是其checkUsage功能特别有帮助在快速回升的语法和文体错误,一个编译器通常会报告(未使用的当地人,未定义的全局函数和变量,部分参数匹配,等等)。

setBreakpoint()是一个更加用户友好的前端到trace() 关于如何在内部细节这个作品是一个可用R最近期刊文章 。

如果您正试图调试别人的包,一旦你找到你的问题在写自己的职能与fixInNamespaceassignInNamespace ,但在产品代码不使用此。

这些都不应该排除尝试和真正标准的R调试工具 ,其中有些是上面一些因素是不可。 特别是, 验尸调试工具是很方便的,当你有一个代码,你不想再运行一个耗时的一群。

最后,这似乎并没有抛出一个错误消息棘手的问题,你可以使用options(error=dump.frames)在这个问题详述: 错误而不引发错误



Answer 4:

在某些时候, glm.fit被调用。 这意味着你调用的函数或由这些函数调用的函数一个人使用任何glmglm.fit

此外,正如我在评论提到上面,这是一个警告不是错误 ,这使得一个很大的不同。 有人告诉我之前,我错了;-)你不能从一个警告(使用默认选项触发任何讨论R的调试工具。

如果我们改变了选项中打开警告到错误,那么我们就可以开始使用的r调试工具。 从?options有:

 ‘warn’: sets the handling of warning messages.  If ‘warn’ is
      negative all warnings are ignored.  If ‘warn’ is zero (the
      default) warnings are stored until the top-level function
      returns.  If fewer than 10 warnings were signalled they will
      be printed otherwise a message saying how many (max 50) were
      signalled.  An object called ‘last.warning’ is created and
      can be printed through the function ‘warnings’.  If ‘warn’ is
      one, warnings are printed as they occur.  If ‘warn’ is two or
      larger all warnings are turned into errors.

所以,如果你运行

options(warn = 2)

然后运行你的代码,R将抛出一个错误。 在这一点,你可以运行

traceback()

看到调用堆栈。 下面是一个例子。

> options(warn = 2)
> foo <- function(x) bar(x + 2)
> bar <- function(y) warning("don't want to use 'y'!")
> foo(1)
Error in bar(x + 2) : (converted from warning) don't want to use 'y'!
> traceback()
7: doWithOneRestart(return(expr), restart)
6: withOneRestart(expr, restarts[[1L]])
5: withRestarts({
       .Internal(.signalCondition(simpleWarning(msg, call), msg, 
           call))
       .Internal(.dfltWarn(msg, call))
   }, muffleWarning = function() NULL)
4: .signalSimpleWarning("don't want to use 'y'!", quote(bar(x + 
       2)))
3: warning("don't want to use 'y'!")
2: bar(x + 2)
1: foo(1)

在这里,你可以忽略帧标记4:高。 我们看到, foo称为barbar产生的警告。 这应该显示哪些功能分别致电glm.fit

如果你现在想调试这一点,我们就可以转到另一个选项,让R时遇到错误进入调试器,以及我们做出错误的警告时触发原有的警告时,我们会得到一个调试器。 对于您应该运行:

options(error = recover)

下面是一个例子:

> options(error = recover)
> foo(1)
Error in bar(x + 2) : (converted from warning) don't want to use 'y'!

Enter a frame number, or 0 to exit   

1: foo(1)
2: bar(x + 2)
3: warning("don't want to use 'y'!")
4: .signalSimpleWarning("don't want to use 'y'!", quote(bar(x + 2)))
5: withRestarts({
6: withOneRestart(expr, restarts[[1]])
7: doWithOneRestart(return(expr), restart)

Selection:

然后,您可以进入其中任何帧时看到抛出的警告发生了什么事。

要重置以上选项的默认输入

options(error = NULL, warn = 0)

至于你引用特定的警告,它极有可能,你需要让代码更迭代。 一旦你发现了什么在呼唤glm.fit ,制定出如何通过它control使用参数glm.control -见?glm.control



Answer 5:

所以browser() traceback()debug()走进一间酒吧,但trace()等待之外,并保持电机运转。

通过将browser在你的函数的地方,执行将暂停,等待您的输入。 您可以向前用 (或回车 ),运行的整个块(迭代)与C,其中f完成电流回路/功能,或用Q退出; 看?browser

随着debug ,你会得到同样的效果与浏览器,但这种停止功能的执行在其开始。 同样的快捷键适用。 该功能将在“调试”模式,直至将其关闭使用undebug (即,经过debug(foo) ,运行函数foo ,直到你每次运行将进入“调试”模式undebug(foo) )。

更短暂的替代方案是debugonce ,它将从功能它评估的下一次后删除“调试”模式。

traceback会给你执行的功能一路攀升到出事了的流量(实际误差)。

您可以使用插入函数代码位(即自定义函数) trace ,例如browser 。 这是从包功能非常有用,你就懒得得到很好的折叠源代码。



Answer 6:

我一般的策略是这样的:

  1. 运行traceback()看到寻找明显的问题
  2. 设置options(warn=2)以像对待错误警告
  3. options(error=recover)到步骤插入错误的调用堆栈


Answer 7:

穿过这里提出的所有步骤去后,我刚刚得知,设置.verbose = TRUEforeach()也给了我很多实用的信息。 特别foreach(.verbose=TRUE)示出的确切位置foreach循环内发生了错误,而traceback()不看foreach循环内部。



Answer 8:

马克Bravington的调试器,它可作为包debug上CRAN是非常好,非常直截了当。

library(debug);
mtrace(myfunction);
myfunction(a,b);
#... debugging, can query objects, step, skip, run, breakpoints etc..
qqq(); # quit the debugger only
mtrace.off(); # turn off debugging

代码中突出显示的Tk的窗口弹出,所以你可以看到发生了什么事情,当然你可以调用另一个mtrace()而在不同的功能。

HTH



Answer 9:

我喜欢加文的回答是:我不知道选项(错误=恢复)。 我也喜欢用“调试”包,给人以视觉的方式来逐步执行代码。

require(debug)
mtrace(foo)
foo(1)

在这一点上它打开了你的显示功能的单独调试窗口,用黄线表示在你的代码。 在主窗口中的代码进入调试模式,并且可以保持击球进入到步骤通过代码(也有其他命令以及),并检查变量值等在调试窗口黄线保持移动以示出你在代码中。 当与调试完成后,你可以关闭与跟踪:

mtrace.off()


Answer 10:

根据我收到的答案在这里 ,你一定要检查出options(error=recover)设置。 当设定,发生错误时,你会看到类似以下内容(在控制台上的文字traceback输出):

> source(<my filename>)
Error in plot.window(...) : need finite 'xlim' values
In addition: Warning messages:
1: In xy.coords(x, y, xlabel, ylabel, log) : NAs introduced by coercion
2: In min(x) : no non-missing arguments to min; returning Inf
3: In max(x) : no non-missing arguments to max; returning -Inf

Enter a frame number, or 0 to exit   

1: source(<my filename>)
2: eval.with.vis(ei, envir)
3: eval.with.vis(expr, envir, enclos)
4: LinearParamSearch(data = dataset, y = data.frame(LGD = dataset$LGD10), data.names = data
5: LinearParamSearch.R#66: plot(x = x, y = y.data, xlab = names(y), ylab = data.names[i])
6: LinearParamSearch.R#66: plot.default(x = x, y = y.data, xlab = names(y), ylab = data.nam
7: LinearParamSearch.R#66: localWindow(xlim, ylim, log, asp, ...)
8: LinearParamSearch.R#66: plot.window(...)

Selection:

此时,你可以选择“边框”进入。 当你做出选择,你会被放置到browser()模式:

Selection: 4
Called from: stop(gettextf("replacement has %d rows, data has %d", N, n), 
    domain = NA)
Browse[1]> 

您可以检查环境,因为它是在错误的时间。 当您完成后,键入c把你带回来的帧选择菜单。 当您完成后,它会告诉你,键入0退出。



Answer 11:

我给了这个答案的一个较新的问题,但我在这里增加它的完整性。

我个人倾向于不使用的功能调试。 我经常发现,因为它解决了这个引起尽可能多的麻烦。 此外,从Matlab的背景我喜欢能够做到这一点的集成开发环境(IDE),而不是在代码中这样来了。 使用一个IDE让你的代码干净和简单。

对于R,我使用所谓的“RStudio”(一个IDE http://www.rstudio.com ),这是适用于Windows,Mac和Linux,并且很容易使用。

距今约2013年10月(?0.98ish)Rstudio的版本必须添加脚本和函数中断点的能力:要做到这一点,只需点击该文件的左边空白处添加断点。 您可以设置一个断点,然后从该点步。 您也可以访问所有在该环境中的数据的,所以你可以尝试的命令。

见http://www.rstudio.com/ide/docs/debugging/overview了解详情。 如果您已经安装了Rstudio,您可能需要升级 - 这是一个相对较新的(2013末期)功能。

你也可能会发现有类似功能的其他的IDE。

诚然,如果它是一个内置的功能,你可能不得不求助于一些由其他人在这个讨论中提出的建议。 但是,如果这是你自己的代码,需要修复,基于IDE的解决方案可能正是您所需要的。



Answer 12:

调试参考类方法没有实例参考

ClassName$trace(methodName, browser)


Answer 13:

我开始觉得不打印错误行号-一个最基本的要求- BY DEFAILT-是某种在R / Rstudio一个笑话。 我发现找到错误发生在那里的唯一可靠的方法就是让calloing 回溯(的额外努力),看看顶线。



文章来源: General suggestions for debugging in R