Fehlerbehandlung in R – Debugging mit RStudio Teil 2

Markus Berroth Blog, Data Science, Statistik

Nachdem der erste Teil die unterschiedlichen Aktivierungsmöglichkeiten für den Debugger behandelt hat, dreht sich der zweite Teil um effizientes Debugging.

„Debugging is like being the detective in a crime movie where you are also the murderer.”(1)

… und manchmal erinnert man sich nicht mal die Tat begangen zu haben.

Im Folgenden werden wir die Debugging-Features von RStudio an einem einfachen Beispiel behandeln. Die folgenden Funktionen sollen die Buchstaben der einzelnen Wörter umdrehen, aber nicht den kompletten Satz.

# drehe ein Wort um
stringrev <- function(str) {
  vec <- strsplit(str, "")
  vec <- rev(unlist(vec))
  paste(vec, collapse = "")
}

# trenne einen Satz in einzelne Woerter
crazify <- function(str) {
  vec <- strsplit(str, " ")
  vec <- lapply(unlist(vec), stringrev)
  paste(vec, collapse = " ")
}

Für einzelne Sätze funktioniert der Code problemlos. Darauf aufbauend möchten wir die Funktion auf einen Abschnitt eines anderen Blogbeitrags anwenden, welcher in einem Data Frame gespeichert wurde.

test_it <- function() {
  sentences <- data.frame(
  titles = c("first", "second"),
  text = c("Bokaj, der beste Ingenieur im nicht-parametrischen
            Universum und glücklicherweise Leiter unseres
            Maschinenraums, hat eine Idee!",
           "Wir demontieren von einem der anderen Schiffe den
            Antrieb und verstärken damit unseren."))
  sentences$text <- vapply(sentences$text, crazify, "character")
  return(sentences)
}

Doch hierbei taucht diese Fehlermeldung auf:
Error in strsplit(str, " ") : non-character argument
Um dieser Fehlermeldung auf den Grund zu gehen aktivieren wir die Option „Debugging on Error“, wie im vorherigen Blog-Post erklärt.

Zuallererst fällt einem auf, dass sich das Aussehen von RStudio verändert, sobald man sich im Debugging-Modus befindet.

Environment-Pane

Debug Environment Pane

Normalerweise werden im Environment-Pane die globalen Objekte angezeigt. Befindet man sich jedoch im Debugging-Modus, werden stattdessen die Objekte im Environment der jeweiligen Funktion angezeigt. Über der Auflistung der Objekte befindet sich ein Dropdown-Menü, welches die Möglichkeit bietet zwischen den unterschiedlichen Environments zu wechseln. Sind Variablen ausgegraut, bedeutet dies, dass es sich um Objekte handelt, die momentan noch nicht im Environment sind, jedoch zukünftig der Funktion zur Verfügung stehen werden.

Traceback

Debug Traceback

Im Traceback befinden sich alle aufgerufenen Funktionen, um zur aktuellen, fehlerverursachenden Funktion zu gelangen. Über dieses Fenster kann ebenfalls zwischen den vorherigen Funktionsaufrufen gewechselt werden, dadurch wechselt ebenfalls der angezeigte Code und die im Environment angezeigten Objekte. Es ist jedoch zu beachten, dass dies nicht das aktuelle Environment verändert. Unten in der Liste befindet sich die erste aufgerufene Funktion, welche in unserem Fall test_it() ist, und geht weiter bis zu crazify(), welche die R-Funktion strsplit() aufruft.

Konsole

Debug Konsole

Im Debugging-Modus gibt es zwei prominente Veränderungen der Konsole. Zum einen steht in der Eingabe nun

Browse[1]>

Dies zeigt an, dass man sich im Environment-Browser von R befindet. Größtenteils verhält sich die Konsole im Debugging-Modus wie die normale Konsole, mit ein paar Ausnahmen:

  1. Objekte werden anhand des aktuellen Environments evaluiert. Beispielsweiße wird das Text-Data Frame ausgegeben, wenn man x eingibt, es ist ebenfalls möglich x einen neuen Wert zuzuweisen.
  2. Mit der Eingabe-Taste wird das aktuelle Statement ausgeführt und man springt zum nächsten Statement. Dadurch lässt sich der Code bequem Schritt für Schritt durchgehen.
  3. Es stehen eine Vielzahl von Debugging-Funktionen zu Verfügung auf die Später genauer eingegangen wird.

Die zweite große Veränderung innerhalb der Konsole ist die Funktionsleiste, welche sich über der Konsole befindet. Diese bietet praktische Schalter, um spezielle Debugging-Funktionen direkt an die R-Konsole zu senden. Es gibt hierbei keinen Unterschied, ob man die Befehle in die R-Konsole eingibt oder die Schalter verwendet. Die Schalter bedeuten von links nach rechts mit den entsprechenden Konsolen-Befehlen:

BefehlFunktion
nAusführen des nächsten Statements
sIn den Funktionsaufruf springen

fFunktion/Schleife beenden
cBis zum nächsten Breakpoint fortfahren
QDebugging beenden

Um das aktuelle Environment zu wechseln, verwendet man die Funktion recover(). Dies listet die Environments der vorausgegangenen Funktionen auf. Aus dieser Liste kann das passende Environment gewählt werden.

Fehlerfindung

Doch wo liegt der Fehler in unserem Beispiel? Im Environment-Pane sieht man, dass es sich bei x, welches in die strsplit()-Funktion übergeben wird, um einen Faktor und nicht um einen Character handelt. Dies liegt daran, dass die Standardeinstellung bei data.frame stringsAsFactors = default.stringsAsFactors() ist. Fügen wir in unserem Ausgangscodeblock der test_it-Funktion stringsAsFactors = FALSE hinzu, sehen wir, dass die Funktion durchläuft und unser gewünschtes Ergebnis ausgibt.

Ergebnis vom Buchstabendrehen

Referenzen

  1. https://twitter.com/fortes/status/399339918213652480
  2. Introduction to Debugging in R
  3. https://github.com/rstudio/webinars/tree/master/15-RStudio-essentials/2-Debugging
Über den Autor
Markus Berroth

Markus Berroth

I am data scientist at STATWORX and I love creating novel knowledge from data. In my time off, I am always open for a weekend trip.