关于在R中调试的一般建议

关于在R中调试的一般建议,r,debugging,r-faq,R,Debugging,R Faq,使用我编写的R函数时出现错误: Warning messages: 1: glm.fit: algorithm did not converge 2: glm.fit: algorithm did not converge 我所做的: 逐步完成函数 添加print以找出错误发生在哪一行,这表明有两个函数不应使用glm.fit。它们是window()和save() 我的一般方法包括添加print和stop命令,并逐行遍历函数,直到找到异常 但是,我不清楚使用这些技术时代码中的错误来自何处。我

使用我编写的R函数时出现错误:

Warning messages:
1: glm.fit: algorithm did not converge 
2: glm.fit: algorithm did not converge 
我所做的:

  • 逐步完成函数
  • 添加print以找出错误发生在哪一行,这表明有两个函数不应使用
    glm.fit
    。它们是
    window()
    save()
  • 我的一般方法包括添加
    print
    stop
    命令,并逐行遍历函数,直到找到异常


    但是,我不清楚使用这些技术时代码中的错误来自何处。我甚至不确定代码中的哪些函数依赖于
    glm.fit
    。如何诊断此问题?

    到目前为止,我看到的最佳演练是:


    有人同意/不同意吗?

    Mark Bravington的调试器在CRAN上作为包
    debug
    提供,它非常好而且非常简单

    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

    我认为调试是一种艺术形式,因此没有明确的解决办法。在任何语言中都有很好的调试策略,它们在这里也适用(例如)。例如,第一件事是重现问题……如果你不能做到这一点,那么你需要获得更多信息(例如,通过日志记录)。一旦你可以复制它,你需要把它减少到源代码

    我想说的不是“技巧”,而是我最喜欢的调试例程:

  • 当发生错误时,我通常做的第一件事是通过调用
    traceback()
    :查看堆栈跟踪:这将显示错误发生的位置,如果您有多个嵌套函数,这将非常有用
  • 接下来我将设置
    选项(error=recover)
    ;这会立即切换到发生错误的浏览器模式,因此您可以从此处浏览工作空间
  • 如果我仍然没有足够的信息,我通常使用
    debug()
    函数逐行遍历脚本 R2.10中最好的新技巧(在处理脚本文件时)是使用
    findLineNum()
    setBreakpoint()
    函数

    最后一点注释:根据错误,围绕外部函数调用设置
    try()
    tryCatch()
    语句也非常有用(特别是在处理S4类时)。这有时会提供更多的信息,还可以让您更好地控制在运行时如何处理错误

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


    在完成这里建议的所有步骤后,我刚刚了解到在
    foreach()
    中设置
    .verbose=TRUE
    也会给我提供大量有用的信息。特别是
    foreach(.verbose=TRUE)
    精确显示了foreach循环中发生错误的位置,而
    traceback()
    没有查看foreach循环内部。

    因此
    browser()
    traceback()
    debug()
    进入一个栏,但是
    trace()
    在室外等待并保持电机运行

    通过在函数中插入
    浏览器
    ,执行将停止并等待您的输入。您可以使用n(或Enter)向前移动,使用c运行整个区块(迭代),使用f完成当前循环/函数,或者使用Q退出;请参见浏览器

    使用
    debug
    ,可以获得与浏览器相同的效果,但这会在函数开始时停止执行。同样的快捷方式也适用。此函数将处于“调试”模式,直到您使用
    undebug
    将其关闭(即,在
    debug(foo)
    之后,运行函数
    foo
    将每次进入“调试”模式,直到您运行
    undebug(foo)

    一种更为暂时的替代方法是
    debugonce
    ,它将在下次评估函数后从函数中删除“debug”模式

    回溯
    将为您提供函数执行流程,直至出现错误(实际错误)的地方


    您可以使用
    跟踪
    在函数中插入代码位(即自定义函数),例如
    浏览器
    。这对于来自软件包的函数很有用,而且您太懒了,无法获得折叠得很好的源代码。

    我的一般策略如下所示:

  • 运行
    traceback()
    查看是否存在明显的问题
  • 设置
    选项(warn=2)
    将警告视为错误
  • 设置
    选项(error=recover)
    以在出错时进入调用堆栈

  • 在某个时候,调用了
    glm.fit
    。这意味着您调用的函数之一或这些函数调用的函数之一正在使用
    glm
    glm.fit

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

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

     ‘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)
    
    以下是一个例子:

    > 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
    ,然后计算如何将
    控件
    参数usi传递给它
    options(error = NULL, warn = 0)
    
    require(debug)
    mtrace(foo)
    foo(1)
    
    mtrace.off()
    
    > 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:
    
    Selection: 4
    Called from: stop(gettextf("replacement has %d rows, data has %d", N, n), 
        domain = NA)
    Browse[1]> 
    
    ClassName$trace(methodName, browser)