2013-03-13 9 views
19

Ich versuche, einen Datenrahmen zu unterteilen, wo ich mehrere Datenrahmen basierend auf mehreren Spaltenwerte erhalten. Hier ist mein BeispielR Untergliederung eines Datenrahmens in mehrere Datenrahmen basierend auf mehreren Spaltenwerten

>df 
    v1 v2 v3 v4 v5 
    A Z 1 10 12 
    D Y 10 12 8 
    E X 2 12 15 
    A Z 1 10 12 
    E X 2 14 16 

Die erwartete Ausgabe ist so etwas wie diese, wo ich diesen Datenrahmen am Aufspalten in Frames mehr Daten basierend auf Spalte v1 und v2

>df1 
v3 v4 v5 
    1 10 12 
    1 10 12 
>df2 
v3 v4 v5 
10 12 8 
>df3 
v3 v4 v5 
2 12 15 
2 14 16 

ich geschrieben habe einen Code, der funktioniert gerade jetzt, aber denke nicht, dass das der beste Weg ist, es zu tun. Es muss einen besseren Weg geben, es zu tun. Angenommen tab ist der data.frame mit den Anfangsdaten. Hier ist mein Code:

v1Factors<-levels(factor(tab$v1)) 
v2Factors<-levels(factor(tab$v2)) 

for(i in 1:length(v1Factors)){ 
    for(j in 1:length(v2Factors)){ 
    subsetTab<-subset(tab, v1==v1Factors[i] & v2==v2Factors[j], select=c("v3", "v4", "v5")) 
    print(subsetTab) 
    } 
} 

Kann jemand vorschlagen, eine bessere Methode, um das Obige zu tun?

+0

Möchten Sie diese Datenrahmen wiederverwenden oder sie nur gruppiert nach diesen Spalten drucken? – Thilo

+0

Ich möchte sie wiederverwenden .... möchte Diagramme auf diesen Datenrahmen plotten. –

Antwort

23

Sie suchen split

split(df, with(df, interaction(v1,v2)), drop = TRUE) 
$E.X 
    v1 v2 v3 v4 v5 
3 E X 2 12 15 
5 E X 2 14 16 

$D.Y 
    v1 v2 v3 v4 v5 
2 D Y 10 12 8 

$A.Z 
    v1 v2 v3 v4 v5 
1 A Z 1 10 12 

Wie in den Kommentaren darauf hingewiesen

eine der folgenden Aktionen funktionieren würde

library(microbenchmark) 
microbenchmark(
       split(df, list(df$v1,df$v2), drop = TRUE), 
       split(df, interaction(df$v1,df$v2), drop = TRUE), 
       split(df, with(df, interaction(v1,v2)), drop = TRUE)) 


Unit: microseconds 
                expr  min  lq median  uq  max neval 
      split(df, list(df$v1, df$v2), drop = TRUE) 1119.845 1129.3750 1145.8815 1182.119 3910.249 100 
    split(df, interaction(df$v1, df$v2), drop = TRUE) 893.749 900.5720 909.8035 936.414 3617.038 100 
split(df, with(df, interaction(v1, v2)), drop = TRUE) 895.150 902.5705 909.8505 927.128 1399.284 100 

Es interaction erscheint, wird etwas schneller (wahrscheinlich aufgrund der Tatsache, dass die f = list(...) werden gerade in eine Interaktion innerhalb der Funktion umgewandelt)


bearbeiten

Wenn Sie die Teilmenge data.frames nur benutzen wollen, dann würde ich für eine einfache Verwendung data.table vorschlagen Kodierung

library(data.table) 

dt <- data.table(df) 
dt[, plot(v4, v5), by = list(v1, v2)] 
+2

'split' kann eine Liste für' f' nehmen, anstatt 'interaction' zu verwenden. Nicht sicher, was jedoch effizienter ist. – A5C1D2H2I1M1N2O1R2T1

+0

@AnandaMahto - Ich habe einen Benchmark hinzugefügt. – mnel

+0

Danke für die Benchmarks. In diesem Fall wäre @ Aruns Trick ('mit (df, split (df, f = do.call (einfügen, df [1: 2]))) wahrscheinlich noch schneller! Und das erzeugt keine unnötigen Level – A5C1D2H2I1M1N2O1R2T1

3

Es jetzt ist auch nest() von tidyr das ist ziemlich nett .

library(tidyr) 
nestdf <- df %>% nest(v3:v5) 
nestdf$data 

> nestdf$data 
[[1]] 
# A tibble: 2 × 3 
    v3 v4 v5 
    <int> <int> <int> 
1  1 10 12 
2  1 10 12 

[[2]] 
# A tibble: 1 × 3 
    v3 v4 v5 
    <int> <int> <int> 
1 10 12  8 

[[3]] 
# A tibble: 2 × 3 
    v3 v4 v5 
    <int> <int> <int> 
1  2 12 15 
2  2 14 16 

Zugang individuelle Tibbles mit nestdf$data[1] und so weiter.