r tidyverse 使い方 | 行 グループ毎の処理 group_by関数 – dplyrパッケージ

tidyverseでデータフレームをグループ別に処理する場合、dplyrパッケージのgroup_by関数を使います。group_by関数以降の処理では、グループ毎に計算が行われます。Rの標準的な操作なら、apply系関数を使って同じような処理を行えます。

行をグループ毎に分ける

dplyrパッケージのgroup_by関数を使えば、データフレームから行をグループ毎に分けることができます。グループ分けは列名を指定し、複数指定してより細かいグループに分けることもできます。グループ分けした後、summarize関数やfilter関数などを使って、グループ毎の計算を行います。tidyverseパッケージをロードすると使えるようになります。

書式

group_by関数は、第1引数にデータ、第2引数以降にグループ分けする列名を指定します。グループ分けに使う列は、列挙して複数指定できます。尚、パイプ(%>%)を使って連続的に処理を記述する場合は、第1引数のデータは省略することができます。

> summarize or filter((group_by(データ, グループ列1, グループ列2), 計算式)

> データ %>% group_by(グループ列1, グループ列2) %>% summarize or filter(計算式)

グループに処理を行う

単純なグループ

group_by関数によるグループ分けは「Species」のみを指定して、グループ毎(Species毎)に「Petal.Width」のtop2(大きいものから2個)を抽出しました。

 1: > iris %>% group_by(Species) %>% top_n(2, Petal.Width)
 2: # A tibble: 7 x 5
 3: # Groups:   Species [3]
 4:   Sepal.Length Sepal.Width Petal.Length Petal.Width Species   
 5:          <dbl>       <dbl>        <dbl>       <dbl> <fct>     
 6: 1          5.1         3.3          1.7         0.5 setosa    
 7: 2          5           3.5          1.6         0.6 setosa    
 8: 3          5.9         3.2          4.8         1.8 versicolor
 9: 4          6.7         3            5           1.7 versicolor
10: 5          6.3         3.3          6           2.5 virginica 
11: 6          7.2         3.6          6.1         2.5 virginica 
12: 7          6.7         3.3          5.7         2.5 virginica

複数指定したグループ

group_by関数によるグループ分けで「id」のみを指定した場合と、複数「id」「number」を指定してより細かいグループ分けをした場合を比較しました。前者は、A・Bからなる2つのグループ分けなので、それぞれの行数は2行・1行。後者は、A_10, B_20、A_30のグループで3つに分かれたので、それぞれの行数は1行ずつになりました。グループの分けかたによって、以降の処理結果が変わることがわかります。

 1: > my_data <- data.frame(id=c("A", "B", "A"), number=c(10, 20, 30))
 2: > my_data
 3:   id number
 4: 1  A     10
 5: 2  B     20
 6: 3  A     30
 7: 
 8: > my_data %>% group_by(id) %>% mutate(lines = n())
 9: # A tibble: 3 x 3
10: # Groups:   id [2]
11:   id    number lines
12:   <fct>  <dbl> <int>
13: 1 A         10     2
14: 2 B         20     1
15: 3 A         30     2
16: 
17: > my_data %>% group_by(id, number) %>% mutate(lines = n())
18: # A tibble: 3 x 3
19: # Groups:   id, number [3]
20:   id    number lines
21:   <fct>  <dbl> <int>
22: 1 A         10     1
23: 2 B         20     1
24: 3 A         30     1

グループ毎にまとめる

group_by関数によるグループ分けは「Species」のみを指定して、グループ毎(Species毎)に集計(summarize)しました。「number」をグループ毎にreduce関数で加算し(A:10+30, B:20)、add列に整理しました。

 1: > my_data
 2:   id number
 3: 1  A     10
 4: 2  B     20
 5: 3  A     30
 6: 
 7: > my_data %>% group_by(id) %>% summarize(add = purrr::reduce(number, `+`))
 8:   id      add
 9:   <fct> <dbl>
10: 1 A        40
11: 2 B        20

Rの標準的な操作

データフレームに対してグループ毎に集計などの処理を行う場合、Rの標準的な方法ではapply系関数を使うと同じような処理を行うことができます。例ではtapplyを使いました。データフレーム([行,列])のfactorでグループ分けされている列に対して、グループ毎の加算行いました。tapplyには、処理対象の列、グループ毎のファクターのリスト、処理内容を与えました。

 1: > my_data
 2:   id number
 3: 1  A     10
 4: 2  B     20
 5: 3  A     30
 6: 
 7: > attach(my_data)
 8: 
 9: > id
10: A B A
11: Levels: A B
12: 
13: > tapply(number, id, sum)
14:  A  B 
15: 40 20

まとめ

  • tidyverseでデータフレームをグループ別に処理する場合、dplyrパッケージのgroup_by関数を使う。
  • group_by関数で分けた後は、グループ毎に集計などが可能で、summarizeやfilterなどが用いられることが多い。
  • Rの標準的な操作なら、apply系関数で同じような処理が可能。