2012-12-20 15 views
8

Poszukuję wzorów do manipulowania obiektami data.table, których struktura przypomina strukturę ramek danych utworzonych za pomocą melt z pakietu reshape2. Mam do czynienia z tabelami danych z milionami wierszy. Wydajność ma kluczowe znaczenie.Szybko stapiane operacje na tabelach danych

Uogólnioną formą pytania jest pytanie, czy istnieje sposób przeprowadzania grupowania w oparciu o podzbiór wartości w kolumnie i czy wynik operacji grupowania tworzy jedną lub więcej nowych kolumn.

Specyficzną formą pytanie może być, jak korzystać data.table osiągnąć równowartość co dcast działa w następujących przypadkach:

input <- data.table(
    id=c(1, 1, 1, 2, 2, 2, 3, 3, 3, 3), 
    variable=c('x', 'y', 'y', 'x', 'y', 'y', 'x', 'x', 'y', 'other'), 
    value=c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) 
dcast(input, 
    id ~ variable, sum, 
    subset=.(variable %in% c('x', 'y'))) 

którego wyjście jest

id x y 
1 1 1 5 
2 2 4 11 
3 3 15 9 
+0

Jestem zdezorientowany , przepraszam - funkcja dcast() działa bez przymusu as.data.frame(). próbujesz to osiągnąć bez korzystania z pakietu plyr? –

+0

@AnthonyDamico tak, chciałbym osiągnąć to bez 'dcast', który jest w' reshape2'. Usunąłem as.data.frame() - dzięki za wskazanie tego. – Sim

Odpowiedz

8

Szybka odpowiedź niesprawdzone: Wygląda szukasz by-bez-by, aka grouping- by-i:

setkey(input,variable) 
input[c("x","y"),sum(value)] 

To jest jak szybki HAVING w SQL. j jest oceniany dla każdego wiersza i. Innymi słowy, powyżej jest taki sam wynik, ale o wiele szybciej niż:

input[,sum(value),keyby=variable][c("x","y")] 

Ten ostatni podzbiorów i evals dla wszystkich grup (rozrzutnie) Przed wybraniem tylko grupy interesów. Ten pierwszy (przez-bez-przez) przechodzi bezpośrednio do podzbioru grup.

Wyniki grupy zostaną zwrócone w długim formacie, jak zawsze. Ale później przekształcenie na szeroką skalę (relatywnie małych) zagregowanych danych powinno być względnie natychmiastowe. I tak myślę.

Pierwszy setkey(input,variable) może odgryźć, jeśli input ma dużo niepotrzebnych kolumn. Jeśli tak, to być może warto podzbioru kolumn potrzebne:

DT = setkey(input[,c("variable","value"),with=FALSE], variable) 
DT[c("x","y"),sum(value)] 

W przyszłości, gdy klucze wtórne są realizowane że byłoby łatwiejsze:

set2key(input,variable)    # add a secondary key 
input[c("x","y"),sum(value),key=2] # syntax speculative 

Do grupy przez id także:

setkey(input,variable) 
input[c("x","y"),sum(value),by='variable,id'] 

i tym razem id w kluczu może być warta setkey w zależności od twoich danych:

setkey(input,variable,id) 
input[c("x","y"),sum(value),by='variable,id'] 

Jeśli połączysz opcję "by-without-by" z "by-by-by", jak wyżej, to by-without-by działa tak jak podzbiór; to znaczy, j jest uruchamiany tylko dla każdego wiersza z i, gdy go brakuje (stąd nazwa by-without-by). Musisz więc ponownie dodać variable w by, jak pokazano powyżej.

Alternatywnie, następujące powinny grupa przez id nad jednością „X” i „Y” zamiast (ale wyżej jest o co prosiliście w pytaniu, IIUC):

input[c("x","y"),sum(value),by=id] 
+0

Dodatkowe klucze byłyby bardzo pomocne. Alternatywnie, sposób budowania "zmian" przez odniesienie za pomocą różnych kluczy. Wzór, który ciągle odkrywam, wymaga kilkukrotnej zmiany klucza dla różnych operacji z tą samą klauzulą, ale różnych klauzul wyboru, a następnie ręcznego złożenia końcowego wyniku z datatables każdej operacji. – Sim

3
> setkey(input, "id") 
> input[ , list(sum(value)), by=id] 
    id V1 
1: 1 6 
2: 2 15 
3: 3 34 

> input[ variable %in% c("x", "y"), list(sum(value)), by=id] 
    id V1 
1: 1 6 
2: 2 15 
3: 3 24 

Ostatni:

> input[ variable %in% c("x", "y"), list(sum(value)), by=list(id, variable)] 
    id variable V1 
1: 1  x 1 
2: 1  y 5 
3: 2  x 4 
4: 2  y 11 
5: 3  x 15 
6: 3  y 9 
+0

To wykonuje 'sumę' dla wszystkich zmiennych w przeciwieństwie do' x' i 'y'. W moim przypadku są setki różnych zmiennych, więc potrzebuję klauzuli podsekcji. Bardzo bym tego nie potrzebował, tworząc całą tymczasową datatable. – Sim

+1

jest bliżej, ale nadal nie jest doskonały keycols <- c ("id", "variable"); setkeyv (input, keycols); wejście [wejście $ zmienna% w% c ("x", "y"), lista (suma (wartość)), by = keycols] –

+0

@Sim: Właśnie pokazywałem ci opcje. Ten ostatni jest wszystkim, czego potrzebujesz i nie tworzy żadnych pośrednich tabel. –

2

Nie jestem pewien, czy jest to najlepszy sposób, ale można spróbować:

input[, list(x = sum(value[variable == "x"]), 
      y = sum(value[variable == "y"])), by = "id"] 
# id x y 
# 1: 1 1 5 
# 2: 2 4 11 
# 3: 3 15 9 
+0

Czy to nie tworzy dwóch tymczasowych wektorów dla równości 'zmiennej' dla każdej wartości' id'? – Sim

Powiązane problemy