web-dev-qa-db-ja.com

dplyr group_byでsplit()をエミュレート:データフレームのリストを返します

Rでsplit()をチョークする大きなデータセットがあります。dplyr group_byを使用できます(とにかく推奨される方法です)が、結果のgrouped_dfをデータフレームのリストとしてフォーマットすることはできません。連続した処理ステップに必要です(SpatialDataFramesなどに強制する必要があります)。

サンプルデータセットを考えます。

df = as.data.frame(cbind(c("a","a","b","b","c"),c(1,2,3,4,5), c(2,3,4,2,2)))
listDf = split(df,df$V1)

戻り値

$a
   V1 V2 V3
 1  a  1  2
 2  a  2  3

$b
   V1 V2 V3
 3  b  3  4
 4  b  4  2

$c
   V1 V2 V3
 5  c  5  2

group_bygroup_by(df,V1)のようなもの)でこれをエミュレートしたいのですが、これはgrouped_dfを返します。 doが私を助けることができることは知っていますが、使用法については確信がありません(議論については link も参照してください)。

このグループを確立するために使用されたファクターの名前で各リストの名前を分割することに注意してください-これは望ましい機能です(最終的に、dfsのリストからこれらの名前を抽出するためのボーナス賞賛)。

23
MartinT

ベース、plyrおよびdplyrのソリューションを比較すると、ベースのソリューションの方がずっと速いようです。

library(plyr)
library(dplyr)   

df <- data_frame(Group1=rep(LETTERS, each=1000),
             Group2=rep(rep(1:10, each=100),26), 
             Value=rnorm(26*1000))

microbenchmark(Base=df %>%
             split(list(.$Group2, .$Group1)),
           dplyr=df %>% 
             group_by(Group1, Group2) %>% 
             do(data = (.)) %>% 
             select(data) %>% 
             lapply(function(x) {(x)}) %>% .[[1]],
           plyr=dlply(df, c("Group1", "Group2"), as.tbl),
           times=50) 

与える:

Unit: milliseconds
  expr      min        lq      mean    median        uq       max neval
  Base 12.82725  13.38087  16.21106  14.58810  17.14028  41.67266    50
  dplyr 25.59038 26.66425  29.40503  27.37226  28.85828  77.16062   50
  plyr 99.52911  102.76313 110.18234 106.82786 112.69298 140.97568    50
15
Matifou

Dplyrに「固定」するには、plyrの代わりにsplitを使用することもできます。

library(plyr)

dlply(df, "V1", identity)
#$a
#  V1 V2 V3
#1  a  1  2
#2  a  2  3

#$b
#  V1 V2 V3
#1  b  3  4
#2  b  4  2

#$c
#  V1 V2 V3
#1  c  5  2
13
Colonel Beauvel

group_split in dplyr 0.8:

Dplyrのバージョン0.8はgroup_splithttps://dplyr.tidyverse.org/reference/group_split.html

データフレームをグループで分割し、データフレームのリストを返します。これらの各データフレームは、分割変数のカテゴリによって定義された元のデータフレームのサブセットです。

例えば。データセットirisを変数Speciesで分割し、各サブデータセットのサマリーを計算します。

> iris %>% 
+     group_split(Species) %>% 
+     map(summary)
[[1]]
  Sepal.Length    Sepal.Width     Petal.Length    Petal.Width          Species  
 Min.   :4.300   Min.   :2.300   Min.   :1.000   Min.   :0.100   setosa    :50  
 1st Qu.:4.800   1st Qu.:3.200   1st Qu.:1.400   1st Qu.:0.200   versicolor: 0  
 Median :5.000   Median :3.400   Median :1.500   Median :0.200   virginica : 0  
 Mean   :5.006   Mean   :3.428   Mean   :1.462   Mean   :0.246                  
 3rd Qu.:5.200   3rd Qu.:3.675   3rd Qu.:1.575   3rd Qu.:0.300                  
 Max.   :5.800   Max.   :4.400   Max.   :1.900   Max.   :0.600                  

