R에서 디버깅을위한 일반적인 제안


120

내가 작성한 R 함수를 사용할 때 오류가 발생합니다.

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

내가 뭘 한거지:

  1. 기능 살펴보기
  2. 어떤 줄에서 오류가 발생하는지 확인하기 위해 print를 추가하면 glm.fit. 그들은 window()save()입니다.

내 일반적인 접근 방식에는 추가 printstop명령, 예외를 찾을 수있을 때까지 기능을 한 줄씩 단계별로 실행하는 것이 포함됩니다.

그러나이 오류가 코드에서 발생하는 기술을 사용하는 것은 분명하지 않습니다. 코드 내에서 어떤 기능이에 의존하는지조차 확실하지 않습니다 glm.fit. 이 문제를 진단하려면 어떻게해야합니까?


5
던컨 머독의 페이지 확인 R에서 디버깅
롭 Hyndman에게

10
좋아, 나는 명백한 상태 것이다 : 그건입니다 경고 가 아닌 오류 .
Gavin Simpson

10
@ gavin-simpson 기술적 인 차이가 있다는 것을 깨닫지 못했습니다. 지적 해 주셔서 감사합니다. 그러나 결국 그것은 나의 이전 기능 기능이 역기능임을 나타냅니다.
David LeBauer 2010

11
@David +1 for "... 이전 기능이 제대로 작동하지 않습니다."
Joshua Ulrich

5
@David : 당신의 추신. 이것은 예제없이 놓쳤을 질문에 차원을 추가합니다. 즉, 경고 만 생성 될 때 R을 디버깅 모드로 전환하는 방법은 무엇입니까? 이 세부 사항을 생략했다면 우리 모두가 당신을 지적하지 않았을 것 options(warn = 2)입니다. 따라서이 경우 일반적인 질문에 대답하려면 세부 정보가 필수적입니다. 나에게서 +1.
Gavin Simpson

답변:


167

디버깅은 예술 형식이므로 명확한 은색 총알이 없습니다. 모든 언어로 디버깅 할 수있는 좋은 전략이 있으며 여기에서도 적용됩니다 (예 : 이 멋진 기사 읽기 ). 예를 들어, 첫 번째 일은 문제재현하는 것입니다 ... 그렇게 할 수 없다면 더 많은 정보를 얻어야합니다 (예 : 로깅). 재현 할 수 있으면 소스 로 줄여야 합니다.

"속임수"라기보다는 내가 좋아하는 디버깅 루틴이 있다고 말하고 싶습니다.

  1. 오류가 발생하면 일반적으로 가장 먼저 수행하는 작업은 다음을 호출하여 스택 추적을 보는 traceback()것입니다. 이는 오류가 발생한 위치를 보여줍니다. 여러 중첩 함수가있는 경우 특히 유용합니다.
  2. 다음으로 설정하겠습니다 options(error=recover). 이렇게하면 오류가 발생한 브라우저 모드로 즉시 전환되므로 거기에서 작업 공간을 탐색 할 수 있습니다.
  3. 그래도 정보가 충분하지 않으면 일반적으로 debug()함수를 사용 하고 스크립트를 한 줄씩 단계별로 실행합니다.

R 2.10의 가장 새로운 트릭 (스크립트 파일 작업시)은 findLineNum()setBreakpoint()함수 를 사용하는 것입니다.

마지막으로, 오류에 따라 외부 함수 호출 (특히 S4 클래스를 다룰 때)에 대한 설정 try()또는 tryCatch()명령문이 매우 유용합니다 . 이는 때로 더 많은 정보를 제공하고 런타임에 오류를 처리하는 방법을 더 잘 제어 할 수 있도록합니다.

이러한 관련 질문에는 많은 제안이 있습니다.


8
debug ()에도 debugonce ()를 추가 할 수 있습니다.
Joris Meys

2
디버깅 할 때만 유용 할뿐만 아니라 fix (df1)는 데이터 프레임 df1이로드 된 그래픽 R 편집기를 엽니 다. 즉석에서 편집하거나 한 눈에 볼 수 있습니다.
Dmitrii I.

