R'de hata ayıklama için genel öneriler


120

Yazdığım bir R işlevini kullanırken bir hata alıyorum:

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

Ne yaptım:

  1. İşleve adım atın
  2. Hatanın hangi satırda oluştuğunu bulmak için baskı eklemek, kullanılmaması gereken iki işlevi önerir glm.fit. Bunlar window()ve save().

Genel yaklaşımlarım arasında , istisnayı bulana kadar, ekleme printve stopkomutlar ve bir işlevde satır satır adım adım yer alır.

Ancak, bu hatanın koddan geldiği bu teknikleri kullanmak benim için açık değil. Kod içindeki hangi işlevlerin bağlı olduğundan bile emin değilim glm.fit. Bu problemi nasıl teşhis edebilirim?



10
Tamam, bariz olanı belirteceğim: bu bir uyarı değil, bir hata .
Gavin Simpson

10
@ gavin-simpson Teknik bir fark olduğunu fark etmedim, bunu belirttiğiniz için teşekkürler. Ama sonuçta, daha önceki işlevsel işlevimin işlevsiz olduğunu gösteriyor.
David LeBauer

11
@David +1 "... önceki işlevsel işlevim işlevsiz."
Joshua Ulrich

5
@David: ps. Bu, soruya örnek olmadan gözden kaçırılacak bir boyut katar; yani, yalnızca uyarılar üretildiğinde R'nin hata ayıklama moduna geçmesi nasıl sağlanır? Bu detayı dışarıda bırakmış olsaydın, hepimiz seni işaret etmezdik options(warn = 2). Dolayısıyla bu durumda, genel sorunuzu yanıtlamak için ayrıntı çok önemlidir. Benden +1.
Gavin Simpson

Yanıtlar:


167

Hata ayıklamanın bir sanat formu olduğunu söyleyebilirim, bu yüzden net bir sihirli değnek yoktur. Herhangi bir dilde hata ayıklamak için iyi stratejiler vardır ve bunlar burada da geçerlidir (örneğin bu güzel makaleyi okuyun ). Örneğin, ilk şey sorunu yeniden oluşturmaktır ... eğer bunu yapamazsanız, o zaman daha fazla bilgi almanız gerekir (örneğin, günlük kaydı ile). Yeniden üretebildiğinizde , kaynağına indirgemeniz gerekir.

Bir "numara" yerine, favori bir hata ayıklama rutinim olduğunu söyleyebilirim:

  1. Bir hata oluştuğunda, genellikle yaptığım ilk şey, çağırarak yığın izine bakmaktır traceback(): bu, hatanın nerede oluştuğunu gösterir, bu özellikle birkaç iç içe işleviniz varsa yararlıdır.
  2. Sonra belirleyeceğim options(error=recover); bu hemen hatanın oluştuğu tarayıcı moduna geçer, böylece çalışma alanına buradan göz atabilirsiniz.
  3. Hala yeterli bilgiye sahip değilsem, genellikle debug()işlevi kullanırım ve komut dosyası boyunca satır satır adım adım ilerlerim.

R 2.10'daki en iyi yeni numara (komut dosyalarıyla çalışırken) findLineNum()ve setBreakpoint()işlevlerini kullanmaktır .

Son bir yorum olarak: Hataya bağlı olarak, harici işlev çağrıları etrafında (özellikle S4 sınıflarıyla uğraşırken) ifadeler ayarlamak try()veya tryCatch()ifadeler oluşturmak çok yararlıdır . Bu bazen daha fazla bilgi sağlar ve ayrıca çalışma zamanında hataların nasıl ele alınacağı konusunda size daha fazla kontrol sağlar.

Bu ilgili soruların birçok önerisi var:


8
Debug () 'a debugonce () de ekleyebilirsiniz.
Joris Meys

