Déboguer les appels lapply/sapply

Code écrit en utilisant lapply et les amis est généralement plus facile sur les yeux et plus Rish que les boucles. J'aime lapply autant que les autres, mais comment puis-je le réfuter quand les choses vont mal? Par exemple:

> ## 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

si j'Avais utilisé une boucle for:

> 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

mais je saurais où l'erreur s'est produite:

> i
[1] 2

Que dois-je faire en utilisant lapply/sapply?

28
r
demandé sur Eduardo Leoni 2009-09-08 22:42:36

7 réponses

utiliser les techniques de débogage standard R pour arrêter exactement quand l'erreur se produit:

options(error = browser) 

ou

options(error = recover)

une fois fait, revenir au comportement standard:

options(error = NULL)
23
répondu 2009-09-09 20:40:00

si vous enveloppez votre fonction interne d'une instruction try (), vous obtenez plus d'informations:

> 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"

dans ce cas, vous pouvez voir quel indice échoue.

22
répondu Shane 2009-09-08 18:59:00

utiliser le paquet plyr, avec .inform = TRUE :

library(plyr)
laply(x, function(x) 1/x, .inform = TRUE)
8
répondu hadley 2009-09-08 23:48:10

comme disait geoffjentry:

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

aussi, votre boucle for pourrait être réécrite pour être beaucoup plus propre (peut-être un peu plus lent):

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

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

pour les boucles sont lents en R, mais à moins que vous ayez vraiment besoin de la vitesse, je dirais une approche itérative simple sur une compréhension de liste confuse.

si j'ai besoin de trouver un code à la volée, j'irai toujours:

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

et écrire le code de l'intérieur de la fonction donc je vois ce que je reçois.

-- Dan

1
répondu ephpostfacto 2009-09-09 21:05:40

utiliser le débogueur ou le navigateur n'est pas une bonne idée dans ce cas, parce qu'il arrêtera votre code si souvent. Utilisez Try ou TryCatch à la place, et faites face à la situation quand elle se présente.

1
répondu griffin 2009-09-10 05:49:11

vous pouvez déboguer() la fonction, ou mettre un navigateur() à l'intérieur du corps. Cela n'est particulièrement utile que si vous n'avez pas un milliard d'itérations à traverser.

aussi, je ne l'ai pas fait personnellement, mais je soupçonne que vous pourriez mettre un navigateur() dans le cadre d'un tryCatch(), de sorte que lorsque l'erreur est générée, vous pouvez utiliser l'interface browser ().

0
répondu geoffjentry 2009-09-08 20:53:15

j'ai fait face au même problème et j'ai eu tendance à faire mes appels avec (l)(m)(s)(t)s'appliquent à être des fonctions que je peux débugger().

donc, au lieu de blah< - sapply(x,fonction (x){ x+1 })

je dirais,

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

et utiliser debug(myfn) avec options(error=recover).

j'aime aussi le Conseil de coller des lignes d'impression() ici et là pour voir ce qui se passe.

encore mieux est de concevoir un test de myfn (x) qu'il doit passer et d'être sûr qu'il passe ledit test avant de le soumettre à sapply. Je n'ai de la patience que la moitié du temps.

0
répondu Jake 2009-09-09 21:02:10