R에서의 디버깅은 매우 어려운 것 같습니다. 예를 들어 경고 코드 라인을 볼 수있는 쉬운 솔루션이 없습니다
TMS

browser()경고 / 오류를 유발하지 않는 오류가있는 경우 (출처 :이 페이지의 Roman Luštrik). 같은 다른 도구 browser()?
PatrickT


32

으로는 나에게 지적 된 또 다른 질문 , Rprof()그리고 summaryRprof()수있는 좋은 도구 프로그램의 느린 부분을 찾을 수는 그 속도를 향상 또는 C / C ++ 구현에 이동에서 힘 혜택은. 이는 시뮬레이션 작업이나 기타 컴퓨팅 또는 데이터 집약적 인 활동을 수행하는 경우 더 많이 적용될 수 있습니다. profr패키지 는 결과를 시각화하는 데 도움 이 될 수 있습니다.

나는 디버깅에 대해 약간 배우고 있으므로 다른 스레드의 또 다른 제안 :

  • options(warn=2)경고를 오류처럼 처리하도록 설정

또한 options선호하는 디버깅 기능을 사용하여 오류 또는 경고가 발생할 때 행동의 열기에 바로 빠져들 수 있습니다. 예를 들면 :

  • Shane이 언급 한대로 오류가 발생 options(error=recover)하면 실행되도록 설정 합니다 recover()(그리고 R 디버깅 가이드에 설명되어 있습니다. 또는 실행하면 유용하다고 생각되는 기타 편리한 기능).

@Shane의 링크 중 하나에서 또 다른 두 가지 방법 :

  • 내부 함수 호출을 try()로 래핑하여 더 많은 정보를 반환합니다.
  • * apply 기능의 경우 .inform=TRUE(plyr 패키지에서) apply 명령에 대한 옵션으로 사용하십시오.

@JoshuaUlrich 는 또한 클래식 browser()명령 의 조건부 기능을 사용하여 디버깅을 켜거나 끄는 깔끔한 방법을 지적했습니다 .

  • 디버그하려는 함수 안에 넣으십시오. browser(expr=isTRUE(getOption("myDebug")))
  • 다음으로 글로벌 옵션을 설정하십시오. options(myDebug=TRUE)
  • 브라우저 호출을 래핑 myBrowse <- browser(expr=isTRUE(getOption("myDebug")))한 다음 myBrowse()전역을 사용하므로 with를 호출 할 수도 있습니다.

그런 다음 R 2.10에서 사용할 수있는 새로운 기능이 있습니다.

  • findLineNum()소스 파일 이름과 줄 번호를 받아 함수와 환경을 반환합니다. 이것은 source().R 파일이고 #n 줄에 오류를 반환 할 때 도움이되는 것 같지만 , #n 줄에 어떤 함수가 있는지 알아야합니다.
  • setBreakpoint() 소스 파일 이름과 줄 번호를 가져와 거기에 중단 점을 설정합니다.

codetools의 패키지, 특히 그 checkUsage기능은 빠르게 구문과 컴파일러는 일반적으로보고 할 것이라고 문체 오류 따기에 (사용되지 않는 지역 주민, 글로벌 함수와 변수, 부분 인수 매칭을 정의되지 않은, 등)에 특히 도움이 될 수 있습니다.

setBreakpoint()는보다 사용자 친화적 인 trace(). 이것이 작동하는 방식의 내부에 대한 자세한 내용은 최근 R Journal 기사 에서 확인할 수 있습니다 .

다른 사람의 패키지를 디버깅하려는 경우 문제를 찾으면 해당 함수fixInNamespace및로 덮어 쓸 수assignInNamespace 있지만 프로덕션 코드에서는 사용하지 마십시오.

이 중 일부는 위에 있고 일부는 그렇지 않은 검증 된 표준 R 디버깅 도구를 배제해서는 안됩니다. 특히, 사후 디버깅 도구 는 시간이 많이 걸리는 코드를 다시 실행하지 않으려는 경우에 유용합니다.

마지막으로 오류 메시지를 표시하지 않는 것처럼 보이는 까다로운 문제의 경우 options(error=dump.frames)다음 질문에 자세히 설명 된대로 사용할 수 있습니다 . 오류가 발생하지 않는 오류