[[2]]
  Sepal.Length    Sepal.Width     Petal.Length   Petal.Width          Species  
 Min.   :4.900   Min.   :2.000   Min.   :3.00   Min.   :1.000   setosa    : 0  
 1st Qu.:5.600   1st Qu.:2.525   1st Qu.:4.00   1st Qu.:1.200   versicolor:50  
 Median :5.900   Median :2.800   Median :4.35   Median :1.300   virginica : 0  
 Mean   :5.936   Mean   :2.770   Mean   :4.26   Mean   :1.326                  
 3rd Qu.:6.300   3rd Qu.:3.000   3rd Qu.:4.60   3rd Qu.:1.500                  
 Max.   :7.000   Max.   :3.400   Max.   :5.10   Max.   :1.800                  

[[3]]
  Sepal.Length    Sepal.Width     Petal.Length    Petal.Width          Species  
 Min.   :4.900   Min.   :2.200   Min.   :4.500   Min.   :1.400   setosa    : 0  
 1st Qu.:6.225   1st Qu.:2.800   1st Qu.:5.100   1st Qu.:1.800   versicolor: 0  
 Median :6.500   Median :3.000   Median :5.550   Median :2.000   virginica :50  
 Mean   :6.588   Mean   :2.974   Mean   :5.552   Mean   :2.026                  
 3rd Qu.:6.900   3rd Qu.:3.175   3rd Qu.:5.875   3rd Qu.:2.300                  
 Max.   :7.900   Max.   :3.800   Max.   :6.900   Max.   :2.500     

また、ネストされたデータフレームでの計算の「内部」で行われていることを「見る」ための迅速な方法であるため、ネストされたデータフレームでの計算のデバッグにも非常に役立ちます。

9
Rasmus Larsen

データフレームが格納される新しい列に名前を付けて、その列をdoにパイプする限り、group_byからlapplyを使用してデータフレームのリストを取得できます。

listDf = df %>% group_by(V1) %>% do(vals=data.frame(.)) %>% select(vals) %>% lapply(function(x) {(x)})
listDf[[1]]
#[[1]]
#  V1 V2 V3
#1  a  1  2
#2  a  2  3

#[[2]]
#  V1 V2 V3
#1  b  3  4
#2  b  4  2

#[[3]]
#  V1 V2 V3
#1  c  5  2
9
COrtega

dplyr 0.8なので、group_split

library(dplyr)
df = as.data.frame(cbind(c("a","a","b","b","c"),c(1,2,3,4,5), c(2,3,4,2,2)))
df %>% group_by(V1) %>% group_split()
#> [[1]]
#> # A tibble: 2 x 3
#>   V1    V2    V3   
#>   <fct> <fct> <fct>
#> 1 a     1     2    
#> 2 a     2     3    
#> 
#> [[2]]
#> # A tibble: 2 x 3
#>   V1    V2    V3   
#>   <fct> <fct> <fct>
#> 1 b     3     4    
#> 2 b     4     2    
#> 
#> [[3]]
#> # A tibble: 1 x 3
#>   V1    V2    V3   
#>   <fct> <fct> <fct>
#> 1 c     5     2
6

_dplyr 0.5.0.9000_なので、group_by()を使用する最も短い解決策は、おそらくdoの後にpullを付けることです。

_df %>% group_by(V1) %>% do(data=(.)) %>% pull(data)
_

splitとは異なり、これは結果のリスト要素に名前を付けないことに注意してください。これが必要な場合は、おそらく次のようなものが必要です

_df %>% group_by(V1) %>% do(data = (.)) %>% with( set_names(data, V1) )
_

少し編集するために、split()がより良いオプションであると言っている人々に同意します。個人的には、データフレームの名前を2回入力する必要があること(たとえばsplit( potentiallylongname, potentiallylongname$V1 ))が常に面倒ですが、問題はパイプで簡単に回避できます。

_df %>% split( .$V1 )
_
3
Artem Sokolov