Upgrade to Pro — share decks privately, control downloads, hide ads and more …

dplyr 1.0.0の新機能 / dplyr 1.0.0

dplyr 1.0.0の新機能 / dplyr 1.0.0

松村優哉

June 27, 2020
Tweet

More Decks by 松村優哉

Other Decks in Programming

Transcript

  1. 誰︖ • 名前: 松村優哉 • 学⽣時代の専⾨: 計量経済学、 ベイズ統計、因果推論、マーケティング (研究室のAWSの管理とかもやってた) •

    ⾔語: R, Python • HR系企業でデータサイエンティストしてます • Tokyo.R 運営(雑⽤, ⾳響) @y__mattu ymattu 2
  2. 今⽇のお話 • dplyr1.0.0での変化 • 1.0.0で変更があったもの • 1.0.0で新しく追加されたもの の中から影響が⼤きそう、注⽬すべきポイント ※20分しかないので、要点を絞っていきます ※ただし、余談として

    • 「新しいバージョンやパッケージを試すときのポイント」 • 「関数のライフサイクル」 みたいな話を挟んでいきます ※全変更点⼀覧はリリースノートを参照 5
  3. 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環境
  4. 使うデータ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", <>, <>, <>, <…
  5. 使うデータ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…
  6. 使うデータ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
  7. .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 ???
  8. .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) が消えた
  9. .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 すべてのグルーピング が消えた
  10. .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 すべてのグルーピング が残る
  11. そもそも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
  12. 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(…)) みたいな書き⽅
  13. 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という扱い ※
  14. ***_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の場合
  15. 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の場合 数値型の列だけを処理
  16. 列の並び替えを簡単にできる関数 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
  17. いくつかの関数が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::
  18. 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() バージョン、旧関数、代⽤の新関数を記述
  19. まとめ • dplyrがついに1.0.0に︕ • ***_at(), ***_if(), ***_all()の書き⽅が変わる →***(across(…))に︕ →以前のコードが動かなくなることはすぐにはないけど 今後の書き⽅は変えたほうが良い

    • summariseの.groups引数は注意︕ • rowwise()を含め、purrrパッケージとの対応は今後もアップデート がありそうなので、備えよう 38
  20. その他の参考リンク • 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