R语言教程 -- 分组操作group_by()、group_keys()、ungroup()

group_by()是最重要的分组动词,需要一个数据框和一个或多个变量进行分组:

详情: https://cloud.r-project.org/web/packages/dplyr/vignettes/grouping.html

 

我们首先加载 dplyr:

library(dplyr)

添加分组 group_by()

最重要的分组动词是group_by():它需要一个数据框和一个或多个变量进行分组:

by_species <- starwars %>% group_by(species)
by_sex_gender <- starwars %>% group_by(sex, gender)

 在添加分组后,print()打印时可以看到分组:

 

by_species
#> # A tibble: 87 x 14
#> # Groups:   species [38]
#>   name     height  mass hair_color  skin_color eye_color birth_year sex   gender
#>   <chr>     <int> <dbl> <chr>       <chr>      <chr>          <dbl> <chr> <chr> 
#> 1 Luke Sk~    172    77 blond       fair       blue            19   male  mascu~
#> 2 C-3PO       167    75 <NA>        gold       yellow         112   none  mascu~
#> 3 R2-D2        96    32 <NA>        white, bl~ red             33   none  mascu~
#> 4 Darth V~    202   136 none        white      yellow          41.9 male  mascu~
#> 5 Leia Or~    150    49 brown       light      brown           19   fema~ femin~
#> 6 Owen La~    178   120 brown, grey light      blue            52   male  mascu~
#> # ... with 81 more rows, and 5 more variables: homeworld <chr>, species <chr>,
#> #   films <list>, vehicles <list>, starships <list>

 

 

计算每个分组的行数,可以通过sort参数控制排序方式。

 

by_species %>% tally()
#> # A tibble: 38 x 2
#>   species      n
#>   <chr>    <int>
#> 1 Aleena       1
#> 2 Besalisk     1
#> 3 Cerean       1
#> 4 Chagrian     1
#> 5 Clawdite     1
#> 6 Droid        6
#> # ... with 32 more rows
by_sex_gender %>% tally(sort = TRUE)
#> # A tibble: 6 x 3
#> # Groups:   sex [5]
#>   sex            gender        n
#>   <chr>          <chr>     <int>
#> 1 male           masculine    60
#> 2 female         feminine     16
#> 3 none           masculine     5
#> 4 <NA>           <NA>          4
#> 5 hermaphroditic masculine     1
#> 6 none           feminine      1

 

在数据探索时比较有用。

除了按照现有变量分组外,还可以按照函数处理后的变量分组,等效在mutate()之后执行group_by:

 

bmi_breaks <- c(0, 18.5, 25, 30, Inf)
starwars %>%
  group_by(bmi_cat = cut(mass/(height/100)^2, breaks=bmi_breaks)) %>%
  tally()
#> # A tibble: 5 x 2
#>   bmi_cat       n
#>   <fct>     <int>
#> 1 (0,18.5]     10
#> 2 (18.5,25]    24
#> 3 (25,30]      13
#> 4 (30,Inf]     12
#> 5 <NA>         28

group_by()可通过在group_by()计算产生的新字段分组

 

查看分组group_keys()

 

 

使用group_keys()查看数据的分组,每个组一行,每个分组变量占一列:

 

by_species %>% group_keys()
#> # A tibble: 38 x 1
#>   species 
#>   <chr>   
#> 1 Aleena  
#> 2 Besalisk
#> 3 Cerean  
#> 4 Chagrian
#> 5 Clawdite
#> 6 Droid   
#> # ... with 32 more rows

by_sex_gender %>% group_keys()
#> # A tibble: 6 x 2
#> sex gender
#> <chr> <chr>
#> 1 female feminine
#> 2 hermaphroditic masculine
#> 3 male masculine
#> 4 none feminine
#> 5 none masculine
#> 6 <NA> <NA>

 也可以使用命令group_indices()查看每行属于哪个组:

 

by_species %>% group_indices()
#>  [1] 11  6  6 11 11 11 11  6 11 11 11 11 34 11 24 12 11 11 36 11 11  6 31 11 11
#> [26] 18 11 11  8 26 11 21 11 10 10 10 38 30  7 38 11 37 32 32 33 35 29 11  3 20
#> [51] 37 27 13 23 16  4 11 11 11  9 17 17 11 11 11 11  5  2 15 15 11  1  6 25 19
#> [76] 28 14 34 11 38 22 11 11 11  6 38 11

该特性方便增加组别列。

 

df <- tibble(a = c('a','a','a','b','b','b','d','e','f'))
df %>% 
  group_by(a) %>%
  mutate(组别列 = group_indices() )
#> Warning: `group_indices()` was deprecated in dplyr 1.0.0.
#> Please use `cur_group_id()` instead.
#> # A tibble: 9 x 2
#> # Groups:   a [5]
#>   a     组别列
#>   <chr>  <int>
#> 1 a          1
#> 2 a          1
#> 3 a          1
#> 4 b          2
#> 5 b          2
#> 6 b          2
#> # ... with 3 more rows

上述用法在dplyr 1.0.0 中弃用,用cur_group_id()代替,如下所示

 

df %>% 
  group_by(a) %>%
  mutate(组别列 = cur_group_id())
#> # A tibble: 9 x 2
#> # Groups:   a [5]
#>   a     组别列
#>   <chr>  <int>
#> 1 a          1
#> 2 a          1
#> 3 a          1
#> 4 b          2
#> 5 b          2
#> 6 b          2
#> # ... with 3 more rows

 dplyr 在我看来 API 变化较快,所以我个人习惯使用 data.table 包处理数据。所以在学习的时候用最新的版本学习。

group_rows()每个组包含哪些行:

 

by_species %>% group_rows() %>% head()
#> <list_of<integer>[6]>
#> [[1]]
#> [1] 72
#> 
#> [[2]]
#> [1] 68
#> 
#> [[3]]
#> [1] 49
#> 
#> [[4]]
#> [1] 56
#> 
#> [[5]]
#> [1] 67
#> 
#> [[6]]
#> [1]  2  3  8 22 73 85

 group_vars()返回分组变量的名称,请使用:

 

by_species %>% group_vars()
#> [1] "species"

by_sex_gender %>% group_vars()
#> [1] "sex" "gender"

删除分组变量ungroup()

 

要删除所有分组变量,使用ungroup():

 

by_species %>%
  ungroup() %>%
  tally()
#> # A tibble: 1 x 1
#>       n
#>   <int>
#> 1    87

 还可以通过列出要删除的变量来有选择的删除分组变量:

by_sex_gender %>% 
  ungroup(sex) %>% 
  tally()
#> # A tibble: 3 x 2
#>   gender        n
#>   <chr>     <int>
#> 1 feminine     17
#> 2 masculine    66
#> 3 <NA>          4

 

实例演示