2013-03-13 9 views
19

Sto provando a creare un sottoinsieme di un frame di dati, in cui ottengo più frame di dati in base a più valori di colonna. Qui è il mio esempioR subsetting di un frame di dati in più frame di dati in base a più valori di colonna

>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 

Il risultato atteso è qualcosa di simile in cui sto stessi dividendo questo lasso di dati in più frame di dati basati su colonna v1 e 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 

Ho scritto un codice che sta lavorando in questo momento, ma non pensare che sia il modo migliore per farlo. Ci deve essere un modo migliore per farlo. Supponendo che tab sia data.frame con i dati iniziali. Ecco il mio codice:

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

Qualcuno può suggerire un metodo migliore per fare quanto sopra?

+0

Vuoi riutilizzare quei dataframes, o semplicemente stamparli raggruppati da quelle colonne? – Thilo

+0

Voglio riutilizzarli .... voglio tracciare grafici su quei frame di dati. –

risposta

23

Siete alla ricerca di 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 

Come notato nei commenti

una delle seguenti avrebbe funzionato

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 

Sembra interaction è leggermente più veloce (probabilmente a causa del fatto che lo f = list(...) viene convertito in un'interazione all'interno della funzione)


Modifica

Se si desidera semplicemente utilizzare i data.frames sottoinsieme allora io suggerirei di usare data.table per la facilità di codifica

library(data.table) 

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

'split' può prendere una lista per' f', invece di dover usare 'interaction'. Non sono sicuro che sia più efficiente. – A5C1D2H2I1M1N2O1R2T1

+0

@AnandaMahto - Ho aggiunto un punto di riferimento. – mnel

+0

Grazie per i parametri di riferimento. In tal caso, il trucco di @ Arun ('with (df, split (df, f = do.call (paste, df [1: 2]))) 'probabilmente sarebbe ancora più veloce! E, ciò non creerà livelli non necessari – A5C1D2H2I1M1N2O1R2T1

3

ora C'è anche nest() da tidyr che è piuttosto bello .

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 

accesso Tibbles individuali con nestdf$data[1] e così via.