2014-05-09 12 views
9

Se si desidera eseguire la ricerca di una funzione per un errore o un avviso, si verifica qualcosa di strano se l'argomento viene convertito in un data.table all'interno del funzione:deparse (sostituto()) all'interno della funzione utilizzando data.table come argomento

e <- data.frame(x = 1:10) 
### something strange is happening 
foo <- function(u) { 
    u <- data.table(u) 
    warning(deparse(substitute(u)), " is not a data.table") 
    u 
} 
foo(e) 

## foo(e) 
##  x 
## 1: 1 
## 2: 2 
## 3: 3 
## 4: 4 
## 5: 5 
## 6: 6 
## 7: 7 
## 8: 8 
## 9: 9 
## 10: 10 
## Warning message: 
## In foo(e) : 
## structure(list(x = 1:10), .Names = "x", row.names = c(NA, -10L), class = c("data.table", "data.frame"), .internal.selfref = <pointer: 0x10026568>) is not a data.table 

Se ho Deparse prima data.table tutto funziona benissimo:

### ok 
foo1 <- function(u) { 
    nu <- deparse(substitute(u)) 
    u <- data.table(u) 
    warning(nu, " is not a data.table") 
    u 
} 
## foo1(e) 
##  x 
## 1: 1 
## 2: 2 
## 3: 3 
## 4: 4 
## 5: 5 
## 6: 6 
## 7: 7 
## 8: 8 
## 9: 9 
## 10: 10 
## Warning message: 
## In foo1(e) : e is not a data.table 

C'è tra l'altro alcuna differenza se e già è un data.table o nessuna t. L'ho trovato apposta, quando stavo creando un codice, dove deparse richiedeva molto tempo perché e era piuttosto grande.

Cosa sta succedendo qui e come posso gestire tali funzioni per l'ingresso data.frame e data.table?

nachti

risposta

10

Questo perché substitute si comporta in modo diverso quando si tratta di una variabile normale invece di un oggetto promessa. Un oggetto promessa è un argomento formale e ha uno slot speciale che contiene l'espressione che lo ha generato. In altre parole, un oggetto promessa è una variabile in una funzione che fa parte dell'elenco di argomenti di quella funzione. Quando si utilizza substitute su un oggetto promessa in una funzione, esso recupera l'espressione nella chiamata alla funzione assegnata a tale argomento formale. Da ?substitute:

Sostituzione avviene esaminando ogni componente del albero di analisi come segue: Se non si tratta di un simbolo legato in env, è immutato. Se è un oggetto promessa, ovvero un argomento formale a una funzione o creato in modo esplicito utilizzando delayedAssign(), , lo slot di espressione della promessa sostituisce il simbolo. Se è una variabile ordinaria, il suo valore è sostituito da, a meno che env sia .GlobalEnv, nel qual caso il simbolo rimane invariato.

Nel tuo caso, in realtà si sovrascrive la variabile promessa originale con uno nuovo con:

u <- data.table(u) 

a quel punto u diventa una variabile normale che contiene una tabella di dati. Quando si substitute su u dopo questo punto, substitute restituisce semplicemente la tabella di dati, che deparse restituisce al linguaggio R che lo genererebbe, motivo per cui è lento.

Questo spiega anche perché il tuo secondo esempio funziona. Si substitute mentre la variabile è ancora una promessa (vale a dire prima di sovrascrivere u). Questa è anche la risposta alla tua seconda domanda. O sostituisci prima di sovrascrivere la tua promessa, o non sovrascrivere la tua promessa.

Per maggiori dettagli, si veda section 2.1.8 della definizione R Lingua (promesse) che ho estratto qui: oggetti

promessa fanno parte del meccanismo di valutazione pigra di R. Contengono tre slot: un valore, un'espressione e un ambiente.Quando viene chiamata una funzione, gli argomenti vengono confrontati e quindi ciascuno degli argomenti formali è vincolato a una promessa. L'espressione che è stata data per quell'argomento formale e un puntatore all'ambiente in cui la funzione è stata chiamata da è memorizzata nella promessa.

+0

@nachti, non risponde alla tua domanda? – BrodieG

+0

@ [BrodieG] (http://stackoverflow.com/users/2725969/brodieg): Grazie per la risposta. Come scritto sopra: come posso gestire tali funzioni per l'input 'data.frame' e' data.table'? Dovrei copiarlo (ha bisogno di molto spazio)? O prima spargere tutto e poi sovrascriverlo? – nachti

+1

@nachti, quest'ultimo, prima scarso. Inoltre, se vuoi evitare le copie dovresti prendere in considerazione l'uso di 'setDT' invece di' data.table'. Il primo crea una tabella di dati per riferimento. – BrodieG

0

Si potrebbe probabilmente fare questo anche con sprintf, insieme a is.data.table.

> e <- data.frame(x = 1:10) 
> foo <- function(u){ 
     nu <- deparse(substitute(u)) 
     if(!is.data.table(u)){ 
      warning(sprintf('%s is not a data table', nu)) 
      u 
     } else { 
      u 
     } 
    } 
> foo(e) 
    x 
1 1 
2 2 
3 3 
4 4 
5 5 
6 6 
7 7 
8 8 
9 9 
10 10 
Warning message: 
In foo(e) : e is not a data table 
+0

Grazie per le vostre risposte! @Richard: Buona idea, ma poi NON è ancora un data.table e non posso usare ': =' per esempio. Dovrebbe essere usato all'interno di una funzione, che accetta un 'data.frame' o un' data.table' come input, fa qualcosa nella sintassi 'data.table' e lo converte in un' data.frame' se l'input era uno. BTW 'u' è grande (~ 250 MB) – nachti

Problemi correlati