Загальні пропозиції щодо налагодження в R


120

Я отримую помилку під час використання функції R, яку я написав:

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

Що я зробив:

  1. Крок через функцію
  2. Додавання друку, щоб з’ясувати, в якому рядку виникає помилка, передбачає дві функції, які не слід використовувати glm.fit. Вони є window()і save().

Мої загальні підходи включають додавання printта stopкоманди та перехід через функціональний рядок за рядком, поки я не зможу знайти виняток.

Однак мені не зрозуміло, використовуючи ті методи, з яких ця помилка походить у коді. Я навіть не впевнений, від яких функцій коду залежить glm.fit. Як мені зайнятися діагностикою цієї проблеми?


5
Перегляньте сторінку Данкана Мердока про налагодження в R
Rob Hyndman

10
Гаразд, я зазначу очевидне: це попередження, а не помилка .
Гевін Сімпсон

10
@ gavin-simpson Я не зрозумів, що є технічна різниця, дякую, що вказав на це. Але врешті-решт це вказує на те, що моя раніше функціональна функція є нефункціональною.
David LeBauer

11
@David +1 для "... моя раніше функціональна функція нефункціональна."
Джошуа Ульріх

5
@David: повторно ваш ps. Це додає вимір питання, яке було б пропущено без прикладу; а саме як змусити R перейти в режим налагодження, коли виробляються лише попередження? Якби ви не залишили цю деталь осторонь, ми б не вказували на вас options(warn = 2). Тож у цьому випадку детальність є важливою для відповіді на ваше загальне запитання. +1 від мене.
Гевін Сімпсон

Відповіді:


167

Я б сказав, що налагодження - це форма мистецтва, тому немає чіткої срібної кулі. Існують хороші стратегії налагодження на будь-якій мові, і вони застосовуються і тут (наприклад, прочитайте цю приємну статтю ). Наприклад, перше, що потрібно відтворити проблему ... якщо ви не можете цього зробити, то вам потрібно отримати більше інформації (наприклад, з веденням журналу). Після того, як ви зможете відтворити його, вам потрібно зменшити його до джерела.

Замість того, щоб "трюк", я б сказав, що у мене є улюблена процедура налагодження:

  1. Коли виникає помилка, перше, що я зазвичай роблю, - це дивитись слід стека за допомогою виклику traceback(): це показує, де сталася помилка, що особливо корисно, якщо у вас є кілька вкладених функцій.
  2. Далі я встановлю options(error=recover); це негайно переходить у режим браузера, де виникає помилка, тож ви можете переглядати робочу область звідти.
  3. Якщо у мене ще недостатньо інформації, я зазвичай використовую цю debug()функцію і переходжу сценарій за рядком.

Найкращий новий трюк в R 2.10 (під час роботи з файлами сценаріїв) - це використовувати функції findLineNum()та setBreakpoint()функції.

Як остаточний коментар: залежно від помилки, також дуже корисно встановити try()абоtryCatch() навколо викликів зовнішніх функцій (особливо при роботі з класами S4). Це іноді надасть ще більше інформації, а також дає більше контролю над тим, як обробляються помилки під час виконання.

Ці пов'язані запитання мають багато пропозицій:


8
Ви також можете додати debugonce () до debug () також.
Joris Meys

2
Хоча не тільки корисно при налагодженні, fix (df1) відкриває графічний редактор R із завантаженим у нього фреймом даних df1, який ви можете редагувати влітку або просто заглянути.
Дмитро І.

налагодження в R здається дуже важким, наприклад, не існує простого рішення, щоб побачити кодові рядки попереджень
TMS

browser()бо коли є помилки, які не викликають попередження / помилки (кредит: Роман Луштрик на цій сторінці). Будь-який інший інструмент, як browser()?
PatrickT


32

Як було зазначено мені в іншому запитанні , Rprof()і summaryRprof()це приємні інструменти для пошуку повільних частин вашої програми, які могли б отримати користь від прискорення або переходу до C / C ++ реалізації. Це, мабуть, стосується більше, якщо ви виконуєте імітаційні роботи або інші обчислювальні чи об'ємні дії. profrПакет може допомогти візуалізувати результати.

