Slide 1

Slide 1 text

dplyr1.0.0の新機能 @y__mattu 2020/6/27 Tokyo.R #86 応⽤セッション

Slide 2

Slide 2 text

誰︖ • 名前: 松村優哉 • 学⽣時代の専⾨: 計量経済学、 ベイズ統計、因果推論、マーケティング (研究室のAWSの管理とかもやってた) • ⾔語: R, Python • HR系企業でデータサイエンティストしてます • Tokyo.R 運営(雑⽤, ⾳響) @y__mattu ymattu 2

Slide 3

Slide 3 text

#宇宙本 3 あれからもう2年… RStudioのバージョンも上がったし、 パッケージも新機能がいろいろ登場した。 例えば、 tidyr 1.0.0の新機能 pivot_*() / tidyr-pivot ※宇宙本に書いてある内容は、 基本的に今の時代でも使える内容です。

Slide 4

Slide 4 text

今回は、dplyr1.0.0について。 4 2020/3/10 訳: dply1.0.0もうすぐ出るよ。 新機能を⼀部紹介するね 訳: dplyr 1.0.0 出たぜ︕ 2020/6/2 2020/5/7 訳:折返し地点︕

Slide 5

Slide 5 text

今⽇のお話 • dplyr1.0.0での変化 • 1.0.0で変更があったもの • 1.0.0で新しく追加されたもの の中から影響が⼤きそう、注⽬すべきポイント ※20分しかないので、要点を絞っていきます ※ただし、余談として • 「新しいバージョンやパッケージを試すときのポイント」 • 「関数のライフサイクル」 みたいな話を挟んでいきます ※全変更点⼀覧はリリースノートを参照 5

Slide 6

Slide 6 text

早速dplyr 1.0.0を試してみよう︕ 〜新しいパッケージを試すときのポイント︕〜 6 Dockerを使うのが吉︕︕ Dockerを使うと、⾃分の環境を汚さずにお⼿軽に新しいものが試せます!

Slide 7

Slide 7 text

Dockerでdplyr1.0.0を試す 7 docker pull rocker/tidyverse:4.0.0 docker run \ -p 8787:8787 \ -v ~/Desktop/dplyr1:/home/rstudio \ -d --name try-dplyr_1 \ rocker/tidyverse:4.0.0 緑⾊のところは、それぞれ、ローカルのディレクトリ、コンテナ名をそれぞれ任意に設定 R 4.0.0 上でtidyverseが インストールされたRstudio環境

Slide 8

Slide 8 text

ブラウザで localhost:8787 に接続 8 ユーザー名はrstudio、 初期パスワードはrstudio

Slide 9

Slide 9 text

dply1.0.0がインストールされてます 9

Slide 10

Slide 10 text

