dplyr の動詞は、グループ化されたデータフレーム(grouped_df
オブジェクト)に適用すると特に強力です。 この vignette では、以下のことを説明します。
group_by()
とその仲間を使って、グループ化、検査、グループ解除を行う方法。
グループ化されたデータフレームに適用すると、個々の dplyr 動詞の動作がどのように変わるか。 データフレーム。
動詞の中から「現在の」グループに関するデータにアクセスする方法。
まずは、dplyrをロードするところから始めましょう。:
group_by()
最も重要なグループ化のための動詞は、group_by()
です。この動詞は、データフレームとグループ化するための1つ以上の変数を受け取ります。:
データを表示するとグループ化されているのがわかります。:
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, blue red 33 none mascu…
#> 4 Darth V… 202 136 none white yellow 41.9 male mascu…
#> # … with 83 more rows, and 5 more variables: homeworld <chr>, species <chr>,
#> # films <list>, vehicles <list>, starships <list>
by_sex_gender
#> # A tibble: 87 x 14
#> # Groups: sex, gender [6]
#> 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, blue red 33 none mascu…
#> 4 Darth V… 202 136 none white yellow 41.9 male mascu…
#> # … with 83 more rows, and 5 more variables: homeworld <chr>, species <chr>,
#> # films <list>, vehicles <list>, starships <list>
訳注: tally = 勘定
また、tally()
を使って各グループの行数を数えることもできます。最大のグループを前面に表示したい場合は、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
#> # … with 34 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
#> # … with 2 more rows
既存の変数でグループ化するだけでなく,既存の変数の任意の関数でグループ化することもできます。これは、group_by()
の前に mutate()
を実行するのと同じです。 :
グループのデータは、group_keys()
で見ることができます。グループごとに1行、グループ変数ごとに1列が用意されています。:
by_species %>% group_keys()
#> # A tibble: 38 x 1
#> species
#> * <chr>
#> 1 Aleena
#> 2 Besalisk
#> 3 Cerean
#> 4 Chagrian
#> # … with 34 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
#> # … with 2 more rows
各行がどのグループに属しているかは、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
また、各グループがどの行を含んでいるかは、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()
を使ってください。:
すでにグループ化されているデータセットに group_by()
を適用すると、既存のグループ化変数が上書きされます。0 例えば、以下のコードでは species
ではなく homeworld
でグループ化しています。
by_species %>%
group_by(homeworld) %>%
tally()
#> # A tibble: 49 x 2
#> homeworld n
#> <chr> <int>
#> 1 Alderaan 3
#> 2 Aleen Minor 1
#> 3 Bespin 1
#> 4 Bestine IV 1
#> # … with 45 more rows
グループ化を 強化 するには、.add = TRUE
1を使用します。例えば、次のコードは、species と homeporld でグループ化します。:
すべてのグルーピング変数を削除するには、ungroup()
を使います。
また、削除したい変数をリストアップして、選択的にグループ解除することもできます。:
以下のセクションでは、グループ化が主な dplyr の動詞にどのように影響するかを説明します。
summarise()
summarise()
は、各グループの要約を計算します。 つまり、group_keys()
から始まり、右辺に要約変数を追加していきます。
by_species %>%
summarise(
n = n(),
height = mean(height, na.rm = TRUE)
)
#> `summarise()` ungrouping output (override with `.groups` argument)
#> # A tibble: 38 x 3
#> species n height
#> <chr> <int> <dbl>
#> 1 Aleena 1 79
#> 2 Besalisk 1 198
#> 3 Cerean 1 198
#> 4 Chagrian 1 196
#> # … with 34 more rows
.groups=
引数は、出力のグループ化構造を制御します。 右側のグループ化変数を削除するという歴史的な動作は、メッセージなしの .groups = "drop_last"
や、メッセージ付きの .groups = NULL
(デフォルト)に対応します。
by_sex_gender %>%
summarise(n = n()) %>%
group_vars()
#> `summarise()` regrouping output by 'sex' (override with `.groups` argument)
#> [1] "sex"
by_sex_gender %>%
summarise(n = n(), .groups = "drop_last") %>%
group_vars()
#> [1] "sex"
バージョン1.0.0以降では、グループを保持したり(.groups = "keep"
)、削除したり(.groups = "drop"
)することもできます。
by_sex_gender %>%
summarise(n = n(), .groups = "keep") %>%
group_vars()
#> [1] "sex" "gender"
by_sex_gender %>%
summarise(n = n(), .groups = "drop") %>%
group_vars()
#> character(0)
出力がグループ化変数を持たなくなると、グループ化されていない(つまり通常のティブル)になります。
select()
, rename()
, relocate()
についてrename()
と relocate()
は、既存のカラムの名前や位置に影響を与えるだけなので、グループ化されたデータでもグループ化されていないデータでも同じように動作します。 グループ化された select()
は,グループ化変数を常に含むことを除けば、グループ化されていない select とほとんど同じです。
by_species %>% select(mass)
#> Adding missing grouping variables: `species`
#> # A tibble: 87 x 2
#> # Groups: species [38]
#> species mass
#> <chr> <dbl>
#> 1 Human 77
#> 2 Droid 75
#> 3 Droid 32
#> 4 Human 136
#> # … with 83 more rows
グループ化された変数が不要な場合は、まず ungroup()
を実行する必要があります。(この設計は間違いの可能性もありますが、今はこれで我慢しています。)
arrange()
グループ化された arrange()
は、.by_group = TRUE
を設定しない限り、グループ化されていない arrange()
と同じです。 グループ化された arrange()
は、グループ化されていない arrange()
と同じです。
by_species %>%
arrange(desc(mass)) %>%
relocate(species, mass)
#> # A tibble: 87 x 14
#> # Groups: species [38]
#> species mass name height hair_color skin_color eye_color birth_year sex
#> <chr> <dbl> <chr> <int> <chr> <chr> <chr> <dbl> <chr>
#> 1 Hutt 1358 Jabba … 175 <NA> green-tan,… orange 600 herm…
#> 2 Kaleesh 159 Grievo… 216 none brown, whi… green, y… NA male
#> 3 Droid 140 IG-88 200 none metal red 15 none
#> 4 Human 136 Darth … 202 none white yellow 41.9 male
#> # … with 83 more rows, and 5 more variables: gender <chr>, homeworld <chr>,
#> # films <list>, vehicles <list>, starships <list>
by_species %>%
arrange(desc(mass), .by_group = TRUE) %>%
relocate(species, mass)
#> # A tibble: 87 x 14
#> # Groups: species [38]
#> species mass name height hair_color skin_color eye_color birth_year sex
#> <chr> <dbl> <chr> <int> <chr> <chr> <chr> <dbl> <chr>
#> 1 Aleena 15 Ratts … 79 none grey, blue unknown NA male
#> 2 Besalisk 102 Dexter… 198 none brown yellow NA male
#> 3 Cerean 82 Ki-Adi… 198 white pale yellow 92 male
#> 4 Chagrian NA Mas Am… 196 none blue blue NA male
#> # … with 83 more rows, and 5 more variables: gender <chr>, homeworld <chr>,
#> # films <list>, vehicles <list>, starships <list>
2番目の例では、species
(group_by()
ステートメントから)、次にmass
(species 内)でソートされていることに注意してください。
mutate()
とtransmute()
についてベクトル化された関数を使った単純なケースでは、グループ化された mutate()
とグループ化されていない mutate()
は同じ結果になります。 summary 関数と併用する場合は異なります。
# Subtract off global mean
starwars %>%
select(name, homeworld, mass) %>%
mutate(standard_mass = mass - mean(mass, na.rm = TRUE))
#> # A tibble: 87 x 4
#> name homeworld mass standard_mass
#> <chr> <chr> <dbl> <dbl>
#> 1 Luke Skywalker Tatooine 77 -20.3
#> 2 C-3PO Tatooine 75 -22.3
#> 3 R2-D2 Naboo 32 -65.3
#> 4 Darth Vader Tatooine 136 38.7
#> # … with 83 more rows
# Subtract off homeworld mean
starwars %>%
select(name, homeworld, mass) %>%
group_by(homeworld) %>%
mutate(standard_mass = mass - mean(mass, na.rm = TRUE))
#> # A tibble: 87 x 4
#> # Groups: homeworld [49]
#> name homeworld mass standard_mass
#> <chr> <chr> <dbl> <dbl>
#> 1 Luke Skywalker Tatooine 77 -8.38
#> 2 C-3PO Tatooine 75 -10.4
#> 3 R2-D2 Naboo 32 -32.2
#> 4 Darth Vader Tatooine 136 50.6
#> # … with 83 more rows
または、min_rank()
のようなウィンドウ関数で。:
# Overall rank
starwars %>%
select(name, homeworld, height) %>%
mutate(rank = min_rank(height))
#> # A tibble: 87 x 4
#> name homeworld height rank
#> <chr> <chr> <int> <int>
#> 1 Luke Skywalker Tatooine 172 29
#> 2 C-3PO Tatooine 167 21
#> 3 R2-D2 Naboo 96 5
#> 4 Darth Vader Tatooine 202 72
#> # … with 83 more rows
# Rank per homeworld
starwars %>%
select(name, homeworld, height) %>%
group_by(homeworld) %>%
mutate(rank = min_rank(height))
#> # A tibble: 87 x 4
#> # Groups: homeworld [49]
#> name homeworld height rank
#> <chr> <chr> <int> <int>
#> 1 Luke Skywalker Tatooine 172 5
#> 2 C-3PO Tatooine 167 4
#> 3 R2-D2 Naboo 96 1
#> 4 Darth Vader Tatooine 202 10
#> # … with 83 more rows
filter()
グループ化された filter()
は、効果的に mutate()
を実行して論理変数を生成し、その変数が TRUE
である行のみを保持する。 これはグループ化されたフィルタが要約関数と一緒に使えることを意味する。 例えば、それぞれの speicies の最も背の高いキャラクターを見つけることができる。
by_species %>%
select(name, species, height) %>%
filter(height == max(height))
#> # A tibble: 35 x 3
#> # Groups: species [35]
#> name species height
#> <chr> <chr> <int>
#> 1 Greedo Rodian 173
#> 2 Jabba Desilijic Tiure Hutt 175
#> 3 Yoda Yoda's species 66
#> 4 Bossk Trandoshan 190
#> # … with 31 more rows
また、filter()
を使ってグループ全体を削除することもできます。例えば、次のコードでは、メンバーが一人しかいないグループをすべて削除しています。
slice()
とその仲間slice()
とその仲間(slice_head()
, slice_tail()
, slice_sample()
, slice_min()
, slice_max()
)は、グループ内の行を選択します。 例えば、それぞれの speicies の中の最初の観測値を選択することができます。
by_species %>%
relocate(species) %>%
slice(1)
#> # A tibble: 38 x 14
#> # Groups: species [38]
#> species name height mass hair_color skin_color eye_color birth_year sex
#> <chr> <chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr>
#> 1 Aleena Ratts … 79 15 none grey, blue unknown NA male
#> 2 Besalisk Dexter… 198 102 none brown yellow NA male
#> 3 Cerean Ki-Adi… 198 82 white pale yellow 92 male
#> 4 Chagrian Mas Am… 196 NA none blue blue NA male
#> # … with 34 more rows, and 5 more variables: gender <chr>, homeworld <chr>,
#> # films <list>, vehicles <list>, starships <list>
同様に,変数の最小の n
個の値を選択するには,slice_min()
を用いることができます.
by_species %>%
filter(!is.na(height)) %>%
slice_min(height, n = 2)
#> # A tibble: 48 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 Ratts Ty… 79 15 none grey, blue unknown NA male mascu…
#> 2 Dexter J… 198 102 none brown yellow NA male mascu…
#> 3 Ki-Adi-M… 198 82 white pale yellow 92 male mascu…
#> 4 Mas Amed… 196 NA none blue blue NA male mascu…
#> # … with 44 more rows, and 5 more variables: homeworld <chr>, species <chr>,
#> # films <list>, vehicles <list>, starships <list>
dplyrの動詞の中では、cur_
という接頭辞を持つ関数群を使って、「現在の」グループの様々なプロパティにアクセスすることができます。 これらの関数は、通常、dplyr の日常的な使用に必要ですが、dplyr の動詞の典型的な制約から解放されるので便利です。
cur_data()
cur_data()
は、現在のグループを、グループ変数を除いて返します。 データフレーム全体を取得する関数に与えると便利です。 例えば、以下のコードは、各種族に mass ~ height
の線形モデルをフィットさせます。
by_species %>%
filter(n() > 1) %>%
mutate(mod = list(lm(mass ~ height, data = cur_data())))
#> # A tibble: 58 x 15
#> # Groups: species [9]
#> 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, blue red 33 none mascu…
#> 4 Darth V… 202 136 none white yellow 41.9 male mascu…
#> # … with 54 more rows, and 6 more variables: homeworld <chr>, species <chr>,
#> # films <list>, vehicles <list>, starships <list>, mod <list>
cur_group()
と cur_group_id()
です。cur_group_id()
は、現在のグループにユニークな数値-を与えます。これは、外部のデータ構造にインデックスを作成したい場合に役立つことがあります。
by_species %>%
arrange(species) %>%
select(name, species, homeworld) %>%
mutate(id = cur_group_id())
#> # A tibble: 87 x 4
#> # Groups: species [38]
#> name species homeworld id
#> <chr> <chr> <chr> <int>
#> 1 Ratts Tyerell Aleena Aleen Minor 1
#> 2 Dexter Jettster Besalisk Ojom 2
#> 3 Ki-Adi-Mundi Cerean Cerea 3
#> 4 Mas Amedda Chagrian Champala 4
#> # … with 83 more rows
なお、dplyr 1.0.0では、引数が add = TRUE
から .add = TRUE
に変更されました。↩︎