2013-05-22 13 views
7

Staram się osiągnąć to samo, co dlply z data.table. Więc po prostu jako bardzo prosty przykład:Równoważne dla dlply w data.table

library(plyr) 
library(data.table) 
dt <- data.table(p = c("A", "B"), q = 1:2) 

dlply(dt, "p", identity) 
$A 
    p q 
1 A 1 

$B 
    p q 
1 B 2 

dt[ , identity(.SD), by = p ] 
    p q 
1: A 1 
2: B 2 

foo <- function(x) as.list(x) 
dt[ , foo(.SD), by = p ] 
    p q 
1: A 1 
2: B 2 

Oczywiście wartości powrotne foo są zwinięte do jednego data.table. I nie chcę używać dlply, ponieważ przekazuje on podzbiór data.tables jako data.frames do foo, co powoduje, że dalsze operacje w tabelach danych w zakresie foo są niewydajne.

+1

plyr jest oddzielny pakiet, który służy do konwersji pomiędzy różnymi strukturami danych z łatwość. data.table jest zaimplementowana jako wydajna/rozszerzona data.frame. To jest jego jedyny cel. Więc nie ma na to żadnej skutecznej metody wewnętrznej. To, co już pokazałeś (lapply), jest tym, co można zrobić. – Arun

+2

Dlaczego chcesz podzielić plik data.table? Jest to niezgodne z celem użycia data.table (lepsza wydajność dzięki unikaniu kopii). – Roland

+0

@Roland Całkowicie się zgadzam. Może mój przykład nie był wystarczająco jasny. Co naprawdę chcę zrobić, to wykonywanie w serii podzbiorów data.table pewnych operacji, które konstruują w końcu nowe obiekty 'ReferenceClasses', które chcę zwrócić jako listę. – Beasterfield

Odpowiedz

3

Oto bardziej zorientowane podejście data.table:

setkey(dt, p) 
dt[, list(list(dt[J(.BY[[1]])])), by = p]$V1 
#[[1]] 
# p q 
#1: A 1 
# 
#[[2]] 
# p q 
#1: B 2 

Istnieje więcej data.table alternatywne style do powyższego, ale to wydaje się być najszybszy - oto porównanie z lapply:

dt <- data.table(p = rep(LETTERS[1:25], 1E6), q = 25*1E6, key = "p") 
microbenchmark(dt[, list(list(dt[J(.BY[[1]])])), by = p]$V1, lapply(unique(dt$p), function(x) dt[x]), times = 10) 
#Unit: seconds 
#          expr  min  lq median  uq  max neval 
#dt[, list(list(dt[J(.BY[[1]])])), by = p]$V1 1.111385 1.508594 1.717357 1.966694 2.108188 10 
#  lapply(unique(dt$p), function(x) dt[x]) 1.871054 1.934865 2.216192 2.282428 2.367505 10 
+3

+1 za używanie '.BY', który jest jednym z tych .VAR's, których jeszcze nie nauczyłem się używać. – Frank

+0

Nie podoba mi się składnia, ale to najlepiej odpowiada na moje pytanie. – Beasterfield

+0

właśnie zdałem sobie sprawę, że 'dt [, list (list (...)), by = p]' to nie tylko najlepsza, ale idealna odpowiedź na moje pytanie. Kolumna wyniku "V1" może nawet zawierać obiekty dowolnego typu (prymitywy, S3, S4, obiekty ReferenceClasses, ...). To powiedziawszy, nienawidzę składni jeszcze więcej :-) – Beasterfield

2

Spróbuj tego:

> split(dt, dt[["p"]]) 
$A 
    p q 
1: A 1 

$B 
    p q 
1: B 2 
+0

To było proste :-) Właśnie zastanawiałem się nad wydajnością, ponieważ split nie korzysta ze składni i możliwości 'data.tables'. Ale twoja odpowiedź dała mi wskazówkę we właściwym kierunku. Wielkie dzięki za to! – Beasterfield

2

chodzi o odpowiedź G. Grothendiecka Byłem ciekaw, jak dobrze wykonuje podzielone: ​​

dt <- data.table(p = rep(LETTERS[1:25], 1E6), q = 25*1E6, key = "p") 

system.time(
    ll <- split(dt, dt[ ,p ]) 
) 
    user system elapsed 
    5.237 1.340 6.563 

system.time(
    ll <- lapply(unique(dt[,p]), function(x) dt[x]) 
) 
    user system elapsed 
    1.179 0.363 1.541 

Więc jeśli nie ma lepszej odpowiedzi, bym trzymać

lapply(unique(dt[,p]), function(x) dt[x])