2
Düzeltme (df1), yalnızca hata ayıklama sırasında yararlı olmasa da, grafiksel R Editörünü, içinde yüklenen df1 veri çerçevesi ile açar ve bu, anında düzenleyebilir veya sadece bir göz atabilirsiniz.
Dmitrii I.

R'de hata ayıklama çok zor görünüyor, örneğin uyarıların kod satırlarını görmenin kolay bir çözümü yok
TMS

browser()uyarıları / hataları tetiklemeyen hatalar olduğunda (kaynak: bu sayfada Roman Luštrik). Gibi başka bir araç var browser()mı?
PatrickT


32

As içinde bana işaret edildi başka soruya , Rprof()ve summaryRprof()güzel araçlardır programın yavaş bölümlerini bulmak o hızlandırmak ya da C / C ++ uygulanmasına hareket etmesini kudreti yarar. Simülasyon çalışması veya diğer bilgi işlem veya veri yoğun etkinlikler yapıyorsanız, bu muhtemelen daha fazla geçerlidir. profrPaket sonuçları görselleştirme yardımcı olabilir.

Hata ayıklama konusunda biraz bilgi edindim, bu yüzden başka bir ileti dizisinden başka bir öneri :

  • options(warn=2)Uyarıları hata gibi ele almak için ayarlayın

Ayrıca options, tercih ettiğiniz hata ayıklama işlevini kullanarak, bir hata veya uyarı oluştuğunda sizi eylemin tam ortasında bırakmak için de kullanabilirsiniz . Örneğin:

  • Shane'in belirttiği gibi (ve R hata ayıklama kılavuzunda belgelendiği gibi . Veya çalıştırmayı yararlı bulacağınız diğer kullanışlı işlevler) bir hata oluştuğunda options(error=recover)çalışacak şekilde ayarlayın .recover()

Ve @ Shane'in bağlantılarından birinden iki yöntem daha :

  • Hakkında try()daha fazla bilgi döndürmek için bir iç işlev çağrısını sarın .
  • * Uygulama işlevleri .inform=TRUEiçin, uygulama komutuna bir seçenek olarak (plyr paketinden) kullanın

@JoshuaUlrich ayrıcabrowser() , hata ayıklamayı açmak / kapatmak için klasik komutun koşullu yeteneklerini kullanmanın düzgün bir yolunu belirtti :

  • Hata ayıklamak isteyebileceğiniz işlevin içine koyun browser(expr=isTRUE(getOption("myDebug")))
  • Ve genel seçeneği şu şekilde ayarlayın: options(myDebug=TRUE)
  • Hatta tarayıcı çağrısını sarmalayabilir myBrowse <- browser(expr=isTRUE(getOption("myDebug")))ve ardından myBrowse()globalleri kullandığı için ile çağrı yapabilirsiniz .

Sonra R 2.10'da mevcut olan yeni işlevler vardır:

  • findLineNum()bir kaynak dosya adını ve satır numarasını alır ve işlevi ve ortamı döndürür. source()Bir .R dosyası oluşturduğunuzda ve #n satırında bir hata döndürdüğünde bu yardımcı olur , ancak #n satırında hangi işlevin bulunduğunu bilmeniz gerekir.
  • setBreakpoint() bir kaynak dosya adı ve satır numarası alır ve orada bir kesme noktası ayarlar

Codetools paketi ve özellikle checkUsagefonksiyon hızla sözdizimi ve derleyici tipik rapor edeceğini üslup hataları toplayıp (kullanılmayan halk, genel işlevler ve değişkenler, kısmi argüman eşleştirmeyi tanımsız ve benzeri) özellikle yararlı olabilir.

setBreakpoint()daha kullanıcı dostu bir ön uçtur trace(). Bunun nasıl çalıştığına dair dahili bilgilerle ilgili ayrıntılar yakın tarihli bir R Journal makalesinde mevcuttur .

