Ogólne sugestie dotyczące debugowania w R

Pojawia się błąd podczas używania funkcji R, którą napisałem:

Warning messages:
1: glm.fit: algorithm did not converge 
2: glm.fit: algorithm did not converge 

Co zrobiłem:

  1. krok przez funkcję
  2. dodanie print, aby dowiedzieć się, w jakiej linii występuje błąd, sugeruje dwie funkcje, które nie powinny używać glm.fit. Są to window() i save().

Moje ogólne podejście obejmuje dodawanie komend print i stop oraz przechodzenie przez linię funkcji po linii, aż uda mi się zlokalizować wyjątek.

Nie jest jednak jasne, aby mnie za pomocą tych technik, z których pochodzi ten błąd w kodzie. Nie jestem nawet pewien, które funkcje w kodzie zależą od glm.fit. Jak mam diagnozować ten problem?

Author: David LeBauer, 2010-12-14

13 answers

Powiedziałbym, że debugowanie jest formą sztuki, więc nie ma wyraźnej srebrnej kuli. Istnieją dobre strategie debugowania w dowolnym języku i mają one zastosowanie również tutaj(np. przeczytaj ten ładny artykuł ). Na przykład, pierwszą rzeczą jest odtworzenie problemu...jeśli nie możesz tego zrobić, musisz uzyskać więcej informacji(np. z logowaniem). Po odtworzeniu musisz zredukować do źródła.

Zamiast "sztuczki", powiedziałbym, że mieć ulubioną procedurę debugowania:

  1. gdy wystąpi błąd, pierwszą rzeczą, którą zwykle robię, jest spojrzenie na ślad stosu przez wywołanie traceback(): pokazuje, gdzie wystąpił błąd, co jest szczególnie przydatne, jeśli masz kilka zagnieżdżonych funkcji.
  2. następnie ustawię options(error=recover); to natychmiast przełącza się w tryb przeglądarki, gdzie występuje błąd, więc możesz przeglądać obszar roboczy stamtąd.
  3. Jeśli nadal nie mam wystarczającej ilości informacji, zwykle używam funkcji debug() i przejść przez skrypt wiersz po linii.

Najlepszą nową sztuczką w R 2.10 (podczas pracy z plikami skryptów) jest użycie funkcji findLineNum() i setBreakpoint().

Jako ostatni komentarz: w zależności od błędu, bardzo pomocne jest również ustawienie instrukcji try() lub tryCatch() wokół zewnętrznych wywołań funkcji (szczególnie w przypadku klas S4). To czasami dostarcza jeszcze więcej informacji, a także daje większą kontrolę nad tym, jak błędy są obsługiwane podczas uruchamiania czas.

Te pytania mają wiele sugestii:

 161
Author: Shane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:19

Najlepszy solucja jaki do tej pory widziałem to:

Http://www.biostat.jhsph.edu/%7Erpeng/docs/R-debug-tools.pdf

Ktoś się zgadza/nie zgadza?

 37
Author: Christopher DuBois,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-23 03:48:02

Jak mi zostało powiedziane w innym pytaniu, Rprof() i {[1] } są dobrymi narzędziami do znajdowania wolnych części programu, które mogą skorzystać z przyspieszenia lub przejścia do implementacji C/C++. Prawdopodobnie dotyczy to bardziej, jeśli wykonujesz prace Symulacyjne lub inne czynności wymagające dużej ilości danych lub obliczeń. Na profr pakiet może pomóc w wizualizacji wyników.

Jestem na lekkim wykopieniu debugowania, więc kolejna sugestia od innego wątek :

  • Ustaw options(warn=2), aby traktować ostrzeżenia jak błędy

