R: tryCatch 簡單範例

R 軟體用於實務分析時,經常需要搭配定期自動執行軟體,以 Batch mode 方式在背景執行,但若 R 程式中某些地方發生錯誤,整個 R 程式往往就會停在出錯的地方,對於大型應用程式而言會造成很多困擾。此時,R 軟體的 tryCatch 函數可以協助偵測並解決 R 程式遇到錯誤時被強迫終止的問題,可讓出錯程式碼下方其他的程式繼續執行。

網路上關於 tryCatch 函數的例子通常都寫得很囉唆、語焉不詳,所以我在這裡提供幾個簡單的應用範例。


假設我們有一個 R 程式檔: d:/try1.R , 內容如下:

x = "-1"
sqrt(x)
y = x
y

在 R 軟體 GUI 中執行該程式檔:

> source("d:/try1.R",echo=TRUE)
> x = "-1"
> sqrt(x)
Error in sqrt(x) : non-numeric argument to mathematical function

我們可以看到,程式執行到第 2 行時,就因為發生錯誤而停止,以致於底下的 y = x 與 y 都沒有被執行.

如果我們把 try1.R 中的 x = “-1” 改成 x = -1 ,再用 source 函數執行一次,則 output 會是這樣:

> x = -1
> sqrt(x)
[1] NaN
> y = x
> y
[1] -1
Warning message:
In sqrt(x) : 產生了 NaNs

這時候只會產生 Warning(警告), 所以程式沒有中斷,y = x 與 y 都有被執行。

接下來的 try2.R , 就是採用 tryCatch 函數同時處理 warning 與 error 的狀況:

tryCatch({
           x = "-1"
           z = sqrt(x)
         },
         # 遇到 warning 時的自訂處理函數
         warning = function(msg) {
              message("Original warning message:")
              message(paste0(msg,"\n"))
              return(NULL)
         },
         # 遇到 error 時的自訂處理函數
         error = function(msg) {
              message("Original error message:")
              message(paste0(msg,"\n"))
              return(NA)
         }

ifelse(exists("z"),z,"z does not exist!")
y = x
y

在 R 軟體 GUI 中執行該程式檔:
> source("d:/try2.R",echo=TRUE)

可以得到以下 output:

Original error message:
Error in sqrt(x): non-numeric argument to mathematical function

[1] NA

> ifelse(exists("z"),z,"z does not exist!")
[1] "z does not exist!"
> y = x
> y
[1] "-1"

我們可以看到,雖然發生錯誤,但 R 程式還是繼續執行,並沒有因此而中斷。

如果我們把 try2.R 中的 x = “-1” 改成 x = -1, 再用 source 執行一次,這次只有 warning 狀況:

Original warning message:
simpleWarning in sqrt(x): 產生了 NaNs
NULL
> ifelse(exists("z"),z,"z does not exist!")
[1] "z does not exist!"
> y = x
> y
[1] -1

最後,若我們把 try2.R 中的 x = -1 再改成 x = 4, 用 source 執行,就是正常未出錯的狀況:

> ifelse(exists("z"),z,"z does not exist!")
[1] 2 # z 變數的值
> y = x
> y
[1] 4

接下來我們再來看第三個例子 try3.R :

x = "-1"
z = tryCatch({
               sqrt(x)
             },
             warning = function(msg) {
                  message("Original warning message:")
                  message(paste0(msg,"\n"))
                  return(NULL)
             },
             error = function(msg) {
                  message("Original error message:")
                  message(paste0(msg,"\n"))
                  return(NA)
             }
)
cat("z = ",z,"\n")
y = x
y

用 source 執行 try3.R 的 output :

Original error message:
Error in sqrt(x): non-numeric argument to mathematical function

> cat("z = ",z,"\n")
z = NA
> y = x
> y
[1] "-1"

再把 try3.R 中的 x = “-1” 改成 x = -1, output 如下:

Original warning message:
simpleWarning in sqrt(x): 產生了 NaNs
> cat("z = ",z,"\n")
z =
> y = x
> y
[1] -1
> is.null(z) # 額外輸入指令檢查 z 變數內容
[1] TRUE