2009-09-08 6 views
28

Code geschrieben mit lapply und Freunden ist in der Regel einfacher auf die Augen und mehr Rish als Schleifen. Ich liebe genauso viel wie der nächste Typ, aber wie kann ich es debuggen, wenn etwas schief läuft? Zum Beispiel:Debugging lapply/sapply Anrufe

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

habe ich eine for-Schleife:

> 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 

Aber ich würde wissen, wo der Fehler aufgetreten ist:

> i 
[1] 2 

Was soll ich tun, wenn lapply mit/sapply?

Antwort

23

mit Hilfe der Standardtechniken R Debuggen genau zu stoppen, wenn der Fehler auftritt:

options(error = browser) 

oder

options(error = recover) 

Wenn getan , zum Standardverhalten zurückkehren:

22

Wenn Sie Ihre innere Funktion mit einem try() Anweisung wickeln, erhalten Sie weitere Informationen:

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

In diesem Fall können Sie sehen, welcher Index fehlschlägt.

0

Sie können die Funktion debuggen() oder einen Browser() in den Körper einfügen. Dies ist nur dann besonders nützlich, wenn Sie keine gaaillion Iterationen zum Durcharbeiten haben.

Auch ich habe das nicht persönlich gemacht, aber ich vermute, dass Sie einen Browser() als Teil eines tryCatch() einfügen könnten, so dass bei der Generierung des Fehlers die Browser() -Schnittstelle verwendet werden kann.

8

Verwenden Sie das plyr Paket mit .inform = TRUE:

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

Ich habe das gleiche Problem konfrontiert und neigte dazu, meine Aufrufe mit (l) (m) (s) (t) zu machen, um Funktionen zu sein, die ich debuggen kann().

Also, statt blah < -sapply (x, Funktion (x) {x + 1})

würde ich sagen,

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

und verwenden debug (myfn) mit Optionen (Fehler = Wiederherstellen).

Ich mag auch den Rat über das Anheften von print() Zeilen hier und da, um zu sehen, was passiert.

Noch besser ist es, einen Test von myfn (x) zu entwerfen, den es passieren muss, und sicher zu sein, dass es den Test besteht, bevor es sapply unterzogen wird. Ich habe nur ungefähr die Hälfte der Zeit Geduld.

+0

Oder nur 'blah <-sapply (x, mfn)'. Und Sie sollten nicht beide "Debug" und "Wiederherstellen" – hadley

1

Wie geoffjentry sagte:

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

Auch könnte Ihre for-Schleife viel sauberer sein neu geschrieben werden (möglicherweise etwas langsamer):

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

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

Für Schleifen langsam in R, aber es sei denn, Sie brauchen wirklich die Geschwindigkeit, die ich mit einem einfachen iterativen Ansatz über ein verwirrendes Listenverständnis gehen würde.

Wenn ich einige Code on the fly brauchen, um herauszufinden, werde ich immer gehen:

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

Und schreiben Sie den Code aus dem Inneren der Funktion, so sehe ich, was ich bekomme.

- Dan

+3

Bad Call auf der for-Schleife benötigen. Das wird die Dinge ** viel langsamer machen. – hadley

+1

@hadley ... weil das gesamte Array neu zugewiesen werden muss (Speicher reservieren, alte Daten kopieren) in jedem einzelnen Schleifenschritt :) 'y <- numerisch (Länge (x))' sollte der schnellste Weg zur Vorabzuweisung sein. – AlexR

1

mit debug oder Browser ist keine gute Idee, in diesem Fall, da es Ihren Code so oft zu stoppen. Verwenden Sie stattdessen Try oder TryCatch, und behandeln Sie die Situation, wenn sie auftritt.