Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up
for free
dplyr 1.0.0の新機能 / dplyr 1.0.0
松村優哉
June 27, 2020
Programming
2
3.1k
dplyr 1.0.0の新機能 / dplyr 1.0.0
松村優哉
June 27, 2020
Tweet
Share
More Decks by 松村優哉
See All by 松村優哉
y__mattu
1
320
Other Decks in Programming
See All in Programming
shin1x1
0
590
akatsukinewgrad
0
160
makicamel
1
170
line_developers_tw
1
430
xrdnk
0
130
momofff
0
160
itosho525
0
360
cocoeyes02
0
220
yaamaa
0
410
adoranwodo
0
220
zsmb
1
120
wasabeef
1
560
Featured
See All Featured
chrislema
231
16k
jasonvnalue
82
8k
jonyablonski
14
1.1k
tammielis
237
23k
caitiem20
308
17k
carmenhchung
26
1.3k
tanoku
258
24k
tanoku
86
8.5k
brettharned
93
3k
philnash
8
490
dotmariusz
94
5.1k
hannesfritz
27
930
Transcript
dplyr1.0.0の新機能 @y__mattu 2020/6/27 Tokyo.R #86 応⽤セッション
誰︖ • 名前: 松村優哉 • 学⽣時代の専⾨: 計量経済学、 ベイズ統計、因果推論、マーケティング (研究室のAWSの管理とかもやってた) •
⾔語: R, Python • HR系企業でデータサイエンティストしてます • Tokyo.R 運営(雑⽤, ⾳響) @y__mattu ymattu 2
#宇宙本 3 あれからもう2年… RStudioのバージョンも上がったし、 パッケージも新機能がいろいろ登場した。 例えば、 tidyr 1.0.0の新機能 pivot_*() /
tidyr-pivot ※宇宙本に書いてある内容は、 基本的に今の時代でも使える内容です。
今回は、dplyr1.0.0について。 4 2020/3/10 訳: dply1.0.0もうすぐ出るよ。 新機能を⼀部紹介するね 訳: dplyr 1.0.0 出たぜ︕
2020/6/2 2020/5/7 訳:折返し地点︕
今⽇のお話 • dplyr1.0.0での変化 • 1.0.0で変更があったもの • 1.0.0で新しく追加されたもの の中から影響が⼤きそう、注⽬すべきポイント ※20分しかないので、要点を絞っていきます ※ただし、余談として
• 「新しいバージョンやパッケージを試すときのポイント」 • 「関数のライフサイクル」 みたいな話を挟んでいきます ※全変更点⼀覧はリリースノートを参照 5
早速dplyr 1.0.0を試してみよう︕ 〜新しいパッケージを試すときのポイント︕〜 6 Dockerを使うのが吉︕︕ Dockerを使うと、⾃分の環境を汚さずにお⼿軽に新しいものが試せます!
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環境
ブラウザで localhost:8787 に接続 8 ユーザー名はrstudio、 初期パスワードはrstudio
dply1.0.0がインストールされてます 9
使うデータ1 10 > library(dplyr) > glimpse(starwars) Rows: 87 Columns: 14
$ name <chr> "Luke Skywalker", "C-3PO", "R2-D2", "Darth Vader", "Leia Organa", "Owen La… $ height <int> 172, 167, 96, 202, 150, 178, 165, 97, 183, 182, 188, 180, 228, 180, 173, 1… $ mass <dbl> 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 <chr> "blond", NA, NA, "none", "brown", "brown, grey", "brown", NA, "black", "au… $ skin_color <chr> "fair", "gold", "white, blue", "white", "light", "light", "light", "white,… $ eye_color <chr> "blue", "yellow", "red", "yellow", "brown", "blue", "blue", "red", "brown"… $ birth_year <dbl> 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 <chr> "male", "none", "none", "male", "female", "male", "female", "none", "male"… $ gender <chr> "masculine", "masculine", "masculine", "masculine", "feminine", "masculine… $homeworld <chr> "Tatooine", "Tatooine", "Naboo", "Tatooine", "Alderaan", "Tatooine", "Tato… $ species <chr> "Human", "Droid", "Droid", "Human", "Human", "Human", "Human", "Droid", "H… $ films <list> [<"The Empire Strikes Back", "Revenge of the Sith", "Return of the Jedi",… $ vehicles <list> [<"Snowspeeder", "Imperial Speeder Bike">, <>, <>, <>, "Imperial Speeder … $ starships <list> [<"X-wing", "Imperial shuttle">, <>, <>, "TIE Advanced x1", <>, <>, <>, <…
使うデータ2 11 > glimpse(iris) Rows: 150 Columns: 5 $ Sepal.Length
<dbl> 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 <dbl> 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 <dbl> 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 <dbl> 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 <fct> setosa, setosa, setosa, setosa, setosa, setosa, setosa, setosa, setosa, setosa, setosa, se…
使うデータ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
dplyr1.0.0の変更点その0 ロゴ
ロゴが変わっただと︕︖ 14 旧ロゴ 新ロゴ
dplyr1.0.0の変更点その1 summarise()の挙動
.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 <chr> <chr> <dbl> 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 ???
.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 <chr> <chr> <dbl> 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) が消えた
.groups引数でグルーピングを制御できるようになった 18 starwars %>% group_by(gender, homeworld) %>% summarise(. groups =
“drop”, height = mean(height)) # A tibble: 58 x 3 gender homeworld height <chr> <chr> <dbl> 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 すべてのグルーピング が消えた
.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 <chr> <chr> <dbl> 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 すべてのグルーピング が残る
注意︕.groupsを書かなかったときの挙動 20 dplyr::summarise()のhelp .groupsを指定しない場合、結果の⼤きさが1のときは”drop_last”が、 ⼤きさが変動する場合は”keep”になります。 options(“dplyr.summarise.inform” = FALSE)をやらない限り、 どれが選ばれたのかメッセージとして出⼒されます。 しばらくは明⽰的に.groupsを書いたほうがトラブルが少なくて済みそう
dplyr1.0.0の変更点その2 rowwise()
そもそも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: <by row> # A tibble: 9 x 3 x y m <int> <int> <dbl> 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
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(…)) みたいな書き⽅
dplyr1.0.0では、正式に使ってOKに (stableというステータスに) 24 df %>% rowwise() %>% mutate(m = mean(c(x,
y))) Source: local data frame [9 x 3] Groups: <by row> # A tibble: 9 x 3 x y m <int> <int> <dbl> 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という扱い ※
dplyr1.0.0の追加関数その1 across(), where()
***_at(), ***_if(), ***_allの書き⽅が変わります︕ 26 starwars %>% group_by(species) %>% filter(n() >
1) %>% summarise_at(vars(gender, homeworld), n_distinct)) species gender homeworld <char> <int> <int> 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: <NA> 2 3 特定の列だけに、特定の処理をする書き⽅ starwars %>% group_by(species) %>% filter(n() > 1) %>% summarise(across(c(gender, homeworld), n_distinct)) species gender homeworld <char> <int> <int> 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: <NA> 2 3 複数列はc()でくくる (tidyr::pivot_***() と同じ書き⽅) ***_atの場合
27 starwars %>% group_by(species) %>% filter(n() > 1) %>% summarise_if(is.numeric,
mean, na.rm = TRUE) species height mass birth_year <char> <num> <num> <num> 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: <NA> 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 <chr> <dbl> <dbl> <dbl> 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の場合 数値型の列だけを処理
***_at() ***(across(列の指定, 処理)) ***_if ***(across(where(列の型の指定), 処理)) ***_all ***(across(everything(), 処理)) ***_at(),
***_if(), ***_allとの対応 28 ***には、mutate/summariseが⼊る
dplyr1.0.0の追加関数その2 relocate()
列の並び替えを簡単にできる関数 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
dplyr1.0.0の追加関数その3 slice_***()
いくつかの関数が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::
関数のライフサイクルについて 主に開発者向け
lifecycle パッケージ 34 https://lifecycle.r-lib.org/articles/lifecycle.html 旧: retired
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) } <bytecode: 0x55fb29fd93f8> <environment: namespace:dplyr> 例: mutate_at() バージョン、旧関数、代⽤の新関数を記述
この資料で出てきた旧関数の1.0.0での扱い 36 rowwise() ***_at() ***_if() ***_all() top_n() top_frac() sample_n() sample_frac()
まとめ
まとめ • dplyrがついに1.0.0に︕ • ***_at(), ***_if(), ***_all()の書き⽅が変わる →***(across(…))に︕ →以前のコードが動かなくなることはすぐにはないけど 今後の書き⽅は変えたほうが良い
• summariseの.groups引数は注意︕ • rowwise()を含め、purrrパッケージとの対応は今後もアップデート がありそうなので、備えよう 38
その他の参考リンク • 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
Enjoy!