2009-09-08 68 views
28

使用lapply和朋友編寫的代碼通常比眼睛更容易,Rish比循環更多。我喜歡和下一個人一樣喜歡樂福,但是當出現問題時我該如何調試呢?例如:調試lapply/sapply調用

> ## a list composed of numeric elements 
> x <- as.list(-2:2) 
> ## turn one of the elements into characters 
> x[[2]] <- "what?!?" 
> 
> ## using sapply 
> sapply(x, function(x) 1/x) 
Error in 1/x : non-numeric argument to binary operator 

如果我用一個循環:

> y <- rep(NA, length(x)) 
> for (i in 1:length(x)) { 
+  y[i] <- 1/x[[i]] 
+ } 
Error in 1/x[[i]] : non-numeric argument to binary operator 

但我想知道哪裏有錯誤發生:

> i 
[1] 2 

使用lapply/sapply時,我應該怎麼辦?

回答

23

使用標準的R調試技術停止什麼時候發生錯誤:

options(error = browser) 

options(error = recover) 

當完成,恢復到標準行爲:

options(error = NULL) 
22

如果你用包裝一個try()語句你的內在功能,你得到更多的信息:

> sapply(x, function(x) try(1/x)) 
Error in 1/x : non-numeric argument to binary operator 
[1] "-0.5"              
[2] "Error in 1/x : non-numeric argument to binary operator\n" 
[3] "Inf"              
[4] "1"              
[5] "0.5" 

在這種情況下,你可以看到哪些指標會失敗。

0

您可以調試()該函數,或者將瀏覽器()放入主體中。如果你沒有gajillion迭代來處理,這只是特別有用。另外,我還沒有親自做過這件事,但我懷疑你可以把瀏覽器()作爲tryCatch()的一部分,這樣當錯誤生成時,你可以使用browser()接口。

8

使用plyr封裝,具有.inform = TRUE

library(plyr) 
laply(x, function(x) 1/x, .inform = TRUE) 
0

我遇到了同樣的問題,並傾向於使(l)(m)(s)(t)的調用適用於我可以調試的函數()。

因此,而不是胡說< -sapply(X,函數(X){X + 1})

我會說,

myfn<-function(x){x+1} 
blah<-sapply(x,function(x){myfn(x)}) 

,並使用與調試選項(myfn)(錯誤恢復=)。

我也喜歡關於堅持print()行在這裏和那裏看看發生了什麼的建議。

更好的是設計一個myfn(x)的測試,它必須通過並確保它在通過測試之前通過了測試。我只有一半的時間耐心。

+0

或者只是'blah <-sapply(x,mfn)'。而且你不應該同時需要'debug'和recover' – hadley

1

像geoffjentry說:

> sapply(x, function(x) { 
    res <- tryCatch(1/x, 
        error=function(e) { 
          cat("Failed on x = ", x, "\n", sep="") ## browser() 
          stop(e) 
         }) 
}) 

此外,您的for循環可以改寫成更清潔(可能慢一點):

> y <- NULL 
> for (xi in x) 
    y <- c(y, 1/xi) 

Error in 1/xi : non-numeric argument to binary operator 

for循環緩慢,R,但除非你真的需要用一個簡單的迭代方法來處理令人困惑的列表理解的速度。

如果我需要找出在運行一些代碼,我會經常去:

sapply(x, function(x) { 
    browser() 
    ... 
}) 

和寫入函數內部的代碼,所以我看到什麼我得到。

- 丹

+3

for循環的錯誤調用。這會讓事情變得更慢。 – hadley

+1

@hadley ...因爲整個數組需要在每個循環步驟中重新分配(保留內存,複製舊數據)。'y < - numeric(length(x))'應該是預分配的最快方式。 – AlexR

1

使用調試或瀏覽器是不是在這種情況下,一個好主意,因爲它會如此頻繁地停止你的代碼。改用Try或TryCatch,並在出現問題時處理。