Я трохи пізнаю про налагодження, тому ще одна пропозиція з іншої теми :

  • Встановіть, options(warn=2)щоб застереження стосувалися помилок

Ви також можете optionsскористатись вашою улюбленою функцією налагодження, яку ви вибрали, щоб перенести вас у розпал дії, коли з’явиться помилка чи попередження. Наприклад:

  • Встановіть options(error=recover)запуск recover()при виникненні помилки, як зазначив Шейн (і як це зафіксовано в посібнику з налагодження R. Або будь-яка інша зручна функція, яку ви вважаєте корисною для запуску.

І ще два методи з одного із посилань @ Shane :

  • Оберніть внутрішній виклик функції, try()щоб повернути більше інформації про нього.
  • Для * застосовувати функції, використовуйте .inform=TRUE(з пакету plyr) як опцію для команди застосовувати

@JoshuaUlrich також вказав на акуратний спосіб використання умовних здібностей класичної browser()команди для включення / вимкнення налагодження:

  • Покладіть всередину функції, яку ви хочете налагодити browser(expr=isTRUE(getOption("myDebug")))
  • І встановити глобальний варіант за допомогою options(myDebug=TRUE)
  • Можна навіть завершити виклик браузера: myBrowse <- browser(expr=isTRUE(getOption("myDebug")))а потім зателефонувати, myBrowse()оскільки він використовує глобальні дані.

Тоді є нові функції, доступні в R 2.10:

  • findLineNum()приймає ім'я вихідного файла та номер рядка та повертає функцію та середовище. Це здається корисним, коли ви source().R файл, і він повертає помилку в рядку #n, але вам потрібно знати, яка функція знаходиться в рядку #n.
  • setBreakpoint() приймає ім'я вихідного файла та номер рядка та встановлює там точку розриву

Пакет codetools , і особливо його checkUsageфункція, можуть бути особливо корисними для швидкого вибору синтаксису та стилістичних помилок, про які зазвичай повідомляє компілятор (невикористані локалі, невизначені глобальні функції та змінні, часткове узгодження аргументів тощо).

setBreakpoint()є більш зручним для користувача фронтальним пристроєм trace(). Детальна інформація про те, як це працює, доступна в останній статті R Journal .

Якщо ви намагаєтеся налагоджувати чужий пакет, як тільки ви розмістили цю проблему ви можете переписані свої функції з fixInNamespaceі assignInNamespace, але не використовувати це в робочому коді.

Ніщо з цього не повинно перешкоджати перевіреним і справжнім стандартним інструментам налагодження R , деякі з яких є вище, а інші - ні. Зокрема, інструменти для налагодження після смерті зручні, коли у вас є багато часу, куди коду, який ви не бажаєте повторно запускати.

Нарешті, для складних проблем, які, здається, не видають повідомлення про помилку, ви можете використати options(error=dump.frames)як детальніше в цьому запитанні: Помилка без помилки


1
+1 за всю роботу, яку ви вклали, об'єднавши ці питання в одне, а потім залишайте його відкритим!
GSee

29

У якийсь момент glm.fitвикликається. Це означає , що одна з функцій ви називаєте або однієї з функцій , що викликаються цими функціями використовується або glm, glm.fit.

Крім того, як я згадую у своєму коментарі вище, це попередження не про помилку , що робить велику різницю. Ви не можете запустити жодне з інструментів налагодження R із попередження (із параметрами за замовчуванням, перш ніж хтось скаже мені, що я помиляюся ;-).

Якщо ми змінимо параметри перетворення попереджень на помилки, тоді ми можемо почати використовувати засоби налагодження R. Від ?optionsнас:

 ‘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.

Тож якщо ти біжиш

options(warn = 2)

потім запустіть свій код, R видасть помилку. У цей момент ви могли бігти

traceback()

щоб побачити стек викликів. Ось приклад.

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

Тут ви можете ігнорувати рамки, позначені 4:і вище. Ми бачимо, що fooдзвонило, barі це barпороджувало попередження. Це повинно показати вам, які функції викликали glm.fit.

Якщо ви зараз хочете налагодити це, ми можемо звернутися до іншого варіанту, щоб сказати R, щоб він увійшов до налагоджувача, коли він виявив помилку, і, як ми зробили помилки попереджень, ми отримаємо відладчик, коли спрацьовує оригінальне попередження. Для цього слід запустити:

options(error = recover)

Ось приклад:

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

Потім ви можете зайти в будь-який з цих кадрів, щоб побачити, що відбувається під час застереження.

Щоб скинути вищевказані параметри за замовчуванням, введіть

options(error = NULL, warn = 0)

Що стосується конкретного попередження, яке ви цитуєте, велика ймовірність, що вам потрібно дозволити більше ітерацій у коді. Після того як ви дізналися, що викликає glm.fit, розробіть, як передавати йому controlаргумент, використовуючи glm.control- див ?glm.control.


4
чудова відповідь. одна примітка песимізму полягає в тому, що подібні помилки конвергенції часто трапляються з нестабільними / хитрими наборами даних (повне розділення тощо), і вікно між "конвергується просто добре" та "неконвергентним, але не може бути виправлене збільшенням кількості" ітерацій - потребує ще більш кардинальних змін ", часто вузький
Бен Болкер

3
Гевін, я побив тебе на 25 секунд. Я вимагаю від вас видалити надто корисну відповідь і перестати красти мої підсумки. ;-)
Джошуа Ульріх

