デバッグ

R のスクリプトを実行する時にエラーが起きた時、その原因を調べたい場合は browserdebugtracetraceback などのデバッグ関数を利用する。

browser browser が書かれている行で、プログラムの実行が一時停止される。この行にまでに出現した変数の中身を確認したりすることができる。
debug 関数名を与えて、その関数の処理を追跡する。
traceback 直前に発生した関数のエラーをトレースバックし、エラーが発生した源を表示する。
trace 関数に任意の位置にブレークポイントを挿入しデバッグを行うことができる。

browser

コードの中に browser 関数を書き入れることで、それが実行されたときに、browser が書かれている行で実行が一時停止される。この時、変数の内容を確認したり、様々なテスト演算を行ったりすることができる。

func <- function(x) {
  x <- x + 2
  y <- x * x
  z <- NULL
  browser()          # ここで一時停止
  a <- x + y
  b <- x - y 
  c <- a + b
  return(c)
}

func 関数を実行すると、browser の行で実行が一時停止される。一時停止された状態で、n を入力することで 1 行後に進むことができる。

func(10)
#'
#' Called from: func(10)
#'
#'Browse[1]> ls()          # 現在で使える変数
#'[1] "x" "y" "z"
#'
#'Browse[1]> x             # xの内容を確認
#'[1] 12
#'
#'Browse[1]> x + y         # 途中状態で計算
#'[1] 156
#'
#'Browse[1]> n             # 次の行を確認(実行されない)
#'debug at #6: a <- x + y
#'
#'Browse[2]> a             # まだ実行されませんので、aには何も入っていない
#'Error: object 'a' not found
#'
#'Browse[2]> n             # 次の行を確認(6行目は実行されて、7行目は実行待機状態)
#'debug at #7: b <- x - y
#'
#'Browse[2]> a             # 6行目が実行されたので、aに値が入った
#'[1] 156
#'
#'Browse[2]> Q             # デバッグを終了
#'

browser 関数を 2 箇所以上埋めた場合、一時停止の状態で c を入力すると、現在の browser の行から次の browser の行にスキップすることができる。

また、条件付きで browser を設定することもできる。例えば、変数 y が 10 以上のときに限り一時停止する場合は以下のようにする。

func <- function(x) {
  x <- x + 2
  y <- x * x
  z <- NULL
  browser(expr = y >= 10)          # ここで一時停止
  a <- x + y
  b <- x - y 
  c <- a + b
  return(c)
}

debug

関数のデバッグを行いたい場合に debug 関数を利用する。debug 関数にデバッグを行いたい関数名を引数として与える。また、デバッグ状態にある関数を解除したい場合は undebug 関数を利用する。

func <- function(x) {
  x <- x + 2
  y <- x * x
  z <- NULL
  a <- x + y
  b <- x - y 
  c <- a + b
  return(c)
}

debug 関数に関数名を代入し、デバッグ状態にする。次にその関数を実行することでデバッグが開始される。

debug(func)               # funcを利用したらデバッグを開始

func(10)
#'debug at #1: {
#'    x <- x + 2
#'    y <- x * x
#'    z <- NULL
#'    a <- x + y
#'    b <- x - y
#'    c <- a + b
#'    return(c)
#'}
#'Browse[2]> ls()         # 一行目が実行する前の状態、変数はxしかない
#'[1] "x"
#'
#'Browse[2]> x            # xの中身を確認
#'[1] 10
#'
#'Browse[2]> n            # 1行進む(だたし実行されない)
#'debug at #2: x <- x + 2
#'
#'Browse[2]> Q            # デバッグを終了

undebug(func)             # デバッグ状態を解除

traceback

R の実行中にエラーが発生した時、traceback 関数によりエラーの源を追跡することができる。

plot(NA, 1)
## Error in plot.window(...) : need finite 'xlim' values
## In addition: Warning messages:
## 1: In min(x) : no non-missing arguments to min; returning Inf
## 2: In max(x) : no non-missing arguments to max; returning -Inf


traceback()
## 4: plot.window(...)
## 3: localWindow(xlim, ylim, log, asp, ...)
## 2: plot.default(NA, 1)
## 1: plot(NA, 1)

エラーの源は plot.window 関数であることがわかったので、更に詳しく調べたい場合は、debug 関数を用いて plot.window 関数を 1 行ずつデバッグしていく。

debug(plot.window)

plot(NA, 1)
#'debugging in: plot.window(...)
#'debug: .Internal(plot.window(xlim, ylim, log, asp, ...))
#'Browse[2]>

trace

trace 関数を利用して、デバッグを行いたい関数の任意の位置にブレークポイントを仕掛けることができる。次は、func 関数の 3 行目にブレークポイント(browser 関数)を挿入する例である。

func <- function(x) {
  x <- x + 1         
  y <- x + 1         
  z <- y + 1         
  w <- z + 1         
}


# fun関数の3行目にデバッグ関数(browser)を仕掛る
# browserの挿入により、funcの3行目は4行目になる(以降、すべての行が1行ずつずれる)
trace(func, tracer=browser, at=3)

# func関数を呼び出す
func(0)
#' Tracing fun(0) step 3 
#' Called from: eval(expr, envir, enclos)
#' Browse[1]> x                    # 2行目の実行が完了しているためxが変わる
#' [1] 1
#' Browse[1]> y                    # fun本来の3行目はbrowserの挿入により、4行目へずれ込み、従ってyはまだ生成されていない
#' Error: object 'y' not found
#' Browse[1]> n                    # 次の行(4行目)に進む(まだ実行されない)
#' debug: y <- x + 1
#' Browse[2]> y
#' Error: object 'y' not found
#' Browse[2]> n                    # 次の行(5行目)に進む(4行目は実行され、5行目は実行待ち)
#' debug at #4: z <- y + 1
#' Browse[2]> y                    # 4行目に書かれているyが生成されている
#' [1] 2
#' Browse[2]> z                    # zはまだ生成されていない
#' Error: object 'z' not found
#' Browse[2]> Q                    # 終了

その他

Warning message はデフォルトでは間違いとみなさないために traceback を適用できない。そこで、options 関数により、Warning message を Error に変更させてから、デバッグする。

options(warn = 2)