Możesz również użyć options, aby rzucić się w sam środek akcji, gdy wystąpi błąd lub ostrzeżenie, używając ulubionej wybranej funkcji debugowania. Na przykład:

    Gdy pojawi się błąd, należy ustawić
  • , aby uruchomić recover(), Jak zauważył Shane (i jak zostało to udokumentowane w podręczniku debugowania r. Lub jakakolwiek inna przydatna funkcja, którą można uruchomić.

I kolejne dwa metody z jednego z linków @ Shane :

  • zawiń wewnętrzne wywołanie funkcji za pomocą try(), aby zwrócić więcej informacji na jej temat.
  • dla funkcji * apply, użyj .inform=TRUE (z pakietu plyr) jako opcji polecenia apply

@JoshuaUlrich wskazał również zgrabny sposób użycia warunkowych możliwości klasycznego polecenia browser() do włączania / wyłączania debugowania:

  • Umieść wewnątrz funkcji, którą chcesz debugować browser(expr=isTRUE(getOption("myDebug")))
  • I ustaw opcję globalną przez options(myDebug=TRUE)
  • Możesz nawet zawinąć wywołanie przeglądarki: myBrowse <- browser(expr=isTRUE(getOption("myDebug"))), a następnie wywołać za pomocą myBrowse(), ponieważ używa globali.

Następnie są nowe funkcje dostępne w R 2.10:

  • findLineNum() pobiera nazwę pliku źródłowego i numer linii oraz zwraca funkcję i środowisko. To wydaje się być pomocne, gdy source() a .Plik R i zwraca błąd w linii #n, ale musisz wiedzieć, jaka funkcja znajduje się w linii #n.
  • setBreakpoint() bierze nazwa pliku źródłowego i numer linii oraz ustawia tam punkt przerwania

Pakiet codetools , a szczególnie jego funkcja checkUsage Może być szczególnie pomocna w szybkim wykrywaniu błędów składniowych i stylistycznych, które kompilator zazwyczaj zgłaszałby (nieużywane lokalne, niezdefiniowane globalne funkcje i zmienne, częściowe dopasowanie argumentów itp.).

setBreakpoint() jest bardziej przyjazny dla użytkownika front-end do trace(). Szczegółowe informacje na temat tego, jak to działa, są dostępne w ostatni artykuł w czasopiśmie R .

Jeśli próbujesz debugować czyjś pakiet, po zlokalizowaniu problemu możesz nadpisać jego funkcje za pomocą fixInNamespace i assignInNamespace, ale nie używaj tego w kodzie produkcyjnym.

Nic z tego nie powinno wykluczać sprawdzonych i prawdziwych standardowych narzędzi debugowania R , z których niektóre są powyżej, a inne nie. W szczególności narzędzia debugowania post mortemsą przydatne, gdy masz czasochłonna kupa kodu, którego nie chcesz uruchamiać ponownie.

Wreszcie, dla trudnych problemów, które wydają się nie rzucać komunikat o błędzie, można użyć options(error=dump.frames) Jak szczegółowo w tym pytaniu: Error without a error being throwed

 32
Author: Ari B. Friedman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:59

W pewnym momencie, glm.fit jest wywoływany. Oznacza to, że jedna z funkcji wywoływanych przez te funkcje lub jedna z funkcji wywoływanych przez te funkcje używa albo glm, glm.fit.

Również, jak wspomniałem w moim komentarzu powyżej, jest to Ostrzeżenie , a nie błąd , co robi dużą różnicę. Nie możesz uruchomić żadnego z narzędzi debugowania R z ostrzeżenia(z domyślnymi opcjami, zanim ktoś powie mi, że się mylę ; -).

Jeśli zmienimy opcje, aby zamienić ostrzeżenia W błędy następnie możemy zacząć używać narzędzi debugowania R. Z ?options mamy:

 ‘warn’: sets the handling of warning messages.  If ‘warn’ is
      negative all warnings are ignored.  If ‘warn’ is zero (the
      default) warnings are stored until the top-level function
      returns.  If fewer than 10 warnings were signalled they will
      be printed otherwise a message saying how many (max 50) were
      signalled.  An object called ‘last.warning’ is created and
      can be printed through the function ‘warnings’.  If ‘warn’ is
      one, warnings are printed as they occur.  If ‘warn’ is two or
      larger all warnings are turned into errors.

Więc jeśli biegniesz

options(warn = 2)

Następnie uruchom kod, R wyrzuci błąd. W którym momencie możesz uruchomić

traceback()

Aby zobaczyć stos połączeń. Oto przykład.

> options(warn = 2)
> foo <- function(x) bar(x + 2)
> bar <- function(y) warning("don't want to use 'y'!")
> foo(1)
Error in bar(x + 2) : (converted from warning) don't want to use 'y'!
> traceback()
7: doWithOneRestart(return(expr), restart)
6: withOneRestart(expr, restarts[[1L]])
5: withRestarts({
       .Internal(.signalCondition(simpleWarning(msg, call), msg, 
           call))
       .Internal(.dfltWarn(msg, call))
   }, muffleWarning = function() NULL)
4: .signalSimpleWarning("don't want to use 'y'!", quote(bar(x + 
       2)))
3: warning("don't want to use 'y'!")
2: bar(x + 2)
1: foo(1)

Tutaj możesz zignorować ramki oznaczone 4: i wyżej. Widzimy, że foo wywołał bar i że bar wygenerował Ostrzeżenie. To powinno pokazać, które funkcje wywoływały glm.fit.

Jeśli teraz chcesz Debuguj to, możemy przejść do innej opcji, aby powiedzieć R, aby wszedł do debuggera, gdy napotka błąd, a ponieważ popełniliśmy błędy ostrzeżeń, otrzymamy debugger po uruchomieniu oryginalnego Ostrzeżenia. W tym celu należy uruchomić:

options(error = recover)
Oto przykład:]}
> options(error = recover)
> foo(1)
Error in bar(x + 2) : (converted from warning) don't want to use 'y'!

