C'è un flag di debugging condizionale che mi manca da Matlab: dbstop if infnan
described here. Se impostato, questa condizione interromperà l'esecuzione del codice quando viene rilevato un Inf
o NaN
(IIRC, Matlab non ha NA).Come forzare un errore se si incontrano valori non finiti (NA, NaN o Inf)
Come posso ottenere questo risultato in R in un modo più efficiente rispetto al test di tutti gli oggetti dopo ogni operazione di assegnazione?
Al momento, gli unici modi che vedo per farlo sono via hack come la seguente:
- inserire manualmente un test, dopo tutti i luoghi dove si possono incontrare questi valori (ad esempio, una divisione, dove la divisione per 0 potrebbe verificarsi). Il test sarebbe quello di utilizzare
is.finite()
, described in this Q & A, su ogni elemento. - Utilizzare
body()
per modificare il codice per chiamare una funzione separata, dopo ogni operazione o eventualmente solo ogni assegnazione, che verifica tutti gli oggetti (e possibilmente tutti gli oggetti in tutti gli ambienti). - Modificare il codice sorgente di R (?!?)
- Tentativo di utilizzare
tracemem
per identificare le variabili che sono state modificate e controllare solo queste per valori errati. - (Nuovo - vedere nota 2) Utilizzare un tipo di gestori di chiamata/callback per richiamare una funzione di test.
La prima opzione è ciò che sto facendo al momento. Questo è noioso, perché non posso garantire di aver controllato tutto. La seconda opzione testerà tutto, anche se un oggetto non è stato aggiornato. Questa è una grande perdita di tempo. La terza opzione comporterebbe la modifica di assegnamenti di NA, NaN e valori infiniti (+/- Inf), in modo che venga generato un errore. Sembra che sia meglio lasciarlo a R Core. La quarta opzione è come la seconda: mi occorrerebbe una chiamata a una funzione separata che elenca tutte le posizioni di memoria, solo per identificare quelli che sono cambiati e quindi controllare i valori; Non sono nemmeno sicuro che funzionerà per tutti gli oggetti, poiché un programma potrebbe eseguire una modifica sul posto, il che sembra non richiamare la funzione duplicate
.
C'è un approccio migliore che mi manca? Forse uno strumento intelligente di Mark Bravington, Luke Tierney o qualcosa di relativamente semplice - qualcosa di simile a un parametro options()
o un flag durante la compilazione di R?
Esempio di codice Ecco un esempio di codice molto semplice da testare, che incorpora la funzione addTaskCallback
proposta da Josh O'Brien. Il codice non viene interrotto, ma si verifica un errore nel primo scenario, mentre nel secondo caso non si verifica alcun errore (ad esempio, badDiv(0,0,FALSE)
non si interrompe). Sto ancora indagando sui callback, visto che sembra promettente.
badDiv <- function(x, y, flag){
z = x/y
if(flag == TRUE){
return(z)
} else {
return(FALSE)
}
}
addTaskCallback(stopOnNaNs)
badDiv(0, 0, TRUE)
addTaskCallback(stopOnNaNs)
badDiv(0, 0, FALSE)
Nota 1. Sarei soddisfatto con una soluzione per operazioni standard R, anche se molti miei calcoli coinvolgono oggetti usati tramite data.table
o bigmemory
(cioè memoria su disco matrici mappati). Questi sembrano avere comportamenti di memoria un po 'diversi rispetto alle operazioni standard matrix e data.frame.
Nota 2. L'idea dei callback sembra un po 'più promettente, in quanto ciò non richiede che io scriva funzioni che mutino il codice R, ad es. tramite l'idea body()
.
Nota 3.Non so se ci sia o meno un modo semplice per verificare la presenza di valori non finiti, ad es. meta informazioni sugli oggetti che indicizza dove NAs, Infs, ecc. sono memorizzati nell'oggetto o se questi sono memorizzati sul posto. Finora, ho provato il pacchetto inspect
di Simon Urbanek e non ho trovato un modo per indovinare la presenza di valori non numerici.
Follow-up: Simon Urbanek ha sottolineato in un commento che tali informazioni non sono disponibili come meta per gli oggetti.
Nota 4. Sto ancora testando le idee presentate. Inoltre, come suggerito da Simon, il test per la presenza di valori non finiti dovrebbe essere il più veloce in C/C++; che dovrebbe superare anche il codice R compilato, ma sono aperto a qualsiasi cosa. Per set di dati di grandi dimensioni, ad es. dell'ordine di 10-50 GB, questo dovrebbe essere un notevole risparmio rispetto alla copia dei dati. Si possono ottenere ulteriori miglioramenti tramite l'uso di più core, ma questo è un po 'più avanzato.
Alcune delle funzioni primitive hanno questa funzionalità built-in, cioè, restituiscono un errore o di un avviso se in dotazione o consegnare un non -punto finito Prendi, 'sin (Inf)' per esempio. Forse è qualcosa che potresti esplorare. –
Beh, non è sempre il caso che un Inf o un NaN * debbano * interrompere la tua funzione/codice (NA è un caso a parte perché è deliberatamente usato sempre come "riempitivo" o "marcatore"). Eseguo spesso alcune operazioni che producono alcuni valori Inf, diciamo nelle regioni a basso segnale di alcune matrici. Sospetto che otterrai informazioni migliori usando 'is.infinite' e/o' is.nan' su variabili sospette comunque. –
@CarlWitthoft Nello scenario di codice + dati su cui sto lavorando attualmente, i valori dei problemi sono precisamente quelli tre: NA, NaN e Infs. In altri casi, ho sicuramente bisogno di NA, ma non oggi. :) Ho bisogno del codice per abortire (è piuttosto costoso dal punto di vista computazionale, b/c del volume di dati) non appena questi si verificano. Quindi, la ragione per cui mi piacerebbe davvero innescare un errore (o almeno un avvertimento). – Iterator