使うデータ1 10 > library(dplyr) > glimpse(starwars) Rows: 87 Columns: 14 $ name "Luke Skywalker", "C-3PO", "R2-D2", "Darth Vader", "Leia Organa", "Owen La… $ height 172, 167, 96, 202, 150, 178, 165, 97, 183, 182, 188, 180, 228, 180, 173, 1… $ mass 77.0, 75.0, 32.0, 136.0, 49.0, 120.0, 75.0, 32.0, 84.0, 77.0, 84.0, NA, 11… $ hair_color "blond", NA, NA, "none", "brown", "brown, grey", "brown", NA, "black", "au… $ skin_color "fair", "gold", "white, blue", "white", "light", "light", "light", "white,… $ eye_color "blue", "yellow", "red", "yellow", "brown", "blue", "blue", "red", "brown"… $ birth_year 19.0, 112.0, 33.0, 41.9, 19.0, 52.0, 47.0, NA, 24.0, 57.0, 41.9, 64.0, 200… $ sex "male", "none", "none", "male", "female", "male", "female", "none", "male"… $ gender "masculine", "masculine", "masculine", "masculine", "feminine", "masculine… $homeworld "Tatooine", "Tatooine", "Naboo", "Tatooine", "Alderaan", "Tatooine", "Tato… $ species "Human", "Droid", "Droid", "Human", "Human", "Human", "Human", "Droid", "H… $ films [<"The Empire Strikes Back", "Revenge of the Sith", "Return of the Jedi",… $ vehicles [<"Snowspeeder", "Imperial Speeder Bike">, <>, <>, <>, "Imperial Speeder … $ starships [<"X-wing", "Imperial shuttle">, <>, <>, "TIE Advanced x1", <>, <>, <>, <…

Slide 11

Slide 11 text

使うデータ2 11 > glimpse(iris) Rows: 150 Columns: 5 $ Sepal.Length 5.1, 4.9, 4.7, 4.6, 5.0, 5.4, 4.6, 5.0, 4.4, 4.9, 5.4, 4.8, 4.8, 4.3, 5.8, 5.7, 5.4, 5.1, … $ Sepal.Width 3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.4, 3.0, 3.0, 4.0, 4.4, 3.9, 3.5, … $ Petal.Length 1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.4, 1.5, 1.5, 1.6, 1.4, 1.1, 1.2, 1.5, 1.3, 1.4, … $ Petal.Width 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.2, 0.1, 0.1, 0.2, 0.4, 0.4, 0.3, … $ Species setosa, setosa, setosa, setosa, setosa, setosa, setosa, setosa, setosa, setosa, setosa, se…

Slide 12

Slide 12 text

使うデータ3 12 > df <- expand.grid(x = 1:3, y = 3:1) > df x y 1 1 3 2 2 3 3 3 3 4 1 2 5 2 2 6 3 2 7 1 1 8 2 1 9 3 1

Slide 13

Slide 13 text

dplyr1.0.0の変更点その0 ロゴ

Slide 14

Slide 14 text

ロゴが変わっただと︕︖ 14 旧ロゴ 新ロゴ

Slide 15

Slide 15 text

dplyr1.0.0の変更点その1 summarise()の挙動

Slide 16

Slide 16 text

.groups引数で、グループの挙動を制御 16 starwars %>% group_by(gender, homeworld) %>% summarise(height = mean(height)) `summarise()` regrouping output by 'gender' (override with `.groups` argument)# A tibble: 58 x 3 # A tibble: 58 x 3 # Groups: gender [3] gender homeworld height 1 feminine Alderaan 150 2 feminine Chandrila 150 3 feminine Coruscant 176. 4 feminine Kamino 213 5 feminine Mirial 168 6 feminine Naboo 162. 7 feminine Ryloth 178 8 feminine Shili 178 9 feminine Tatooine 164 10 feminine Zolan 168 # … with 48 more rows ???

Slide 17

Slide 17 text

.groups引数でグルーピングを制御できるようになった 17 starwars %>% group_by(gender, homeworld) %>% summarise(. groups = “drop_last”, height = mean(height)) # A tibble: 58 x 3 # Groups: gender [3] gender homeworld height 1 feminine Alderaan 150 2 feminine Chandrila 150 3 feminine Coruscant 176. 4 feminine Kamino 213 5 feminine Mirial. 168 6 feminine Naboo 162. 7 feminine Ryloth 178 8 feminine Shili 178 9 feminine Tatooine 164 10 feminine Zolan 168 # … with 48 more rows 他に、”drop”と”keep”と”rowwiseが 選択可能 最後のグルーピング(ここではhomeworld) が消えた

Slide 18

Slide 18 text

.groups引数でグルーピングを制御できるようになった 18 starwars %>% group_by(gender, homeworld) %>% summarise(. groups = “drop”, height = mean(height)) # A tibble: 58 x 3 gender homeworld height 1 feminine Alderaan 150 2 feminine Chandrila 150 3 feminine Coruscant 176. 4 feminine Kamino 213 5 feminine Mirial. 168 6 feminine Naboo 162. 7 feminine Ryloth 178 8 feminine Shili 178 9 feminine Tatooine 164 10 feminine Zolan 168 # … with 48 more rows すべてのグルーピング が消えた

Slide 19

Slide 19 text

.groups引数でグルーピングを制御できるようになった 19 starwars %>% group_by(gender, homeworld) %>% summarise(. groups = keep”, height = mean(height)) # A tibble: 58 x 3 # Groups: gender, homeworld [58] gender homeworld height 1 feminine Alderaan 150 2 feminine Chandrila 150 3 feminine Coruscant 176. 4 feminine Kamino 213 5 feminine Mirial. 168 6 feminine Naboo 162. 7 feminine Ryloth 178 8 feminine Shili 178 9 feminine Tatooine 164 10 feminine Zolan 168 # … with 48 more rows すべてのグルーピング が残る

Slide 20

Slide 20 text

注意︕.groupsを書かなかったときの挙動 20 dplyr::summarise()のhelp .groupsを指定しない場合、結果の⼤きさが1のときは”drop_last”が、 ⼤きさが変動する場合は”keep”になります。 options(“dplyr.summarise.inform” = FALSE)をやらない限り、 どれが選ばれたのかメッセージとして出⼒されます。 しばらくは明⽰的に.groupsを書いたほうがトラブルが少なくて済みそう

Slide 21

Slide 21 text

dplyr1.0.0の変更点その2 rowwise()

Slide 22

Slide 22 text

そもそもrowwise()ってどんな関数︖ 22 df %>% mutate(m = mean(c(x, y))) x y m 1 1 3 2 2 2 3 2 3 3 3 2 4 1 2 2 5 2 2 2 6 3 2 2 7 1 1 2 8 2 1 2 9 3 1 2 もともと、レコード⽅向の操作は苦⼿ なので、それを解消するもの df %>% rowwise() %>% mutate(m = mean(c(x, y))) Source: local data frame [9 x 3] Groups: # A tibble: 9 x 3 x y m 1 1 3 2 2 2 3 2.5 3 3 3 3 4 1 2 1.5 5 2 2 2 6 3 2 2.5 7 1 1 1 8 2 1 1.5 9 3 1 2

Slide 23

Slide 23 text

rowwiseの歴史 23 • 2014年頃(dplyr0.2くらい) →rowwise()はすでにあった • 2017年頃(dplyr0.7くらい) →purrrパッケージやtidyr::nest()の充実で 推奨されなくなる (将来的になくなるとの⾒解も) • 2019年頃(dplyr0.8くらい) →questioning(使ってもいいけど、ちょっ とどうなんだろう︖でも代替⼿段はない)と いうステータスになっていた 参考: do()とかrowwise()は今から覚える必要はない(たぶん) https://notchained.hatenablog.com/entry/2017/11/15/212117 df %>% mutate(m = pmap(…)) みたいな書き⽅

Slide 24

Slide 24 text

dplyr1.0.0では、正式に使ってOKに (stableというステータスに) 24 df %>% rowwise() %>% mutate(m = mean(c(x, y))) Source: local data frame [9 x 3] Groups: # A tibble: 9 x 3 x y m 1 1 3 2 2 2 3 2.5 3 3 3 3 4 1 2 1.5 5 2 2 2 6 3 2 2.5 7 1 1 1 8 2 1 1.5 9 3 1 2 使い⽅はこれまでと⼀緒 ちなみに、 「purrrの機能を減らして dplyrでもっと⾊々やれるようにしよう」 という動きもあるみたいです 昔purrrlyrというパッケージもあったし、 purrrとdplyrの関係はこれからも変わっていきそう… ※いまはretiredという扱い ※

Slide 25

Slide 25 text

dplyr1.0.0の追加関数その1 across(), where()

Slide 26

Slide 26 text

***_at(), ***_if(), ***_allの書き⽅が変わります︕ 26 starwars %>% group_by(species) %>% filter(n() > 1) %>% summarise_at(vars(gender, homeworld), n_distinct)) species gender homeworld 1: Droid 2 3 2: Gungan 1 1 3: Human 2 16 4: Kaminoan 2 1 5: Mirialan 1 1 6: Twi'lek 2 1 7: Wookiee 1 1 8: Zabrak 1 2 9: 2 3 特定の列だけに、特定の処理をする書き⽅ starwars %>% group_by(species) %>% filter(n() > 1) %>% summarise(across(c(gender, homeworld), n_distinct)) species gender homeworld 1: Droid 2 3 2: Gungan 1 1 3: Human 2 16 4: Kaminoan 2 1 5: Mirialan 1 1 6: Twi'lek 2 1 7: Wookiee 1 1 8: Zabrak 1 2 9: 2 3 複数列はc()でくくる (tidyr::pivot_***() と同じ書き⽅) ***_atの場合

Slide 27

Slide 27 text

27 starwars %>% group_by(species) %>% filter(n() > 1) %>% summarise_if(is.numeric, mean, na.rm = TRUE) species height mass birth_year 1: Droid 140.0000 69.75000 53.33333 2: Gungan 208.6667 74.00000 52.00000 3: Human 176.6452 82.78182 53.41200 4: Kaminoan 221.0000 88.00000 NaN 5: Mirialan 168.0000 53.10000 49.00000 6: Twi'lek 179.0000 55.00000 48.00000 7: Wookiee 231.0000 124.00000 200.00000 8: Zabrak 173.0000 80.00000 54.00000 9: 160.0000 48.00000 62.00000 starwars %>% group_by(species) %>% filter(n() > 1) %>% summarise(across(where(is.numeric), mean, na.rm = TRUE)) `summarise()` ungrouping output (override with `.groups` argument) # A tibble: 9 x 4 species. height mass birth_year 1 Droid 131. 69.8 53.3 2 Gungan 209. 74. 52 3 Human 177. 82.8. 53.4 4 Kaminoan 221 88. NaN 5 Mirialan 168. 53.1. 49 6 Twi'lek 179 55. 48 7 Wookiee 231 124 200 8 Zabrak. 173 80 54 9 NA 181. 48 62 ***_ifの場合 数値型の列だけを処理

Slide 28

Slide 28 text

***_at() ***(across(列の指定, 処理)) ***_if ***(across(where(列の型の指定), 処理)) ***_all ***(across(everything(), 処理)) ***_at(), ***_if(), ***_allとの対応 28 ***には、mutate/summariseが⼊る

Slide 29

Slide 29 text

dplyr1.0.0の追加関数その2 relocate()

Slide 30

Slide 30 text

列の並び替えを簡単にできる関数 30 iris %>% relocate(Species, .before =Sepal.Length) %>% head() Species Sepal.Length Sepal.Width Petal.Length Petal.Width 1 setosa 5.1 3.5 1.4 0.2 2 setosa 4.9 3.0 1.4 0.2 3 setosa 4.7 3.2 1.3 0.2 4 setosa 4.6 3.1 1.5 0.2 5 setosa 5.0 3.6 1.4 0.2 6 setosa 5.4 3.9 1.7 0.4 ※ あとに持っていきたいときは .after

Slide 31

Slide 31 text

dplyr1.0.0の追加関数その3 slice_***()

Slide 32

Slide 32 text

いくつかの関数がslice_***()にまとまります 32 sample_n() sample_frac() ランダムにN件(fracの場合は割合)抽出 top_n() top_frac() 上位N件(fracの場合は割合)抽出 slice_sample() slice_max() slice_min() head() tail() 最初(最後)のN件を抽出 slice_head() slice_tail() ※グループ化されていると グループごとにN件 utils::

Slide 33

Slide 33 text

関数のライフサイクルについて 主に開発者向け

Slide 34

Slide 34 text

lifecycle パッケージ 34 https://lifecycle.r-lib.org/articles/lifecycle.html 旧: retired

Slide 35

Slide 35 text

lifecycle パッケージの使い⽅ 35 > mutate_at function (.tbl, .vars, .funs, ..., .cols = NULL) { lifecycle::signal_superseded("1.0.0", "mutate_at()", "across()") .vars <- check_dot_cols(.vars, .cols) funs <- manip_at(.tbl, .vars, .funs, enquo(.funs), caller_env(), .include_group_vars = TRUE, ..., .caller = "mutate_at") mutate(.tbl, !!!funs) } 例: mutate_at() バージョン、旧関数、代⽤の新関数を記述

Slide 36

Slide 36 text

この資料で出てきた旧関数の1.0.0での扱い 36 rowwise() ***_at() ***_if() ***_all() top_n() top_frac() sample_n() sample_frac()

Slide 37

Slide 37 text

まとめ

Slide 38

Slide 38 text

まとめ • dplyrがついに1.0.0に︕ • ***_at(), ***_if(), ***_all()の書き⽅が変わる →***(across(…))に︕ →以前のコードが動かなくなることはすぐにはないけど 今後の書き⽅は変えたほうが良い • summariseの.groups引数は注意︕ • rowwise()を含め、purrrパッケージとの対応は今後もアップデート がありそうなので、備えよう 38

Slide 39

Slide 39 text

その他の参考リンク • dplyr 1.0.0 available now! – Tidyverse.org https://www.tidyverse.org/blog/2020/06/dplyr-1-0-0/ • dplyr 1.0.0 https://speakerdeck.com/romainfrancois/dplyr-1-dot-0-0 • dplyr ver.1.0.0に追加された関数 + α - 名前はまだない https://saltcooky.hatenablog.com/entry/2020/06/13/161919 • dplyr 1.00のacross関数が便利だった - 世界銀⾏で働くデータサ イエンティストのブログ https://datascience-blog.com/2020/06/02/202427 39

Slide 40

Slide 40 text

Enjoy!