Je reçois une erreur en utilisant une fonction R que j'ai écrite:
Warning messages:
1: glm.fit: algorithm did not converge
2: glm.fit: algorithm did not converge
Ce que j'ai fait:
glm.fit
. Ils sont window()
et save()
.Mes approches générales incluent l’ajout de commandes print
et stop
et l’exploration ligne par ligne d’une fonction jusqu’à ce que je puisse localiser l’exception.
Cependant, l'utilisation de ces techniques pour expliquer l'origine de cette erreur dans le code n'est pas claire. Je ne suis même pas certain que les fonctions dans le code dépendent de glm.fit
. Comment puis-je diagnostiquer ce problème?
Je dirais que le débogage est une forme d'art, il n'y a donc pas de solution miracle. Il existe de bonnes stratégies de débogage dans toutes les langues et elles s'appliquent ici aussi (par exemple, lisez cet article de Nice ). Par exemple, la première chose à faire est de reproduire le problème ... si vous ne pouvez pas le faire, vous devez obtenir plus d'informations (par exemple, en vous connectant). Une fois que vous pouvez le reproduire, vous devez le réduire à la source.
Plutôt qu'un "truc", je dirais que j'ai une routine de débogage favorite:
traceback()
: elle vous indique où l’erreur est survenue, ce qui est particulièrement utile si vous avez plusieurs fonctions imbriquées.options(error=recover)
; cela bascule immédiatement en mode navigateur où l'erreur se produit, vous permettant ainsi de parcourir l'espace de travail à partir de là.debug()
et parcourt le script ligne par ligne. Le meilleur nouveau truc dans R 2.10 (lorsque vous travaillez avec des fichiers de script) est d'utiliser les fonctions findLineNum()
et setBreakpoint()
.
Dernier commentaire: en fonction de l'erreur, il est également très utile de définir des instructions try()
ou tryCatch()
autour d'appels de fonctions externes (en particulier pour les classes S4). Cela fournira parfois même plus d'informations, et vous donnera également plus de contrôle sur la manière dont les erreurs sont gérées au moment de l'exécution.
Ces questions connexes ont beaucoup de suggestions:
La meilleure solution que j'ai vue jusqu'à présent est:
http://www.biostat.jhsph.edu/%7Erpeng/docs/R-debug-tools.pdf
Quelqu'un est d'accord/pas d'accord?
Comme il m’a été signalé dans autre question , Rprof()
et summaryRprof()
sont de bons outils pour trouver les parties lentes de votre programme qui pourraient bénéficier d’une accélération ou d’une transition vers une implémentation C/C++. Cela s'applique probablement davantage si vous effectuez des travaux de simulation ou d'autres activités gourmandes en ressources informatiques ou informatiques. Le profr
package peut aider à visualiser les résultats.
Je suis sur le coup d'apprendre quelque chose sur le débogage, donc une autre suggestion de un autre fil :
options(warn=2)
pour traiter les avertissements comme des erreursVous pouvez également utiliser options
pour vous plonger dans le feu de l'action lorsqu'une erreur ou un avertissement se produit, à l'aide de la fonction de débogage de votre choix. Par exemple:
options(error=recover)
pour exécuter recover()
lorsqu'une erreur se produit, comme Shane l'a noté (et comme indiqué dans le guide de débogage R) . Ou toute autre fonction utile que vous jugeriez utile d'exécuter.Et deux autres méthodes de l'une des liens } de @ Shane:
try()
pour renvoyer plus d’informations à son sujet..inform=TRUE
(du paquet plyr) comme option de la commande apply@JoshuaUlrich a également fait remarquer une manière élégante d'utiliser les capacités conditionnelles de la commande browser()
classique pour activer/désactiver le débogage:
browser(expr=isTRUE(getOption("myDebug")))
options(myDebug=TRUE)
myBrowse <- browser(expr=isTRUE(getOption("myDebug")))
, puis appeler avec myBrowse()
puisqu'il utilise des globales.Ensuite, 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 renvoie la fonction et l'environnement. Cela semble être utile lorsque vous source()
un fichier .R et qu'il renvoie une erreur à la ligne #n, mais vous devez savoir quelle fonction se trouve à la ligne #n.setBreakpoint()
prend un nom de fichier source et un numéro de ligne et y définit un point d'arrêt Le package codetools , et en particulier sa fonction checkUsage
, peut être particulièrement utile pour détecter rapidement les erreurs de syntaxe et de style que le compilateur devrait généralement signaler (locals inutilisés, fonctions et variables globales non définies, correspondance partielle d'arguments, etc.). ).
setBreakpoint()
est un frontal plus convivial pour trace()
. Des détails sur le fonctionnement interne de ce processus sont disponibles dans un article récent du journal R .
Si vous essayez de déboguer le paquet de quelqu'un d'autre, une fois que vous avez localisé le problème, vous pouvez écraser leurs fonctions } avec fixInNamespace
et assignInNamespace
, mais ne l'utilisez pas dans le code de production.
Rien de tout cela ne devrait exclure les outils de débogage R standard qui ont fait leurs preuves, dont certains sont au-dessus et d'autres pas. En particulier, les outils de débogage post-mortem sont pratiques lorsque vous avez une pile de code qui prend du temps et que vous préférez ne pas réexécuter.
Enfin, pour les problèmes complexes qui ne semblent pas générer de message d'erreur, vous pouvez utiliser options(error=dump.frames)
comme indiqué dans cette question: Erreur sans qu'une erreur ne soit générée
glm.fit
est appelé à un moment donné. Cela signifie que l’une des fonctions que vous appelez ou l’une des fonctions appelées par ces fonctions utilise soit glm
, glm.fit
.
En outre, comme je l’ai mentionné dans mon commentaire ci-dessus, c’est un avertissement pas une erreur , ce qui fait toute la différence. Vous ne pouvez déclencher aucun des outils de débogage de R par un avertissement (avec les options par défaut avant que quelqu'un ne me dise que je me trompe ;-).
Si nous changeons les options pour transformer les avertissements en erreurs, nous pourrons 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 tu cours
options(warn = 2)
puis lancez votre code, R va lancer une erreur. A quel point, vous pourriez courir
traceback()
pour voir la pile d'appels. Voici 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 les cadres marqués 4:
et plus. Nous voyons que foo
a 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 utiliser une autre option pour demander à R d'entrer dans le débogueur lorsqu'il rencontre une erreur. Comme nous avons commis des erreurs d'avertissement, nous aurons un débogueur lorsque l'avertissement d'origine est déclenché. Pour cela, vous devriez lancer:
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 ensuite entrer dans n'importe lequel de ces cadres pour voir ce qui se passait lorsque l'avertissement a été lancé.
Pour réinitialiser les options ci-dessus à leurs valeurs par défaut, entrez
options(error = NULL, warn = 0)
En ce qui concerne l'avertissement spécifique que vous citez, il est fort probable que vous deviez autoriser davantage d'itérations dans le code. Une fois que vous avez découvert l'appel de glm.fit
, déterminez comment passer l'argument control
à l'aide de glm.control
- voir ?glm.control
.
Ainsi, browser()
, traceback()
et debug()
entrent dans un bar, mais trace()
attend à l'extérieur et maintient le moteur en marche.
En insérant browser
quelque part dans votre fonction, l'exécution sera interrompue et attendra votre entrée. Vous pouvez avancer en utilisant n (ou Enter), lancez le morceau entier (itération) avec c, terminez la boucle/fonction en cours avec fou quitter avec Q; voir ?browser
.
Avec debug
, vous obtenez le même effet qu'avec le navigateur, mais cela arrête l'exécution d'une fonction à son début. Les mêmes raccourcis s'appliquent. Cette fonction sera en mode "débogage" jusqu'à ce que vous la désactiviez avec undebug
(c'est-à-dire qu'après debug(foo)
, l'exécution de la fonction foo
entrera en mode "debug" jusqu'à ce que vous exécutiez undebug(foo)
).
Une alternative plus transitoire est debugonce
, qui supprimera le mode "débogage" de la fonction lors de sa prochaine évaluation.
traceback
vous donnera le flux d'exécution des fonctions jusqu'à l'endroit où quelque chose s'est mal passé (une erreur réelle).
Vous pouvez insérer des bits de code (c'est-à-dire des fonctions personnalisées) dans des fonctions en utilisant trace
, par exemple browser
. Ceci est utile pour les fonctions des packages et vous êtes trop paresseux pour obtenir le code source bien plié.
Ma stratégie générale ressemble à:
traceback()
pour rechercher des problèmes évidentsoptions(warn=2)
pour traiter les avertissements comme des erreursoptions(error=recover)
pour entrer dans la pile d'appels en cas d'erreurAprès avoir suivi toutes les étapes suggérées ici, je viens d’apprendre que le réglage de .verbose = TRUE
dans foreach()
me donne également une tonne d’informations utiles. En particulier, foreach(.verbose=TRUE)
indique exactement où une erreur se produit dans la boucle foreach, alors 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 Tk en surbrillance afin que vous puissiez voir ce qui se passe et, bien sûr, vous pouvez appeler une autre mtrace()
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 stade, il ouvre une fenêtre de débogage séparée affichant votre fonction, avec une ligne jaune indiquant votre position dans le code. Dans la fenêtre principale, le code entre en mode débogage et vous pouvez appuyer sur entrée pour faire défiler le code (et d'autres commandes également), et examiner les valeurs de variables, etc. La ligne jaune dans la fenêtre de débogage continue de défiler vous êtes dans le code. Une fois le débogage terminé, vous pouvez désactiver le traçage avec:
mtrace.off()
Sur la base de la réponse que j'ai reçue ici , vous devez absolument vérifier le paramètre options(error=recover)
. Lorsque cette option est définie, en cas d'erreur, le texte affiché sur la console est similaire à ce qui suit (sortie traceback
):
> 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:
A quel point vous pouvez choisir quel "cadre" entrer. Lorsque vous effectuez une sélection, vous passez 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 de cadre. Lorsque vous avez terminé, comme indiqué, tapez 0
pour quitter.
J'ai donné cette réponse à une question plus récente, mais l'ajoute ici par souci d'exhaustivité.
Personnellement, j'ai tendance à ne pas utiliser les fonctions pour déboguer. Je trouve souvent que cela cause autant de problèmes qu’il en résout. De plus, venant d'un environnement Matlab, j'aime pouvoir le faire dans un environnement de développement intégré (IDE) plutôt que dans le code. L'utilisation d'un IDE maintient votre code propre et simple.
Pour R, j'utilise un IDE appelé "RStudio" ( http://www.rstudio.com ), disponible pour Windows, Mac et Linux et qui est assez facile à utiliser.
Les versions de Rstudio depuis octobre 2013 environ (0.98?) Permettent d'ajouter des points d'arrêt dans les scripts et les fonctions: il suffit pour cela de cliquer sur la marge de gauche du fichier pour ajouter un point d'arrêt. Vous pouvez définir un point d'arrêt, puis passer à partir de ce point. Vous avez également accès à toutes les données de cet environnement, vous pouvez donc 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 mettre à niveau - il s'agit d'une fonctionnalité relativement nouvelle (fin 2013).
Vous pouvez également trouver d'autres IDE ayant des fonctionnalités similaires.
Certes, s'il s'agit d'une fonction intégrée, vous devrez peut-être recourir à certaines des suggestions faites par d'autres personnes au cours de cette discussion. Toutefois, si votre propre code doit être corrigé, une solution basée sur l'EDI est peut-être ce dont vous avez besoin.
Pour déboguer Classe de référence méthodes sans référence d'instance
ClassName$trace(methodName, browser)
Je commence à penser que ne pas imprimer le numéro de ligne d'erreur - une exigence fondamentale - BY DEFAILT - est une sorte de blague dans R/Rstudio . La seule méthode fiable que j'ai trouvée pour trouver une erreur est de faire l'effort supplémentaire de calloing traceback () et de voir la ligne du haut.