【dplyr】_if()、_at()、_all()が全部across()で済むようになった。
dplyr1.0.0がリリースされました。
今回のアップデートの中で、across()
関数が導入されたのは大きな変化の1つでしょう。
dplyr 1.0.0 will include the powerful new across() function that lets you repeat operations across multiple columns in any dplyr verb. Learn more about it at https://t.co/l25ECyHXlP #rstats
— Hadley Wickham (@hadleywickham) 2020年4月3日
何ができるようになったかというと、
今まではfilter()
関数やmutate()
関数などで複数列を同時に処理する際に
suffixが_if()
や_at()
や_all()
のscope functionを適宜使い分けてましたが、これらが全部across()
関数で済むようになるよって話。
覚えることが減った。やったね。
across()でできること
どう置き換わったのか、例をいくつか。
以下のようなデータフレームを用意します。
set.seed(1) df <- tibble( id=1:10, test1=runif(10,max=100), test2=runif(10,max=100), test3=runif(10,max=100), test4=runif(10,max=100), weight=runif(10, min = 40, max = 80), type=c('A','C','C','B','C','A','C','A','A','B') ) > df # A tibble: 10 x 7 id test1 test2 test3 test4 weight type <int> <dbl> <dbl> <dbl> <dbl> <dbl> <chr> 1 1 47.8 91.3 33.9 43.5 49.6 A 2 2 86.1 29.4 83.9 71.3 42.4 C 3 3 43.8 45.9 34.7 40.0 65.7 C 4 4 24.5 33.2 33.4 32.5 75.1 B 5 5 7.07 65.1 47.6 75.7 71.2 C ...
生徒10人にidが割り振られ、4つのテストの点数と体重、属性(A,B,C)のデータがあります。
データフレームの数字を全て四捨五入したければ
df %>% mutate_if(is.numeric, round)
とするところをacross()
関数で以下のように表現できます。
df %>% mutate(across(is.numeric, round)) > df # A tibble: 10 x 7 id test1 test2 test3 test4 weight type <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <chr> 1 1 27 21 93 48 73 A 2 2 37 18 21 60 66 C 3 3 57 69 65 49 71 C 4 4 91 38 13 19 62 B 5 5 20 77 27 83 61 C ...
今度は、weightに関しては四捨五入せずにそのままにしたいとしましょう。
つまりテストの点だけ四捨五入して、体重のデータは小数点まで表示させたいようなシチュエーションです。
列名を指定するために今度はmutate_if()
ではなくmutate_at()
を用いる必要がありました。
df %>% mutate_at(c("test1","test2","test3","test4"), round)
こちらもacross()
関数で
df %>% mutate(across(test1:test4,round)) > df # A tibble: 10 x 7 id test1 test2 test3 test4 weight type <int> <dbl> <dbl> <dbl> <dbl> <dbl> <chr> 1 1 27 21 93 48 72.8 A 2 2 37 18 21 60 65.9 C 3 3 57 69 65 49 71.3 C 4 4 91 38 13 19 62.1 B 5 5 20 77 27 83 61.2 C ...
と表現できます。複数列を簡略に抽出するためのvars()
関数も必要なくなりました。
また、mutate_all()
関数はacross()
関数の中にeverything()
を用いることで同じ処理ができるようになります。
df %>% mutate_all(mean) #across()を用いた場合 df %>% mutate(across(everything(), mean))
_all()
に関しては便利になったのか正直よく分かりませんが、_at()
と_if()
がうまいこと1つになったのがacross()
関数と言えそうです。
今回は簡単な例でやってみましたが、実務で扱うレベルだと大分記述が楽になるのではないでしょうか。