Başka birinin paketinde hata ayıklamaya çalışıyorsanız, sorunu bulduğunuzda, işlevlerinin üzerine fixInNamespaceve ile yazabilirsinizassignInNamespace , ancak bunu üretim kodunda kullanmayın.

Bunların hiçbiri denenmiş ve doğrulanmış standart R hata ayıklama araçlarını engellememelidir; bunlardan bazıları yukarıda, bazıları ise değildir. Özellikle, ölüm sonrası hata ayıklama araçları , yeniden çalıştırmayı tercih etmediğiniz, zaman alan bir kod grubunuz olduğunda kullanışlıdır.

Son olarak, bir hata mesajı vermeyen zorlu problemler için options(error=dump.frames), bu soruda ayrıntılı olarak açıklanan şekilde kullanabilirsiniz : Hata atılmadan hata


1
Bu soruları bir araya getirmek ve ardından açık tutmak için harcadığınız tüm çalışmalar için +1!
GSee

29

Bir noktada glm.fitçağrılıyor. Bu, çağırdığınız işlevlerden birinin veya bu işlevler tarafından çağrılan işlevlerden birinin glm, ikisinden birini kullandığı anlamına gelir glm.fit.

Ayrıca yukarıdaki yorumumda da bahsettiğim gibi bu büyük bir fark yaratan hata değil uyarıdır . R'nin hata ayıklama araçlarından herhangi birini bir uyarıdan tetikleyemezsiniz (biri bana hatalı olduğumu söylemeden önce varsayılan seçeneklerle ;-).

Uyarıları hatalara dönüştürmek için seçenekleri değiştirirsek, R'nin hata ayıklama araçlarını kullanmaya başlayabiliriz. Gönderen ?optionsbiz var:

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

Yani koşarsan

options(warn = 2)

sonra kodunuzu çalıştırın, R bir hata atacaktır. Hangi noktada koşabilirsin

traceback()

çağrı yığınını görmek için. İşte bir örnek.

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

Burada işaretlenmiş 4:ve daha yüksek çerçeveleri göz ardı edebilirsiniz . Bunun fooçağrıldığını barve baruyarıyı oluşturduğunu görüyoruz . Bu size hangi fonksiyonların çağırdığını göstermelidir glm.fit.

Şimdi bunu hata ayıklamak istiyorsanız, başka bir seçeneğe dönerek R'ye bir hatayla karşılaştığında hata ayıklayıcıyı girmesini söyleyebiliriz ve uyarı hataları yaptığımızda, orijinal uyarı tetiklendiğinde bir hata ayıklayıcı alacağız. Bunun için koşmalısınız:

options(error = recover)

İşte bir örnek:

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

Daha sonra, uyarı atıldığında ne olduğunu görmek için bu çerçevelerden herhangi birine adım atabilirsiniz.

Yukarıdaki seçenekleri varsayılan değerlerine sıfırlamak için şunu girin:

options(error = NULL, warn = 0)

Alıntı yaptığınız özel uyarıya gelince, büyük olasılıkla kodda daha fazla yinelemeye izin vermeniz gerekir. Neyin çağrıldığını anladıktan sonra glm.fit, controlargümanı kullanarak onu nasıl geçireceğinizi bulun glm.control- bkz ?glm.control.


4
mükemmel cevap. karamsarlığın bir notu, bu tür yakınsama hatalarının genellikle dengesiz / bozuk veri kümelerinde (tam ayrılma vb.) ortaya çıkması ve 'yakınsak' ve 'yakınsak olmayan' arasındaki pencerenin sayıları artırarak düzeltilemeyeceğidir. yinelemelerin sayısı - biraz daha büyük bir değişiklik gerekiyor 'genellikle dar
Ben Bolker

3
Gavin, seni 25 saniye geride bıraktım. Aşırı yardımcı cevabınızı kaldırmanızı ve oylarımı çalmayı bırakmanızı talep ediyorum. ;-)
Joshua Ulrich

