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_by
(group_by(df,V1)
のようなもの)でこれをエミュレートしたいのですが、これはgrouped_df
を返します。 do
が私を助けることができることは知っていますが、使用法については確信がありません(議論については link も参照してください)。
このグループを確立するために使用されたファクターの名前で各リストの名前を分割することに注意してください-これは望ましい機能です(最終的に、dfsのリストからこれらの名前を抽出するためのボーナス賞賛)。
ベース、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
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
group_split in dplyr 0.8:
Dplyrのバージョン0.8はgroup_split
: https://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
また、ネストされたデータフレームでの計算の「内部」で行われていることを「見る」ための迅速な方法であるため、ネストされたデータフレームでの計算のデバッグにも非常に役立ちます。
データフレームが格納される新しい列に名前を付けて、その列を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
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
_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 )
_