Enter a frame number, or 0 to exit   

1: foo(1)
2: bar(x + 2)
3: warning("don't want to use 'y'!")
4: .signalSimpleWarning("don't want to use 'y'!", quote(bar(x + 2)))
5: withRestarts({
6: withOneRestart(expr, restarts[[1]])
7: doWithOneRestart(return(expr), restart)

Selection:

Możesz wejść do każdej z tych klatek, aby zobaczyć, co się dzieje, gdy ostrzeżenie zostało rzucone.

Aby zresetować powyższe opcje do domyślnych, wpisz

options(error = NULL, warn = 0)

Co do szczególnego Ostrzeżenia cytujesz, jest wysoce prawdopodobne, że musisz zezwolić na więcej iteracji w kodzie. Gdy dowiesz się, co wywołuje glm.fit, zastanów się, jak przekazać argument control używając glm.control - zobacz ?glm.control.

 27
Author: Gavin Simpson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-14 18:45:05

Więc browser(), traceback() wchodzi do baru, ale czeka na zewnątrz i utrzymuje silnik w ruchu.

Wstawiając browser gdzieś w twojej funkcji, wykonanie zatrzyma się i będzie czekać na twoje wejście. Możesz przejść do przodu używając n (lub Enter), uruchomić cały fragment (iterację) za pomocą c, zakończyć pętlę/funkcję za pomocą f, lub zakończyć za pomocą Q; zobacz ?browser.

Z debug, uzyskujesz taki sam efekt jak w przeglądarce, ale to zatrzymuje wykonywanie funkcji na jej początku. Obowiązują te same skróty. Funkcja ta będzie w trybie "debugowania", dopóki nie wyłączysz jej za pomocą undebug (to znaczy, po debug(foo), uruchomienie funkcji foo wejdzie w tryb "debugowania" za każdym razem, dopóki nie uruchomisz undebug(foo)).

Bardziej przejściową alternatywą jest debugonce, która usunie tryb "debug" z funkcji po następnym jej ocenie.

traceback zapewni Ci przepływ realizacji funkcji aż do miejsca, w którym coś poszło nie tak(rzeczywisty błąd).

Można wstawiać bity kodu (np. funkcje niestandardowe) do funkcji za pomocą trace, na przykład browser. Jest to przydatne dla funkcji z Pakietów i jesteś zbyt leniwy, aby uzyskać ładnie złożony kod źródłowy.

 20
Author: Roman Luštrik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-04 02:20:25

Moja ogólna strategia wygląda następująco:

  1. Uruchom traceback() aby zobaczyć szukać oczywistych problemów
  2. Ustaw options(warn=2), aby traktować ostrzeżenia jak błędy
  3. Ustaw options(error=recover), aby wejść do stosu wywołań w przypadku błędu
 18
Author: Joshua Ulrich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-14 18:44:51

Po przejściu przez wszystkie sugerowane tutaj kroki dowiedziałem się, że ustawienie .verbose = TRUE w foreach() daje mi również mnóstwo przydatnych informacji. W szczególności foreach(.verbose=TRUE) pokazuje dokładnie, gdzie występuje błąd wewnątrz pętli foreach, podczas gdy traceback() nie zagląda do wnętrza pętli foreach.

 15
Author: Michael Schneider,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-29 19:15:45

Debugger Mark Bravington, który jest dostępny jako pakiet {[1] } na CRAN jest bardzo dobry i całkiem prosty.

library(debug);
mtrace(myfunction);
myfunction(a,b);
#... debugging, can query objects, step, skip, run, breakpoints etc..
qqq(); # quit the debugger only
mtrace.off(); # turn off debugging

Kod pojawia się w podświetlonym oknie Tk, dzięki czemu możesz zobaczyć, co się dzieje i oczywiście możesz wywołać inną mtrace() podczas gdy w innej funkcji.

HTH

 13
Author: David Lawrence Miller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-23 08:04:13

Podoba mi się odpowiedź Gavina: nie wiedziałem o opcjach (error = recover). Lubię również używać pakietu 'debug', który daje wizualny sposób na przejście przez kod.

require(debug)
mtrace(foo)
foo(1)

W tym momencie otwiera osobne okno debugowania pokazujące twoją funkcję, z żółtą linią pokazującą, gdzie jesteś w kodzie. W głównym oknie Kod wchodzi w tryb debugowania i możesz wciskać enter, aby przejść przez kod (i są też inne polecenia) i sprawdzić wartości zmiennych itp. Na żółta linia w oknie debugowania porusza się, aby pokazać, gdzie jesteś w kodzie. Po zakończeniu debugowania można wyłączyć śledzenie za pomocą:

mtrace.off()
 11
Author: Prasad Chalasani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-15 15:57:04

Na podstawie odpowiedzi, którą otrzymałem tutaj , zdecydowanie powinieneś sprawdzić options(error=recover) ustawienie. Gdy ta opcja jest ustawiona, po napotkaniu błędu zobaczysz tekst na konsoli podobny do następującego (traceback output):

> source(<my filename>)
Error in plot.window(...) : need finite 'xlim' values
In addition: Warning messages:
1: In xy.coords(x, y, xlabel, ylabel, log) : NAs introduced by coercion
2: In min(x) : no non-missing arguments to min; returning Inf
3: In max(x) : no non-missing arguments to max; returning -Inf

Enter a frame number, or 0 to exit   

1: source(<my filename>)
2: eval.with.vis(ei, envir)
3: eval.with.vis(expr, envir, enclos)
4: LinearParamSearch(data = dataset, y = data.frame(LGD = dataset$LGD10), data.names = data
5: LinearParamSearch.R#66: plot(x = x, y = y.data, xlab = names(y), ylab = data.names[i])
6: LinearParamSearch.R#66: plot.default(x = x, y = y.data, xlab = names(y), ylab = data.nam
7: LinearParamSearch.R#66: localWindow(xlim, ylim, log, asp, ...)
8: LinearParamSearch.R#66: plot.window(...)

Selection:

W którym momencie możesz wybrać, którą" klatkę " wprowadzić. Po dokonaniu wyboru zostaniesz przeniesiony do trybu browser():

Selection: 4
Called from: stop(gettextf("replacement has %d rows, data has %d", N, n), 
    domain = NA)
Browse[1]> 

I możesz zbadać środowisko tak, jak było w czasie błędu. Kiedy skończysz, wpisz c, aby przynieść wróć do menu wyboru ramki. Kiedy skończysz, jak ci to mówi, wpisz 0, aby wyjść.

 5
Author: eykanal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:33:24

Odpowiedziałem na pytanie bardziej aktualne, ale dodałem je tutaj dla kompletności.

Osobiście nie używam funkcji do debugowania. Często stwierdzam, że powoduje to tyle problemów, ile rozwiązuje. Ponadto, pochodząc z tła Matlab lubię być w stanie to zrobić w zintegrowanym środowisku programistycznym (IDE), a nie robić to w kodzie. Korzystanie z IDE sprawia, że Twój kod jest czysty i prosty.

Dla R, używam IDE o nazwie " RStudio" ( http://www.rstudio.com ), który jest dostępny dla Systemów windows, mac i linux i jest dość łatwy w użyciu.

Wersje Rstudio od około października 2013 (0.98 ish?) mają możliwość dodawania punktów przerwania w skryptach i funkcjach: aby to zrobić, wystarczy kliknąć lewy margines pliku, aby dodać punkt przerwania. Możesz ustawić punkt przerwania, a następnie przejść od tego punktu. Masz również dostęp do wszystkich danych w tym środowisku, dzięki czemu możesz wypróbować polecenia.

Zobacz http://www.rstudio.com/ide/docs/debugging/overview Po szczegóły. Jeśli masz już zainstalowane Rstudio, może być konieczne uaktualnienie-jest to stosunkowo nowa (późny 2013) funkcja.

Możesz również znaleźć inne IDE, które mają podobną funkcjonalność.

Co prawda, jeśli jest to wbudowana funkcja, być może będziesz musiał odwołać się do niektórych sugestii innych osób w tej dyskusji. Ale jeśli twój własny kod wymaga naprawy, rozwiązanie oparte na IDE może być właśnie tym, co Ty potrzeba.

 4
Author: Andy Clifton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:33:24

Do debugowania klasy referencyjnej metod bez referencji instancji

ClassName$trace(methodName, browser)
 1
Author: shiva,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-26 11:57:17

Zaczynam myśleć, że nie wypisanie numeru linii błędu-najbardziej podstawowego wymogu-przez DEFAILT-to jakiś żart w R/RStudio. Jedyną wiarygodną metodą, jaką znalazłem, aby znaleźć miejsce wystąpienia błędu, jest wykonanie dodatkowego wysiłku wywołania traceback () i zobacz górną linię.

 0
Author: user9669128,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-19 10:47:08