@Ben harika bir nokta. David'in sorunu ayrılıksa, yinelemelerin sayısını artırmak yardımcı olmamalı, yine de bir araya gelememelidir. Bu noktada tahminlere ve standart hatalara bakmak bir sorun olduğunu gösterebilir. Ayırma veya benzeri bir sorun olsaydı, sayısal olarak 0 veya 1 olarak takılan değerler hakkında uyarı görmeyi beklerdim. Yineleme sayısını artırmak işe yaramazsa, David yardım için başka bir Q gönderebilir ve ben @ Joshua'nın olumlu oylarından daha fazlasını çalabilirim ;-)
Gavin Simpson

1
@Joshua, onu yenmenin bir yolu yok. Onun yüzünden kaybetmiş olabileceğim olumlu oyları saymayı bıraktım. Ama yine de sağladığı yardım, bunu açık ara açıklıyor. Onu yenersen kendi nişlerini bulmalısın. Burada tuş vuruşu başına olumlu oylar öneriyorum ... :)
Matt Bannert

1
Kahretsin @ ran2, dünyayı ele geçirmek için alçakça , aldatıcı planımı bozdun, Mwahahahahaha !!!!
Gavin Simpson

21

Yani browser(), traceback()ve debug()bir bara girer, ancak trace()beklediği dışında ve motoru çalışır tutar.

browserİşlevinizde bir yere eklediğinizde , yürütme durur ve girişinizi bekler. Sen kullanarak ileriye taşıyabilir n(veya Enter), ile tüm yığın (yineleme) çalıştırın c, ile akım döngüsü / fonksiyonu bitirmek fveya birlikte çıkın Q; bakın ?browser.

İle debug, tarayıcı ile aynı etkiyi elde edersiniz, ancak bu, bir işlevin başlangıcında çalışmasını durdurur. Aynı kısayollar geçerlidir. Bu işlevi kullanarak kapatana kadar bir "hata ayıklama" modunda olacaktır undebug(yani debug(foo), çalıştırıldıktan sonra , çalıştırılana kadar işlev fooher seferinde "hata ayıklama" moduna girecektir undebug(foo)).

Daha geçici bir alternatif, bir debugoncedahaki sefere değerlendirildikten sonra işlevden "hata ayıklama" modunu kaldıracaktır.

traceback size bir şeylerin ters gittiği yere kadar (gerçek bir hata) kadar fonksiyonların yürütme akışını verecektir.

traceÖrneğin, işlevlerine kod bitleri (yani özel işlevler) ekleyebilirsiniz browser. Bu, paketlerdeki işlevler için kullanışlıdır ve güzel bir şekilde katlanmış kaynak kodunu elde edemeyecek kadar tembelsiniz.


18

Genel stratejim şöyle görünüyor:

  1. traceback()Belirgin sorunları aramak için çalıştırın
  2. options(warn=2)Uyarıları hata gibi ele almak için ayarlayın
  3. options(error=recover)Hata durumunda çağrı yığınına adım atmak için ayarlayın

15

Tüm boyunca burada önerilen adımları gittikten sonra ben sadece ayar öğrendim .verbose = TRUEde foreach()aynı zamanda bana yararlı bilgiler ton verir. Özellikle foreach(.verbose=TRUE)foreach döngüsünün içinde tam olarak nerede bir hata oluştuğunu gösterirken, foreach döngüsünün traceback()içine bakmaz.


13

Mark Bravington'ın CRAN'daki paket olarak mevcut olan hata ayıklayıcısı debugçok iyi ve oldukça basittir.

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, vurgulanmış bir Tk penceresinde açılır, böylece neler olup bittiğini görebilir ve elbette mtrace()farklı bir işlevdeyken başka birini arayabilirsiniz .

HTH


11

Gavin'in cevabını beğendim: Seçenekleri bilmiyordum (hata = kurtarma). Ayrıca, kodunuzda ilerlemeniz için görsel bir yol sunan 'hata ayıklama' paketini kullanmayı seviyorum.

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

