UPDATE: 2023-05-20 20:21:27
ブログからの引っ越し記事。
この記事はTidy evaluationをもとにTidy evaluationについて学習した内容を自分の備忘録としてまとめたものです。
tidyevalを利用して関数を作成するための基本的なプロセスであり、quote
とunquote
はそのプロセスを構成する関数。
enquo()
:自動的にその引数をクオートするために使用。!!
:引数のクオートを外すのに使用。グループごとに平均を計算する関数grouped_mean()
を作成したいとする。この関数では、グループの単位となるgroup_var
とsummary_var
をうまく評価させることで、汎用的な関数を作る必要がある。
grouped_mean <- function(data, group_var, summary_var) {
data %>%
group_by(group_var) %>%
summarise(mean = mean(summary_var))
}
さっそくこの関数を使用してみるが、うまくいかない。Column group_var is unknown
がないとエラーを返されているが、こちらとしては、group_var = Species
を指定しているので、うまく行ってほしい。
iris %>% grouped_mean(., group_var = Species, summary_var = Sepal.Length)
エラー: Column `group_var` is unknown
これを修正するためにenquo()
を使い、入力された表現式をクオートする必要があります。
group_var <- enquo(group_var)
summary_var <- enquo(summary_var)
そして、これらの変数が他の引用される場所を特定し、!!
を使って一時的にクオートを外します。
grouped_mean <- function(data, group_var, summary_var) {
group_var <- enquo(group_var)
summary_var <- enquo(summary_var)
data %>%
group_by(!!group_var) %>%
summarise(mean = mean(!!summary_var))
}
iris %>% grouped_mean(., group_var = Species, summary_var = Sepal.Length)
# A tibble: 3 x 2
Species mean
<fct> <dbl>
1 setosa 5.01
2 versicolor 5.94
3 virginica 6.59
これがQuote and unquoteというtidyevalにおける関数作成の基本らしい。
Quote and unquoteというステップでなくても、文字を使っても問題はないが、単純に文字が使えるわけではない。
var <- "Petal.Length"
ris %>% mutate(., rescaled = !!var * 100)
"Petal.Length" * 100 でエラー: 二項演算子の引数が数値ではありません
このエラーはqq_show()
で明らかにできる。100*"character"
になっているので、文字×数値となっているのでエラーが起こる。
rlang::qq_show(iris %>% mutate(., rescaled = !!var * 100))
iris %>% mutate(., rescaled = "Petal.Length" * 100)
このエラーを回避するために文字をクオートすることでシンボルに変換しないといけない。
"Petal.Length"
[1] "Petal.Length"
quote(Petal.Length)
Petal.Length
is.symbol(quote(Petal.Length))
[1] TRUE
もしくはsym()
を使って文字型をシンボルに変更できる。
sym("Petal.Length")
Petal.Length
is.symbol(sym("Petal.Length"))
[1] TRUE
シンボルを使って書き直すと、文字型を使ってうまく関数を動かすことができる。
grouped_mean2 <- function(data, group_var, summary_var) {
group_var <- sym(group_var)
summary_var <- sym(summary_var)
data %>%
group_by(!!group_var) %>%
summarise(mean = mean(!!summary_var))
}
iris %>% grouped_mean2(., group_var = "Species", summary_var = "Sepal.Length")
# A tibble: 3 x 2
Species mean
<fct> <dbl>
1 setosa 5.01
2 versicolor 5.94
3 virginica 6.59
こうすることで、予め文字型で指定していても、関数内部でsym()
は文字をシンボル化してくれて、!!
が一時的にクオートを外すことができる。
grp_var <- "Species"
sum_var <- "Sepal.Length"
iris %>% grouped_mean2(., grp_var, sum_var)
# A tibble: 3 x 2
Species mean
<fct> <dbl>
1 setosa 5.01
2 versicolor 5.94
3 virginica 6.59