mutate_atで引数付き関数を使う
やりたいこと
mutate
では、関数を以下のように適用を適用することができる。
library(tidyverse) iris %>% group_by(Species) %>% mutate(Sepal.Length_lag2 = lag(Sepal.Length,2)) # Sepal.Length Sepal.Width Petal.Length Petal.Width Species Sepal.Length_lag2 # <dbl> <dbl> <dbl> <dbl> <fct> <dbl> # 1 5.1 3.5 1.4 0.2 setosa NA # 2 4.9 3 1.4 0.2 setosa NA # 3 4.7 3.2 1.3 0.2 setosa 5.1 # 4 4.6 3.1 1.5 0.2 setosa 4.9 # 5 5 3.6 1.4 0.2 setosa 4.7 # 6 5.4 3.9 1.7 0.4 setosa 4.6 # 7 4.6 3.4 1.4 0.3 setosa 5 # 8 5 3.4 1.5 0.2 setosa 5.4 # 9 4.4 2.9 1.4 0.2 setosa 4.6 # 10 4.9 3.1 1.5 0.1 setosa 5
また、mutate_at
ではvars
に指定した列に対して関数を適用できる。funs
で作成したlist(fun_list)を関数部分に用いると指定した要素名を末尾に追加した列名を追加することができる。
iris %>% group_by(Species) %>% mutate_at(vars(Sepal.Length:Petal.Width), funs('lag' = lag)) # # Sepal.Length Sepal.Width Petal.Length Petal.Width Species Sepal.Length_lag Sepal.Width_lag Petal.Length_lag Petal.Width_lag # <dbl> <dbl> <dbl> <dbl> <fct> <dbl> <dbl> <dbl> <dbl> # 1 5.1 3.5 1.4 0.2 setosa NA NA NA NA # 2 4.9 3 1.4 0.2 setosa 5.1 3.5 1.4 0.2 # 3 4.7 3.2 1.3 0.2 setosa 4.9 3 1.4 0.2 # 4 4.6 3.1 1.5 0.2 setosa 4.7 3.2 1.3 0.2 # 5 5 3.6 1.4 0.2 setosa 4.6 3.1 1.5 0.2 # 6 5.4 3.9 1.7 0.4 setosa 5 3.6 1.4 0.2 # 7 4.6 3.4 1.4 0.3 setosa 5.4 3.9 1.7 0.4 # 8 5 3.4 1.5 0.2 setosa 4.6 3.4 1.4 0.3 # 9 4.4 2.9 1.4 0.2 setosa 5 3.4 1.5 0.2 # 10 4.9 3.1 1.5 0.1 setosa 4.4 2.9 1.4 0.2
しかし、このときfuns
を使った関数で引数を使おうとしても上手く動かない(何故か全てNA)になる。
iris %>% group_by(Species) %>% mutate_at(vars(Sepal.Length:Petal.Width), funs('lag' = lag(2))) # Sepal.Length Sepal.Width Petal.Length Petal.Width Species Sepal.Length_lag Sepal.Width_lag Petal.Length_lag Petal.Width_lag # <dbl> <dbl> <dbl> <dbl> <fct> <dbl> <dbl> <dbl> <dbl> # 1 5.1 3.5 1.4 0.2 setosa NA NA NA NA # 2 4.9 3 1.4 0.2 setosa NA NA NA NA # 3 4.7 3.2 1.3 0.2 setosa NA NA NA NA # 4 4.6 3.1 1.5 0.2 setosa NA NA NA NA # 5 5 3.6 1.4 0.2 setosa NA NA NA NA # 6 5.4 3.9 1.7 0.4 setosa NA NA NA NA # 7 4.6 3.4 1.4 0.3 setosa NA NA NA NA # 8 5 3.4 1.5 0.2 setosa NA NA NA NA # 9 4.4 2.9 1.4 0.2 setosa NA NA NA NA # 10 4.9 3.1 1.5 0.1 setosa NA NA NA NA
対応策
内部的にどういう挙動になっているかよくわからないが、mutate_at
の関数部分は関数か、funs
のようにlistを指定する。
そのため、引数付きの関数を事前に作成して関数部分にfuns
のようなlistを適用するとよさそう。
partial
という関数を用いると既存関数を用いた無名関数を作成することができる。
そのため、この無名関数をfuns
のように作成して関数部分に渡すことで対応ができる。
iris %>% group_by(Species) %>% mutate_at(vars(Sepal.Length:Petal.Width), list(lag2 = partial(lag, n=2))) # Sepal.Length Sepal.Width Petal.Length Petal.Width Species Sepal.Length_la… Sepal.Width_lag2 Petal.Length_la… # <dbl> <dbl> <dbl> <dbl> <fct> <dbl> <dbl> <dbl> # 1 5.1 3.5 1.4 0.2 setosa NA NA NA # 2 4.9 3 1.4 0.2 setosa NA NA NA # 3 4.7 3.2 1.3 0.2 setosa 5.1 3.5 1.4 # 4 4.6 3.1 1.5 0.2 setosa 4.9 3 1.4 # 5 5 3.6 1.4 0.2 setosa 4.7 3.2 1.3 # 6 5.4 3.9 1.7 0.4 setosa 4.6 3.1 1.5 # 7 4.6 3.4 1.4 0.3 setosa 5 3.6 1.4 # 8 5 3.4 1.5 0.2 setosa 5.4 3.9 1.7 # 9 4.4 2.9 1.4 0.2 setosa 4.6 3.4 1.4 # 10 4.9 3.1 1.5 0.1 setosa 5 3.4 1.5
なお、mutate_at
は前述のようにlistでhoge = 関数
で渡すと適用した列の末尾にlistの要素名が_
で付けることができるので上記コードもlistで渡しているが、必要ない場合そのままpartial
無名関数を渡す。
iris %>% group_by(Species) %>% mutate_at(vars(Sepal.Length:Petal.Width), partial(lag, n=2)) # Sepal.Length Sepal.Width Petal.Length Petal.Width Species # <dbl> <dbl> <dbl> <dbl> <fct> # 1 NA NA NA NA setosa # 2 NA NA NA NA setosa # 3 5.1 3.5 1.4 0.2 setosa # 4 4.9 3 1.4 0.2 setosa # 5 4.7 3.2 1.3 0.2 setosa # 6 4.6 3.1 1.5 0.2 setosa # 7 5 3.6 1.4 0.2 setosa # 8 5.4 3.9 1.7 0.4 setosa # 9 4.6 3.4 1.4 0.3 setosa # 10 5 3.4 1.5 0.2 setosa