Bu noktada, kodun neresinde olduğunuzu gösteren sarı bir çizgi ile fonksiyonunuzu gösteren ayrı bir hata ayıklama penceresi açar. Ana pencerede kod hata ayıklama moduna girer ve kodda ilerlemek için enter tuşuna basmaya devam edebilirsiniz (ve başka komutlar da vardır) ve değişken değerleri inceleyebilirsiniz. Hata ayıklama penceresindeki sarı çizgi nerede olduğunu göstermek için hareket etmeye devam eder. kodun içindesin. Hata ayıklama ile bittiğinde, izlemeyi şu şekilde kapatabilirsiniz:

mtrace.off()

5

Burada aldığım cevaba göre , options(error=recover)ayarı kesinlikle kontrol etmelisiniz . Bu ayarlandığında, bir hatayla karşılaştığınızda, konsolda aşağıdakine benzer bir metin göreceksiniz ( tracebackçıktı):

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

Hangi noktada hangi "çerçevenin" girileceğini seçebilirsiniz. Bir seçim yaptığınızda, browser()moda alınacaksınız :

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

Ve çevreyi hata anında olduğu gibi inceleyebilirsiniz. Bitirdiğinizde, sizi cçerçeve seçim menüsüne geri getirmek için yazın. Bitirdiğinizde, size söylediği gibi 0çıkmak için yazın.


4

Bu cevabı daha yeni bir soruya verdim , ancak eksiksiz olması için buraya ekliyorum.

Şahsen ben hata ayıklamak için işlevler kullanmıyorum. Sık sık bunun çözdüğü kadar sorun yarattığını görüyorum. Ayrıca, bir Matlab geçmişinden geldiğimde, bunu kodda yapmaktansa entegre bir geliştirme ortamında (IDE) yapabilmeyi seviyorum. IDE kullanmak, kodunuzu temiz ve basit tutar.

R için, Windows, mac ve linux için mevcut olan ve kullanımı oldukça kolay olan "RStudio" ( http://www.rstudio.com ) adlı bir IDE kullanıyorum.

Yaklaşık Ekim 2013'ten beri Rstudio'nun sürümleri (0.98ish?), Komut dosyalarına ve işlevlere kesme noktaları ekleme yeteneğine sahiptir: Bunu yapmak için, bir kesme noktası eklemek için dosyanın sol kenar boşluğunu tıklamanız yeterlidir. Bir kesme noktası belirleyebilir ve ardından bu noktadan sonra adım atabilirsiniz. Ayrıca bu ortamdaki tüm verilere erişiminiz vardır, böylece komutları deneyebilirsiniz.

Ayrıntılar için http://www.rstudio.com/ide/docs/debugging/overview adresine bakın. Zaten Rstudio yüklediyseniz, yükseltmeniz gerekebilir - bu nispeten yeni (2013 sonu) bir özelliktir.

Benzer işlevlere sahip başka IDE'ler de bulabilirsiniz.

Kuşkusuz, bu yerleşik bir işlevse, bu tartışmada başkaları tarafından yapılan önerilerin bazılarına başvurmanız gerekebilir. Ancak, düzeltilmesi gereken kendi kodunuzsa, IDE tabanlı bir çözüm tam da ihtiyacınız olan şey olabilir.


1

Örnek başvurusu olmadan Referans Sınıfı yöntemlerinde hata ayıklamak için

ClassName$trace(methodName, browser)

0

En temel gereklilik olan - DEFAILT TARAFINDAN - hata satır numarasını yazdırmamanın R / Rstudio'da bir tür şaka olduğunu düşünmeye başlıyorum . Bir hatanın nerede oluştuğunu bulmak için bulduğum tek güvenilir yöntem, traceback () çağırmak için ek çaba sarf etmek ve en üst satırı görmektir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.