Suggestions générales pour le débogage en R
j'obtiens une erreur en utilisant une fonction R que j'ai écrit:
Warning messages:
1: glm.fit: algorithm did not converge
2: glm.fit: algorithm did not converge
Ce que j'ai fait:
- Étape par le biais de la fonction
- Ajout d'impression pour savoir à quelle ligne l'erreur se produit suggère deux fonctions qui ne devraient pas utiliser
glm.fit
. Ils sontwindow()
etsave()
.
mes approches générales comprennent l'ajout Commandes print
et stop
, et passage d'une fonction ligne par ligne jusqu'à ce que je trouve l'exception.
cependant, il ne me semble pas évident d'utiliser ces techniques pour déterminer d'où vient cette erreur dans le code. Je ne sais même pas quelles fonctions du code dépendent de glm.fit
. Comment dois-je aller sur le diagnostic de ce problème?
13 réponses
je dirais que le débogage est une forme d'art, donc il n'y a pas de solution claire. Il existe de bonnes stratégies pour déboguer dans n'importe quelle langue, et elles s'appliquent ici aussi (par exemple lire cet article agréable ). Par exemple, la première chose est de reproduire le problème ...si vous ne pouvez pas faire cela, alors vous devez obtenir plus d'informations (par exemple avec la journalisation). Une fois que vous pouvez le reproduire, vous devez réduire jusqu'à la source.
plutôt qu'un" truc", je dirais que j'ai une routine de débogage préférée:
- Lorsqu'une erreur se produit, la première chose que je fais habituellement est de regarder la trace de la pile en appelant
traceback()
: cela vous montre où l'erreur s'est produite, ce qui est particulièrement utile si vous avez plusieurs fonctions imbriquées. - ensuite, je vais mettre
options(error=recover)
; cela passe immédiatement en mode navigateur où l'erreur se produit, donc vous on peut parcourir l'espace de travail à partir de là. - si je n'ai toujours pas assez d'informations, j'utilise habituellement la fonction
debug()
et je passe le script ligne par ligne.
la meilleure nouvelle astuce dans R 2.10 (quand on travaille avec des fichiers de script) est d'utiliser les fonctions findLineNum()
et setBreakpoint()
.
comme commentaire final: selon l'erreur, il est également très utile de définir try()
ou tryCatch()
des instructions concernant les appels de fonction externes (en particulier lorsqu'il s'agit de classes S4). Cela fournira parfois encore plus d'informations, et vous donnera également plus de contrôle sur la façon dont les erreurs sont traitées au moment de l'exécution.
ces questions connexes ont beaucoup de suggestions:
La meilleure soluce que j'ai vu jusqu'à présent est:
http://www.biostat.jhsph.edu/%7Erpeng/docs/R-debug-tools.pdf
Quelqu'un est d'accord/pas d'accord?
comme cela m'a été signalé dans une autre question , Rprof()
et summaryRprof()
sont de bons outils pour trouver les parties lentes de votre programme qui pourraient bénéficier d'accélérer ou de passer à une implémentation C/C++. Cela s'applique probablement davantage si vous faites du travail de simulation ou d'autres activités de calcul ou de données intensives. Le profr
package peut aider à visualiser les résultats.
Je suis sur un coup de pied d'apprendre-sur-débogage, donc une autre suggestion de un autre fil :
- Set
options(warn=2)
pour traiter les avertissements comme des erreurs
vous pouvez également utiliser options
pour vous déposer directement dans le feu de l'action lorsqu'une erreur ou un avertissement se produit, en utilisant votre fonction de débogage préféré de votre choix. Par exemple:
- Set
options(error=recover)
pour exécuterrecover()
quand une erreur se produit, comme Shane l'a noté (et comme est documenté dans le R debugging guide . Ou toute autre fonction pratique que vous jugeriez utile d'avoir exécutée.
et deux autres méthodes de l'une des de @Shane" liens :
- envelopper un appel de fonction interne avec
try()
pour retourner plus d'informations sur elle. - pour * appliquer des fonctions, utiliser
.inform=TRUE
(du paquet plyr) en option de la commande apply
@JoshuaUlrich a également souligné une façon soignée d'utiliser les capacités conditionnelles de la commande classique browser()
pour activer/désactiver le débogage:
- mettez à l'intérieur de la fonction que vous pourriez vouloir déboguer
browser(expr=isTRUE(getOption("myDebug")))
- et définit l'option globale par
options(myDebug=TRUE)
- vous pourriez même envelopper l'appel de navigateur:
myBrowse <- browser(expr=isTRUE(getOption("myDebug")))
et puis appeler avecmyBrowse()
car il utilise des globals.
puis il y a les nouvelles fonctions disponibles dans R 2.10:
-
findLineNum()
prend un nom de fichier source et un numéro de ligne et retourne la fonction et l'environnement. Cela semble être utile lorsque voussource()
un .R et il retourne une erreur à la ligne #n, mais vous devez savoir quelle fonction est située à la ligne #N. -
setBreakpoint()
prend un nom de fichier source et un numéro de ligne et y fixe un point de rupture
le paquet codetools , et en particulier sa fonction checkUsage
peut être particulièrement utile pour détecter rapidement les erreurs de syntaxe et de style qu'un compilateur signalerait typiquement (locaux inutilisés, fonctions et variables globales non définies, correspondance partielle des arguments, etc.).
setBreakpoint()
est une partie avant plus conviviale que trace()
. Des détails sur l'intérieur de la façon dont cela fonctionne sont disponibles dans un R récent article de Journal .
si vous essayez de déboguer le paquet de quelqu'un d'autre, une fois que vous avez localisé le problème , vous pouvez sur-écrire leurs fonctions avec fixInNamespace
et assignInNamespace
, mais ne l'utilisez pas dans le code de production.
rien de cela ne devrait empêcher les standard R debugging tools , dont certains sont ci-dessus et d'autres pas. En particulier, les outils de débogage post-mortem sont pratiques lorsque vous avez un paquet de code qui prend beaucoup de temps et que vous préférez ne pas relancer.
enfin, pour les problèmes délicats qui ne semblent pas envoyer de message d'erreur, vous pouvez utiliser options(error=dump.frames)
comme détaillé dans cette question:
erreur sans qu'une erreur soit lancée
à un moment donné, glm.fit
est appelé. Cela signifie que l'une des fonctions que vous appelez ou l'une des fonctions appelées par ces fonctions est d'utiliser soit glm
, glm.fit
.
aussi, comme je le mentionne dans mon commentaire ci-dessus, c'est un avertissement pas une erreur , ce qui fait une grande différence. Vous ne pouvez déclencher aucun des outils de débogage de R à partir d'un avertissement (avec des options par défaut avant que quelqu'un me dit que je suis mauvais.)-;
si nous changeons les options pour transformer les avertissements en erreurs, alors nous pouvons commencer à utiliser les outils de débogage de R. De ?options
nous avons:
‘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.
donc si vous courez
options(warn = 2)
puis lancez votre code, R va lancer une erreur. À ce moment, vous pourriez courir
traceback()
pour voir la pile d'appel. Ici est un exemple.
> 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)
ici, vous pouvez ignorer le cadres marqués 4:
et plus. Nous voyons que foo
appelé bar
et que bar
a généré l'avertissement. Cela devrait vous montrer quelles fonctions appelaient glm.fit
.
si vous voulez maintenant déboguer ceci, nous pouvons nous tourner vers une autre option pour dire à R d'entrer dans le débogueur quand il rencontre une erreur, et comme nous avons fait des erreurs d'Avertissements nous obtiendrons un débogueur quand l'avertissement original est déclenché. Pour cela, vous devez exécuter:
options(error = recover)
voici un exemple:
> 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:
vous pouvez alors entrer dans l'un de ces cadres pour voir ce qui se passait lorsque l'avertissement a été lancé.
pour réinitialiser les options ci-dessus à leur valeur par défaut, entrer
options(error = NULL, warn = 0)
quant à l'avertissement spécifique que vous citez, il est très probable que vous devez autoriser plus d'itérations dans le code. Une fois que vous avez trouvé ce qui s'appelle glm.fit
, travailler sur la façon de passer le "1519170920 argument de" l'aide glm.control
- voir ?glm.control
.
So browser()
, traceback()
et debug()
marcher dans une barre, mais trace()
attend à l'extérieur et maintient le moteur en marche.
en insérant browser
quelque part dans votre fonction, l'exécution s'arrêtera et attendra votre entrée. Vous pouvez aller de l'avant en utilisant n (ou entrer ), exécuter le morceau entier (itération) avec c , terminer la boucle/Fonction actuelle avec f , ou arrêter avec Q ; voir ?browser
.
Avec debug
, vous obtenez le même effet qu'avec le navigateur, mais cela s'arrête l'exécution d'une fonction à son début. Les mêmes raccourcis s'appliquent. Cette fonction sera en mode" debug "jusqu'à ce que vous l'arrêtiez en utilisant undebug
(c'est-à-dire, après debug(foo)
, la fonction foo
entrera en mode" debug "à chaque fois jusqu'à ce que vous exécutiez undebug(foo)
).
A une alternative plus transitoire est debugonce
, qui supprimera le mode" debug " de la fonction après la prochaine évaluation.
traceback
vous donnera le flux d'exécution des fonctions jusqu'à l'endroit où quelque chose a mal tourné (une erreur réelle).
vous pouvez insérer des bits de code (c.-à-d. des fonctions personnalisées) dans les fonctions en utilisant trace
, par exemple browser
. Ceci est utile pour les fonctions de paquets et vous êtes trop paresseux pour obtenez le code source joliment plié.
ma stratégie générale ressemble à:
- Exécuter
traceback()
pour voir regarder pour d'évidentes questions de - Set
options(warn=2)
pour traiter les avertissements comme des erreurs - Set
options(error=recover)
à l'étape dans la pile d'appel sur l'erreur
après avoir passé en revue toutes les étapes suggérées ici, je viens d'apprendre que le réglage .verbose = TRUE
dans foreach()
me donne aussi des tonnes d'informations utiles. En particulier foreach(.verbose=TRUE)
montre exactement où une erreur se produit à l'intérieur de la boucle foreach, tandis que traceback()
ne regarde pas à l'intérieur de la boucle foreach.
le débogueur de Mark Bravington qui est disponible sous le paquet debug
sur CRAN est très bon et assez simple.
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
le code apparaît dans une fenêtre en surbrillance de Tk de sorte que vous pouvez voir ce qui se passe et, bien sûr, vous pouvez appeler un autre mtrace()
alors que dans une fonction différente.
HTH
j'aime la réponse de Gavin: Je ne connaissais pas les options(erreur = récupérer). J'aime aussi utiliser le paquet' debug ' qui donne un moyen visuel de parcourir votre code.
require(debug)
mtrace(foo)
foo(1)
à ce point il ouvre une fenêtre de débogage séparée montrant votre fonction, avec une ligne jaune montrant où vous êtes dans le code. Dans la fenêtre principale le code entre en mode debug, et vous pouvez continuer à frapper enter pour passer à travers le code( et il y a aussi d'autres commandes), et examiner valeurs variables, etc. La ligne jaune dans la fenêtre de débogage continue de bouger pour montrer où vous êtes dans le code. Lorsque le débogage, vous pouvez désactiver le traçage avec:
mtrace.off()
basé sur la réponse que j'ai reçue ici , vous devriez certainement vérifier le réglage options(error=recover)
. Lorsque cette option est activée, en cas d'erreur, vous verrez sur la console un texte similaire à celui qui suit ( 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:
, À quel point vous pouvez choisir "image" pour entrer. Lorsque vous faites une sélection, vous serez placé en mode browser()
:
Selection: 4
Called from: stop(gettextf("replacement has %d rows, data has %d", N, n),
domain = NA)
Browse[1]>
Et vous pouvez examiner l'environnement tel qu'il était au moment de l'erreur. Lorsque vous avez terminé, tapez c
pour vous ramener au menu de sélection des cadres. Quand vous avez terminé, comme il vous dit, tapez 0
pour sortir.
j'ai donné cette réponse à une question plus récente, mais je l'ajoute ici pour l'exhaustivité.
personnellement, J'ai tendance à ne pas utiliser de fonctions pour déboguer. Je trouve souvent que cela cause autant de problèmes que cela résout. En outre, venant d'un contexte Matlab, j'aime pouvoir le faire dans un environnement de développement intégré (IDE) plutôt que de le faire dans le code. Utiliser un IDE permet de garder votre code propre et simple.
pour R, j'utilise un IDE appelé "RStudio" ( ) http://www.rstudio.com ), qui est disponible pour windows, mac et linux et est assez facile à utiliser.
Versions de Rstudio depuis environ octobre 2013 (0,98 ish?) ont la possibilité d'ajouter des points de rupture dans les scripts et les fonctions: pour ce faire, il suffit de cliquer sur la marge gauche du fichier pour ajouter un point de rupture. Vous pouvez définir un point d'arrêt et ensuite étape à partir de ce point. Vous avez également accès à toutes les données que environnement, donc vous pouvez essayer des commandes.
voir http://www.rstudio.com/ide/docs/debugging/overview pour plus de détails. Si vous avez déjà installé Rstudio, vous devrez peut - être faire une mise à niveau-il s'agit d'une fonctionnalité relativement nouvelle (fin 2013).
vous pouvez également trouver d'autres IDEs qui ont des fonctionnalités similaires.
Certes, si c'est une fonction intégrée vous pouvez avoir recours à certaines des suggestions faites par d'autres des gens dans cette discussion. Mais, si c'est votre propre code qui doit être corrigé, une solution basée sur L'IDE pourrait être exactement ce dont vous avez besoin.
debug Classe de Référence méthodes sans instance de référence
ClassName$trace(methodName, browser)
je commence à penser que ne pas imprimer le numéro de ligne d'erreur - une exigence la plus élémentaire - par défaut - est une sorte de blague dans R/Rstudio . La seule méthode fiable que j'ai trouvé pour trouver où une erreur s'est produite est de faire l'effort supplémentaire de Callo traceback() et voir la ligne supérieure.