1
이 질문을 하나로 통합 한 다음 열어두기 위해 수행 한 모든 작업에 대해 +1하십시오!
GSee jul.

29

어느 시점에서 glm.fit호출되고 있습니다. 즉, 호출하는 함수 중 하나 또는 해당 함수에서 호출하는 함수 중 하나가 glm, glm.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호출 bar되고 bar경고 가 생성 된 것을 볼 수 있습니다. 어떤 함수를 호출했는지 보여줄 것입니다 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.


4
좋은 대답입니다. 비관적 인 한 가지 주목할 점은 이러한 종류의 수렴 오류는 불안정하거나 이상한 데이터 세트 (완전 분리 등)에서 자주 발생하며 '잘 수렴'과 '수렴하지 않음'사이의 창은 숫자를 늘려서 수정할 수 없다는 것입니다. 반복 횟수-좀 더 과감한 변경이 필요함 '은 종종 좁습니다
Ben Bolker dec

3
개빈, 너를 25 초로 이겼다. 지나치게 도움이되는 답변을 삭제하고 내 업보를 훔치는 것을 중지 할 것을 요구합니다. ;-)
Joshua Ulrich

@ 벤 좋은 지적. David의 문제가 분리 인 경우 반복 횟수를 늘려도 도움이되지 않지만 여전히 수렴에 실패합니다. 그 시점에서 추정치와 표준 오류를 보면 문제가 있음을 알 수 있습니다. 또한 분리 등이 문제가되는 경우 적합치에 대한 경고가 숫자 0 또는 1로 표시 될 것으로 예상합니다. 반복 횟수를 늘려도 도움이되지 않는 경우 David는 도움을 받기 위해 다른 Q를 게시 할 수 있으며 @Joshua의 upvotes를 더 훔칠 수 있습니다. ;-)
Gavin Simpson

1
@Joshua, 그를 이길 방법이 없습니다. 나는 그 때문에 잃어버린 찬성 투표 수를 세지 않았습니다. 그러나 어쨌든 그가 제공하는 도움은 그에 대한 설명입니다. 당신이 그를 이겼다면 자신의 틈새 시장을 찾아야합니다. 여기에서 키 입력 당 upvotes를 제안합니다 ... :)
Matt Bannert 2010

1
@ ran2 젠장, 당신은 세상 을 장악하려는 내 비열하고 사악한 계획을 좌절 시켰습니다, Mwahahahahaha !!!!
Gavin Simpson

21

그래서 browser(), traceback()그리고 debug()술집으로 걸어 있지만, trace()대기 외부 모터 실행을 유지합니다.

browser함수 어딘가에 삽입 하면 실행이 중지되고 입력을 기다립니다. 를 사용하여 n(또는 Enter) 앞으로 이동 하거나를 사용 하여 전체 청크 (반복)를 실행 c하거나을 사용하여 현재 루프 / 함수를 완료 f하거나으로 종료 할 수 있습니다 Q. 참조하십시오 ?browser.

를 사용하면 debug브라우저와 동일한 효과를 얻을 수 있지만 처음에 함수 실행이 중지됩니다. 동일한 단축키가 적용됩니다. 이 함수는를 사용하여 끌 때까지 "디버그"모드에 있습니다 undebug(즉, 이후 debug(foo)에 함수 foo를 실행하면 실행할 때까지 매번 "디버그"모드로 들어갑니다 undebug(foo)).

좀 더 일시적인 대안은 debugonce다음 번에 평가 될 때 함수에서 "디버그"모드를 제거합니다.

traceback 문제가 발생한 곳 (실제 오류)까지 함수 실행 흐름을 제공합니다.

trace예를 들어를 사용하여 함수에 코드 비트 (예 : 사용자 정의 함수)를 삽입 할 수 있습니다 browser. 이것은 패키지의 함수에 유용하며 멋지게 접힌 소스 코드를 얻기에는 너무 게으르다.


18

