使用dplyr group_by模拟split():返回数据帧列表

Mar*_*inT 23 split r list dplyr

我有一个split()在R 中窒息的大型数据集.我能够使用dplyrgroup_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

比较基础plyrdplyr解决方案,它似乎仍然更快!

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)

  • 感谢您指出了这一点!我纠正了它,确实,base 变慢了,尽管仍然比其他人快。 (3认同)

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)

  • 如何使用`plyr`坚持使用`dplyr`? (30认同)
  • 非常感谢你.这导致了我想要的,并快速完成.我不会将它标记为正确的答案,因为我仍然感兴趣如何将group_by的结果导出为数据框列表,但是谢谢 - 你已经解决了我的问题并且我学到了一些东西!有趣的是,从一个380Mb的数据集中,结果声称是一个340Gb的列表!我希望我可以保存它,看起来很奇怪 - 但它完成得非常快,大约需要5分钟. (3认同)

Ras*_*sen 12

dplyr中的group_split:

Dplyr已实现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     
Run Code Online (Sandbox Code Playgroud)

这对于调试嵌套数据帧上的计算也非常有帮助,因为它是一种“查看”嵌套数据帧上“内部”计算的快速方法。

  • 另外:如果你想为你的列表命名。使用此处的函数 `named_group_split()` https://github.com/tidyverse/dplyr/issues/4223 (2认同)

小智 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)

  • 一个相同但略短的版本是:`df%>%group_by(V1)%>%do(data =(.))%>%select(data)%>%map(identity)` (7认同)
  • 使用最新版本的`tidyr`(0.4.1),你可以用`nest()`替换`do(vals = data.frame(.))`.`vals`默认命名为`data` (2认同)

Moo*_*per 6

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)


Art*_*lov 5

由于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)