2013-05-17 3 views
31

data.table è un fantastico pacchetto R e lo sto utilizzando in una libreria che sto sviluppando. Finora tutto sta andando molto bene, tranne una complicazione. Sembra essere molto più difficile (rispetto ai frame dati convenzionali) fare riferimento alle colonne data.table utilizzando nomi salvati in variabili (come per i frame di dati, ad esempio: colname="col"; df[df[,colname]<5,colname]=0).Fare riferimento alle colonne data.table per nome salvato nelle variabili

Forse ciò che complica maggiormente le cose è l'apparente mancanza di coerenza della sintassi su questo in data.table. In alcuni casi, eval(colname) e get(colname) o anche c(colname) sembrano funzionare. In altri, DT[,colname, with=F] è la soluzione. Tuttavia in altri, come ad esempio le funzioni set() e subset(), non ho trovato alcuna soluzione. Infine, un caso di uso estremo, anche se abbastanza comune, è stato discusso in precedenza (passing column names to data.table programmatically) e le soluzioni proposte, anche se apparentemente facendo il loro lavoro, non sembravano particolarmente leggibili ...

Forse sto complicando troppo le cose? Se qualcuno potesse buttare giù un rapido cheatsheet per fare riferimento ai nomi delle colonne data.table usando le variabili per diversi scenari comuni, sarei molto grato.

UPDATE:

Alcuni esempi specifici che lavoro messe a disposizione posso nomi delle colonne codificare:

x.short = subset(x, abs(dist)<=100) 
set(x, which(x$val<10), "val", 0) 

Ora assumere distcol="dist", valcol="val". Qual è il modo migliore per fare quanto sopra utilizzando distcol e valcol, ma non dist e val?

+0

Questa domanda sembra troppo incerta. Potrebbe essere migliorato se offri casi di test specifici. –

+0

OK, trasferirà gli esempi dalla discussione in basso alla domanda stessa. – msp

risposta

17

Se avete intenzione di fare operazioni complicate all'interno del vostro j espressioni, probabilmente si dovrebbe usare eval e quote. Un problema con questo nella versione corrente di data.table è che l'ambiente di eval non viene sempre elaborato correttamente - eval and quote in data.table (Nota: c'è stato un aggiornamento a tale risposta in base ad un aggiornamento del pacchetto.) - e la correzione corrente per questo è aggiungere .SD a eval. Per quanto posso dire da alcuni test che ho eseguito ciò non influisce sulla velocità (il modo in cui, ad esempio, avere .SD[1] in j).

È interessante notare che questo problema affligge solo il j e andrà tutto bene utilizzando eval normalmente in i (dove .SD non è disponibile in ogni caso).

L'altro problema è l'assegnazione e ci sono stringhe. Conosco un modo per estrarre il nome della stringa da un'espressione quotata: non è carina, ma funziona. Ecco un esempio che combina tutto insieme:

x = data.table(dist = c(1:10), val = c(1:10)) 
distcol = quote(dist) 
valcol = quote(val) 

x[eval(valcol) < 5, 
    capture.output(str(distcol, give.head = F)) := eval(distcol)*sum(eval(distcol, .SD))] 

Nota come mi era ok non aggiungendo .SD in una eval(distcol), ma non sarà se lo prendo fuori l'altro eval.

Un'altra opzione è quella di utilizzare get:

diststr = "dist" 
valstr = "val" 

x[get(valstr) < 5, c(diststr) := get(diststr)*sum(get(diststr))] 
+0

Grazie mille per la spiegazione. Comunque, come ho detto nel mio commento a @Frank sopra, il mio problema è con l'uso di 'quote (dist)' e 'quote (val)'. Nel mio caso non ho accesso a questi, solo alle variabili 'distcol =" dist "' e 'valcol =" val "'. C'è una soluzione per questo? – msp

+1

Si può andare dall'altra parte, immagino, da una stringa a 'quote'-cosa. – Frank

+0

@msp ha aggiunto una versione per questo - funziona per questo semplice esempio, ma si aspetta un problema in anticipo :) – eddi

6

Forse conosci già questa soluzione?

DT[[colname]] 

presenta un design ispirato @ Eddi della soluzione nei commenti qui sotto, usando l'esempio del PO:

set.seed(1) 
x = data.table(a = 1:10, b=rnorm(10)) 
colstr="b" 
col <- eval(parse(text=paste("quote(",colstr,")",sep=""))) 
x[eval(col)<0] 
x[eval(col)<0,c(colstr):=-100] 
+0

Grazie, faccio in realtà, ma non sempre funziona - 'set()' e 'sottoinsieme()' che sono esempi - e quello che non so se quando lo fa e quando non lo fa ... – msp

+1

Ok, 'set' e' subset' sono al di fuori di quello che uso normalmente. So che ci sono alcune domande su SO sull'uso di 'quote' e' eval'; quelli potrebbero aiutare ... – Frank

+0

Mi chiedo che cosa usi invece di queste funzioni - forse dovrei fare anche io. Ad esempio, in questi casi: 'x.short = sottoinsieme (x, abs (dist) <= 100); set (x, which (x $ val <10), "val", 0) '. Assumi 'distcol =" dist ", valcol =" val "'. Sapresti come collegarli? Grazie! – msp

3

Diciamo che avete il nome della colonna nella variabile x, si potrebbe fare

colname = as.name(x) 

è quindi possibile utilizzare colname nella funzione subset

+1

Grande, grazie per questo! – msp

+0

Questo non ha funzionato per me in un data.table. Forse lo fa nella funzione sottoinsieme che menzioni? Se funziona anche in data.tables, potresti fare un esempio? –