내 일반적인 전략은 다음과 같습니다.

  1. traceback()명백한 문제를 찾기 위해 실행
  2. options(warn=2)경고를 오류처럼 처리하도록 설정
  3. options(error=recover)오류 발생시 호출 스택에 들어가도록 설정

15

여기에 제안 된 모든 단계를 수행 한 후, 설정 하면 유용한 정보 .verbose = TRUEforeach()많이 제공 된다는 사실을 방금 알게 되었습니다 . 특히 foreach(.verbose=TRUE)foreach 루프 내부에서 오류가 발생하는 위치를 정확히 보여 주지만 foreach 루프 내부를 traceback()보지 않습니다.


13

debugCRAN 에서 패키지로 사용할 수있는 Mark Bravington의 디버거 는 매우 훌륭하고 매우 간단합니다.

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


11

나는 Gavin의 대답을 좋아한다 : 나는 옵션 (오류 = 복구)에 대해 몰랐다. 또한 코드를 단계별로 시각적으로 보여주는 '디버그'패키지를 사용하고 싶습니다.

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

이 시점에서 함수를 보여주는 별도의 디버그 창이 열리고 코드에서 현재 위치를 나타내는 노란색 선이 표시됩니다. 기본 창에서 코드는 디버그 모드로 전환되고 Enter 키를 계속 눌러 코드를 단계별로 실행하고 (다른 명령도 있음) 변수 값 등을 검사 할 수 있습니다. 디버그 창의 노란색 선이 계속 움직여서 어디에 있는지 표시합니다. 당신은 코드에 있습니다. 디버깅이 완료되면 다음을 사용하여 추적을 끌 수 있습니다.

mtrace.off()

5

여기 에서 받은 답변을 바탕으로 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하여 종료하십시오.


4

나는 더 최근의 질문 에이 답변을 었지만 완전성을 위해 여기에 추가하고 있습니다.

개인적으로 나는 디버깅을 위해 함수를 사용하지 않는 경향이 있습니다. 나는 이것이 해결하는 것만 큼 많은 문제를 일으키는 것을 종종 발견합니다. 또한 Matlab 배경에서 왔기 때문에 코드에서이 작업을 수행하는 것보다 IDE (통합 개발 환경)에서이 작업을 수행하는 것이 좋습니다. IDE를 사용하면 코드를 깨끗하고 간단하게 유지할 수 있습니다.

R의 경우 "RStudio"( http://www.rstudio.com ) 라는 IDE를 사용합니다.이 IDE는 Windows, Mac 및 Linux에서 사용할 수 있으며 사용하기 매우 쉽습니다.

2013 년 10 월경 (0.98ish?) 이후 Rstudio 버전에는 스크립트와 함수에 중단 점을 추가하는 기능이 있습니다. 이렇게하려면 파일의 왼쪽 여백을 클릭하여 중단 점을 추가하면됩니다. 중단 점을 설정 한 다음 해당 지점부터 단계별로 진행할 수 있습니다. 또한 해당 환경의 모든 데이터에 액세스 할 수 있으므로 명령을 시도해 볼 수 있습니다.

자세한 내용은 http://www.rstudio.com/ide/docs/debugging/overview 를 참조하십시오. 이미 Rstudio가 설치되어 있다면 업그레이드가 필요할 수 있습니다. 이것은 비교적 새로운 (2013 년 후반) 기능입니다.

유사한 기능을 가진 다른 IDE를 찾을 수도 있습니다.

물론 그것이 내장 함수라면이 토론에서 다른 사람들이 제안한 몇 가지 제안에 의존해야 할 수도 있습니다. 그러나 수정이 필요한 자체 코드 인 경우 IDE 기반 솔루션이 필요할 수 있습니다.


1

인스턴스 참조없이 참조 클래스 메서드 를 디버깅하려면

ClassName$trace(methodName, browser)

0

가장 기본적인 요구 사항 인 BY DEFAILT- 오류 줄 번호를 인쇄하지 않는 것은 R / Rstudio 에서 일종의 농담이라고 생각하기 시작했습니다 . 오류가 발생한 위치를 찾는 유일한 신뢰할 수있는 방법은 traceback ()을 추가로 호출 하고 맨 위 줄을 보는 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.