2017-01-25 4 views
2

Das folgende Problem hindert mich bisher an einer wirklich flexiblen Nutzung von data.table aggregations.Flexibles Mischen mehrerer Aggregationen in data.table für verschiedene Spaltenkombinationen

Beispiel:

library(data.table) 
set.seed(1) 
DT <- data.table(C1=c("a","b","b"), 
       C2=round(rnorm(4),4), 
       C3=1:12, 
       C4=9:12) 

sum_cols <- c("C2","C3") 

#I want to apply a custom aggregation over multiple columns 
DT[,lapply(.SD,sum),by=C1,.SDcols=sum_cols] 

### Part 1 of question ### 
#but what if I want to add another aggregation, e.g. count 
DT[,.N,by=C1] 

#this is not working as intended (creates 4 rows instead of 2 and doesnt contain sum_cols) 
DT[,.(.N,lapply(.SD,sum)),by=C1,.SDcols=sum_cols] 

### Part 2 of question ### 
# or another function for another set of colums and adding a prefix to keep them appart? 
mean_cols <- c("C3","C4") 

#intended table structure (with 2 rows again) 
C1 sum_C2 sum_C3 mean_C3 mean_C4 

Ich weiß, dass ich immer verschiedene einzelne Aggregation Ergebnisse von einigen Schlüssel zusammenführen können, aber Ich bin mir sicher muss es eine richtige, flexible und einfache Art und Weise zu tun, was ich tun möchte (vor allem Teil 2).

Antwort

2

Das erste, was zu verketten, die mit c gebaut werden können wie in @ akruns Antwort erwähnt. Es gibt zwei Möglichkeiten, es zu tun:

set.seed(1) 
DT <- data.table(C1=c("a","b","b"), C2=round(rnorm(4),4), C3=1:12, C4=9:12) 
sum_cols <- c("C2","C3") 
mean_cols <- c("C3","C4") 

# with the development version, 1.10.1+ 
DT[, c(
    .N, 
    sum = lapply(.SD[, ..sum_cols], sum), 
    mean = lapply(.SD[, ..mean_cols], mean) 
), by=C1] 

# in earlier versions 
DT[, c(
    .N, 
    sum = lapply(.SD[, sum_cols, with=FALSE], sum), 
    mean = lapply(.SD[, mean_cols, with=FALSE], mean) 
), by=C1] 

mget gibt eine Liste und c verbindet Elemente zusammen, um eine Liste zu machen.


Kommentare

Wenn Sie auf der verbose data.table Option für diese Anrufe schalten, erhalten Sie eine Meldung:

Das Ergebnis j ist eine benannte Liste. Es ist sehr ineffizient, immer wieder dieselben Namen für jede Gruppe zu erstellen. Wenn j = list (...), werden alle Namen erkannt, entfernt und nach der Gruppierung wieder eingefügt, um die Effizienz zu erhöhen. Die Verwendung von j = transform() zum Beispiel verhindert diese Beschleunigung (in Betracht ziehen, zu: = zu wechseln). Diese Nachricht wird möglicherweise in Zukunft auf Warnung aktualisiert.

Außerdem werden Sie sehen, dass der optimierte Gruppenmittelwert und die Summe nicht verwendet werden (Details siehe ?GForce). Wir können diese by following FAQ 1.6 vielleicht umgehen, aber ich konnte nicht herausfinden, wie.

+0

Toll, danke - das wird mein Leben mit dt viel einfacher und bequemer machen. Leistung kommt an zweiter Stelle (in diesem Fall) - Ich werde Ihre Anmerkungen überprüfen, wenn ich auf Probleme stoße. Ich bin allerdings überrascht, dass das .SDcols hier nicht so hilfreich ist ... es scheint im Allgemeinen ziemlich begrenzt zu sein. – katsumi

+0

@katsumi Yeah, .SDcols ist nur für eine Reihe von Cols auf einmal, also wenn Sie mehrere (möglicherweise überlappende) Sets wollen, wird es nicht so nützlich sein, denke ich. – Frank

0

Der Ausgang ist list s, so verwenden wir c sowohl die list Ausgänge j Argument ist das data.table eine Ausgabeliste erwartet zu bemerken

DT[,c(.N,lapply(.SD,sum)),by=C1,.SDcols=sum_cols] 
# C1 N C2 C3 
# 1: a 4 0.288 22 
# 2: b 8 0.576 56 
+0

Danke, das löst wirklich den ersten Teil der Frage. Irgendwelche Ideen für den zweiten Teil, wo ich verschiedene Aggregationen für verschiedene Spaltensätze haben möchte (idealerweise mit einem aggregationsabhängigen Namensschema für Ausgabespalten)? – katsumi

Verwandte Themen