2013-03-13 3 views
19

Я пытаюсь подмножить фрейм данных, где я получаю несколько кадров данных на основе нескольких значений столбцов. Вот мой примерR подмножество кадра данных в несколько кадров данных на основе нескольких значений столбца

>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 

Ожидаемый выход что-то вроде этого, где я разделив этот кадр данных на несколько кадров данных на основе столбца v1 и 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 

Я написал код, который работает прямо сейчас, но не думайте, что это лучший способ сделать это. Должен быть лучший способ сделать это. Предполагая, что tab - это data.frame с исходными данными. Вот мой код:

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

Может ли кто-нибудь предложить лучший способ сделать это?

+0

Вы хотите повторно использовать эти фреймы данных или просто распечатать их, сгруппированные по этим столбцам? – Thilo

+0

Я хочу их повторно использовать .... хочу строить графики на этих кадрах данных. –

ответ

23

Вы ищете 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 

Как было отмечено в комментариях

любой из следующих будет работать

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 

Оказывается interaction немного быстрее (возможно, из-за того факта, что f = list(...) просто преобразуются в взаимодействие внутри функции)


Редактировать

Если вы хотите использовать подмножество data.frames, то я бы предложил использовать data.table для облегчения кодирования

library(data.table) 

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

'split' может взять список для' f', вместо того, чтобы использовать 'взаимодействие'. Не уверен, что более эффективно. – A5C1D2H2I1M1N2O1R2T1

+0

@AnandaMahto - Я добавил тест. – mnel

+0

Спасибо за тесты. В этом случае трюк @ Arun ('with (df, split (df, f = do.call (paste, df [1: 2])))', вероятно, будет еще быстрее! И это не создаст ненужных уровней что необходимо удалить. – A5C1D2H2I1M1N2O1R2T1

3

Там теперь также nest() от tidyr который довольно хорошо ,

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 

доступа к отдельным tibbles с nestdf$data[1] и так далее.