@Ben чудово. Якщо проблема Девіда - це розділення, то збільшення кількості повторень не повинно допомогти, воно все одно не зможе зблизитися. У цей момент перегляд оцінок і стандартних помилок може припустити, що існує проблема. Я також очікував би побачити попередження про встановлені значення чисельно 0 або 1, якщо розділення чи подібне виникло проблеми. Якщо збільшити кількість повторень не допоможе, Девід може опублікувати ще один Q для допомоги, і я можу вкрасти більше оновлень @ Джошуа ;-)
Гевін Сімпсон

1
@ Джошуа, немає ніякого способу перемогти його. Я перестала рахувати нагороди, які я могла втратити через нього. Але в будь-якому разі допомога, яку він надає, нараховує це далеко не так. Ви повинні знайти власні ніші, якщо ви били його. Я пропоную виплати за кожний натискання клавіш тут ... :)
Метт Баннерт

1
Чорт @ @ ran2, ти зірвав мій підступний, кричущий план захопити світ , Mwahahahahaha !!!!
Гевін Сімпсон

21

Отже browser(), traceback()і debug()заходьте в бар, алеtrace() чекаєте на вулиці і тримає мотор.

Вставивши browserдесь у вашій функції, виконання зупиниться і чекатиме вашого введення. Ви можете рухатися вперед за допомогою n(або Enter), запускати весь фрагмент (ітерацію) за допомогою c, закінчувати поточний цикл / функцію за допомогою fабо виходити з Q; див ?browser.

З debug, ви отримуєте той же ефект, що і у браузері, але це зупиняє виконання функції на її початку. Застосовуються ті самі ярлики. Ця функція буде знаходитися в режимі "налагодження", поки ви не вимкнете її за допомогою undebug(тобто після debug(foo)запуску функції fooкожен раз переходитиме в режим "налагодження" до запуску undebug(foo)).

Більш тимчасовою альтернативою є те debugonce, що видалить режим "налагодження" з функції після наступного оцінювання.

traceback дасть вам потік виконання функцій аж до того, де щось пішло не так (фактична помилка).

Ви можете вставити біти коду (тобто спеціальні функції) у функції trace, наприклад browser. Це корисно для функцій з пакетів, і ви занадто ліниві, щоб отримати добре складений вихідний код.


18

