Mar*_*inT 23 split r list dplyr
我有一个split()
在R 中窒息的大型数据集.我能够使用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)
Run Code Online (Sandbox Code Playgroud)
回报
$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
Run Code Online (Sandbox Code Playgroud)
我想用group_by
(类似的东西group_by(df,V1)
)来模仿这个,但这会返回一个,grouped_df
.我知道do
应该可以帮助我,但我不确定使用情况(另见讨论链接.)
请注意,每个列表的拆分名称都是用于建立此组的因子的名称 - 这是一个所需的功能(最终,这是从dfs列表中提取这些名称的方法的奖励).
Mat*_*fou 15
比较基础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)
Run Code Online (Sandbox Code Playgroud)
得到:
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
Run Code Online (Sandbox Code Playgroud)
Col*_*vel 13
要"坚持"到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
Run Code Online (Sandbox Code Playgroud)
Ras*_*sen 12
dplyr中的group_split:
Dplyr已实现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
Run Code Online (Sandbox Code Playgroud)
这对于调试嵌套数据帧上的计算也非常有帮助,因为它是一种“查看”嵌套数据帧上“内部”计算的快速方法。
小智 9
你可以从数据帧列表group_by
使用do
,只要你命名新的列,其中数据帧将被保存,然后通过管道将列进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
Run Code Online (Sandbox Code Playgroud)
从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
Run Code Online (Sandbox Code Playgroud)
由于dplyr 0.5.0.9000
,使用的最短解决方案group_by()
可能是do
遵循pull
:
df %>% group_by(V1) %>% do(data=(.)) %>% pull(data)
Run Code Online (Sandbox Code Playgroud)
请注意,与 不同的是split
,这不会命名结果列表元素。如果这是需要的,那么您可能想要类似的东西
df %>% group_by(V1) %>% do(data = (.)) %>% with( set_names(data, V1) )
Run Code Online (Sandbox Code Playgroud)
稍微编辑一下,我同意人们所说的这split()
是更好的选择。就我个人而言,我总是觉得很烦人,因为我必须输入数据框的名称两次(例如,split( potentiallylongname, potentiallylongname$V1 )
),但这个问题很容易通过管道回避:
df %>% split( .$V1 )
Run Code Online (Sandbox Code Playgroud)