2013-05-17 27 views
31

data.table to fantastyczny pakiet R i używam go w bibliotece, którą tworzę. Jak dotąd wszystko idzie bardzo dobrze, z wyjątkiem jednej komplikacji. Wydaje się, że jest o wiele trudniejsze (w porównaniu z konwencjonalnymi ramkami danych) odnoszenie się do kolumn data.table przy użyciu nazw zapisanych w zmiennych (tak jak w przypadku ramek danych, na przykład: colname="col"; df[df[,colname]<5,colname]=0).Odwołując się do kolumn data.table według nazw zapisanych w zmiennych

Być może najbardziej komplikuje to oczywisty brak spójności składni na tym w data.table. W niektórych przypadkach wydaje się, że działają eval(colname) i get(colname), a nawet c(colname). W innych rozwiązaniach jest DT[,colname, with=F]. Jednak w innych, takich jak na przykład funkcje set() i subset(), nie znalazłem żadnego rozwiązania. Wreszcie, skrajny, choć dość powszechny przypadek użycia został omówiony wcześniej (passing column names to data.table programmatically), a proponowane rozwiązania, choć najwyraźniej wykonujące swoją pracę, nie wydawały się szczególnie czytelne ...

Może komplikuję zbyt wiele rzeczy? Jeśli ktokolwiek mógłby napisać krótki kod do odnoszenia się do nazw kolumn data.table za pomocą zmiennych dla różnych typowych scenariuszy, byłbym bardzo wdzięczny.

UPDATE:

Niektóre konkretne przykłady, że prace wymienione mogę nazwy kolumn ciężko kod:

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

Teraz zakładamy distcol="dist", valcol="val". Jaki jest najlepszy sposób na wykonanie powyższych czynności przy użyciu distcol i valcol, ale nie dist i val?

+0

To pytanie wydaje się zbyt mało precyzyjne. Może być poprawiony, jeśli oferujesz określone przypadki testowe. –

+0

OK, przeniesie przykłady z dyskusji poniżej na samo pytanie. – msp

Odpowiedz

17

Jeśli zamierzasz robić skomplikowanych operacji wewnątrz firmy j wyrażeń, powinieneś użyć eval i quote. Jednym z problemów z obecną wersją data.table jest to, że środowisko eval nie zawsze jest poprawnie przetwarzane - eval and quote in data.table (Uwaga: Zaktualizowano tę odpowiedź na podstawie aktualizacji pakietu.) - i obecna poprawka do tego jest aby dodać .SD do eval. O ile mogę powiedzieć z kilku testów, które przeprowadziłem, nie ma to wpływu na szybkość (sposób, na przykład, gdyby miał .SD[1] w j).

Co ciekawe ten problem plag tylko j i wszystko będzie w porządku za pomocą eval normalnie i (gdzie .SD nie jest dostępny w każdym razie).

Innym problemem jest przydział i tam musisz mieć łańcuchy. Znam jeden sposób na wyodrębnienie nazwy ciągu z cytowanego wyrażenia - nie jest ładny, ale działa. Oto przykład łącząc wszystko razem:

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

Uwaga jak ja było ok nie dodając .SD w jednym eval(distcol), ale nie będzie, jeśli wezmę go z drugiej eval.

Inną opcją jest użycie get:

diststr = "dist" 
valstr = "val" 

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

Wielkie dzięki za wyjaśnienie. Jednak jak wspomniałem w moim komentarzu do @Frank powyżej, moim problemem jest użycie 'quote (dist)' i 'quote (val)'. W moim przypadku nie mam do nich dostępu, tylko do zmiennych 'distcol =" dist "' i 'valcol =" val "'. Czy jest na to jakieś rozwiązanie? – msp

+1

Możesz przejść w drugą stronę, jak sądzę, od napisu do "cytatu". – Frank

+0

@msp dodano do tego wersję - działa na ten prosty przykład, ale spodziewaj się kłopotów z wyprzedzeniem :) – eddi

6

Być może już wiesz o tym rozwiązaniu?

DT[[colname]] 

To jest inspirowana przez @ Eddi na rozwiązanie w komentarzach poniżej, za pomocą przykładu PO w:

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

Dzięki, rzeczywiście, ale nie zawsze działa - "set()" i "podzbiór()" są przykładami - i nie wiem, czy kiedy to robi, a kiedy nie ... – msp

+1

W porządku, 'set' i' subset' są poza tym, czego normalnie używam. Wiem, że są pewne pytania na SO dotyczące używania 'quote' i' eval'; te mogą pomóc ... – Frank

+0

Zastanawiam się, czego używasz zamiast tych funkcji - może powinienem też zrobić. Na przykład w tych przypadkach: 'x.short = podzbiór (x, abs (dist) <= 100); set (x, which (x $ val <10), "val", 0) '. Załóżmy 'distcol =" dist ", valcol =" val "'. Czy wiesz, jak je podłączyć? Dzięki! – msp

3

Powiedzmy, że masz nazwę kolumny w zmiennej x, można zrobić

colname = as.name(x) 

można użyć colname w funkcji subset

+1

Świetnie, dzięki za to! – msp

+0

To nie działa dla mnie w data.table. Może robi to w funkcji podzbioru, o której wspomniałeś? Jeśli działa również w tabelach danych, czy mógłby podać przykład? –

Powiązane problemy