Моя загальна стратегія виглядає так:

  1. Біжи traceback() щоб шукати очевидні проблеми
  2. Встановити options(warn=2)щоб застереження стосувалися помилок
  3. Встановіть, options(error=recover)щоб перейти до стеку дзвінків помилково

15

Після проходження через всі кроки , запропоновані тут , я тільки що дізнався , що установка .verbose = TRUEв foreach()теж дає мені тонни корисної інформації. Зокрема, foreach(.verbose=TRUE)точно показано, де відбувається помилка всередині циклу передбачення, а traceback()не дивиться всередині циклу передбачення.


13

Відладчик Марка Бравінгтона, який доступний як пакет debugна CRAN, дуже хороший і досить прямо.

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

Код з'являється у виділеному вікні Tk, щоб ви могли бачити, що відбувається, і, звичайно, можете зателефонувати іншому mtrace() перебуваючи в іншій функції.

HTH


11

Мені подобається відповідь Гевіна: я не знав про варіанти (помилка = відновлення). Мені також подобається використовувати пакет "налагодження", який дає наочний спосіб перейти до вашого коду.

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

У цей момент воно відкриває окреме вікно налагодження, що показує вашу функцію, жовтою лінією показує, де ви знаходитесь у коді. У головному вікні код переходить у режим налагодження, і ви можете продовжувати натискати клавішу Enter, щоб перейти через код (а також є й інші команди), а також вивчити змінні значення тощо. Жовта лінія у вікні налагодження постійно рухається, щоб показати, де ви в коді. Закінчивши налагодження, ви можете вимкнути трасування за допомогою:

mtrace.off()

5

Виходячи з відповіді, яку я отримав тут , ви обов'язково повинні перевірити options(error=recover)налаштування. Якщо це встановлено, то, зіткнувшись з помилкою, ви побачите текст на консолі, подібний до наступного ( 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:

У цей момент ви можете вибрати, в який "кадр" ввести. Зробивши вибір, ви перейдете в browser()режим:

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

І ви можете вивчити навколишнє середовище таким, яким воно було на момент помилки. Після завершення введіть, cщоб повернути вас до меню вибору кадру. Коли ви закінчите, як вам каже, введіть 0для виходу.


4

Я дав цю відповідь на більш недавнє запитання, але додаю його тут для повноти.

Особисто я прагну не використовувати функції для налагодження. Я часто виявляю, що це завдає стільки ж клопотів, скільки вирішує. Також, виходячи з фону Matlab, мені подобається, що я можу це робити в інтегрованому середовищі розробки (IDE), а не робити це в коді. Використання IDE забезпечує чистий і простий код.

Для R я використовую IDE під назвою "RStudio" ( http://www.rstudio.com ), який доступний для windows, mac та linux і досить простий у використанні.

Версії Rstudio приблизно з жовтня 2013 року (0,98ish?) Мають можливість додавати точки прориву в сценарії та функції: для цього достатньо натиснути лівий край файлу, щоб додати точку розриву. Ви можете встановити точку розриву, а потім перейти з цього моменту. Ви також маєте доступ до всіх даних у цьому середовищі, тому ви можете спробувати команди.

Детальніше див. У розділі http://www.rstudio.com/ide/docs/debugging/overview . Якщо у вас вже встановлений Rstudio, можливо, вам знадобиться оновити - це відносно нова функція (наприкінці 2013 року).

Ви також можете знайти інші IDE, які мають аналогічні функції.

Справді, якщо це вбудована функція, можливо, вам доведеться вдатися до деяких пропозицій, висловлених іншими людьми в цій дискусії. Але, якщо це власний код, який потребує виправлення, рішення на основі IDE може бути саме тим, що вам потрібно.


1

Для налагодження методів Reference Class без посилання на екземпляр

ClassName$trace(methodName, browser)

0

Я починаю вважати, що не друкуючи номер рядка помилок - найголовніша вимога - ЗАВДАННЯ - це якась жарт у R / Rstudio . Єдиний надійний метод, який я знайшов, де виявилася помилка, - докласти додаткових зусиль для виклику traceback () та переглянути верхній рядок.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.