使用 rlang 围绕 ez::ezANOVA 编写自定义函数
using `rlang` to write a custom function around `ez::ezANOVA`
我正在尝试使用 rlang
+ ez
为 运行 单向受试者内方差分析编写自定义函数。
我期望的输出示例:
# setup
set.seed(123)
library(WRS2)
library(ez)
library(tidyverse)
# getting data in format that `ez` expects
df <- WRS2::WineTasting %>%
dplyr::mutate_if(
.tbl = .,
.predicate = purrr::is_bare_character,
.funs = as.factor
) %>%
dplyr::mutate(.data = ., Taster = as.factor(Taster))
# this works
ez::ezANOVA(
data = df,
dv = Taste,
wid = Taster,
within = Wine,
detailed = TRUE,
return_aov = TRUE
)
#> $ANOVA
#> Effect DFn DFd SSn SSd F p
#> 1 (Intercept) 1 21 2.005310e+03 4.2186364 9982.254929 1.311890e-29
#> 2 Wine 2 42 9.371212e-02 0.3129545 6.288308 4.084101e-03
#> p<.05 ges
#> 1 * 0.99774530
#> 2 * 0.02026075
#>
#> $`Mauchly's Test for Sphericity`
#> Effect W p p<.05
#> 2 Wine 0.7071776 0.03128132 *
#>
#> $`Sphericity Corrections`
#> Effect GGe p[GG] p[GG]<.05 HFe p[HF] p[HF]<.05
#> 2 Wine 0.7735015 0.008439799 * 0.8233709 0.007188822 *
#>
#> $aov
#>
#> Call:
#> aov(formula = formula(aov_formula), data = data)
#>
#> Grand Mean: 5.512121
#>
#> Stratum 1: Taster
#>
#> Terms:
#> Residuals
#> Sum of Squares 4.218636
#> Deg. of Freedom 21
#>
#> Residual standard error: 0.4482047
#>
#> Stratum 2: Taster:Wine
#>
#> Terms:
#> Wine Residuals
#> Sum of Squares 0.09371212 0.31295455
#> Deg. of Freedom 2 42
#>
#> Residual standard error: 0.08632091
#> Estimated effects may be unbalanced
现在这是我编写的一个自定义函数来执行相同的操作,但使用 rlang
中实现的非标准评估:
# custom function
aov_fun <- function(data, x, y, id) {
# getting data in format that `ez` expects
df <- data %>%
dplyr::mutate_if(
.tbl = .,
.predicate = purrr::is_bare_character,
.funs = as.factor
) %>%
dplyr::mutate(.data = ., {{ id }} := as.factor({{ id }})) %>%
tibble::as_tibble(.)
# print the dataframe to see if it was cleaned as expected
print(df)
# running anova
ez::ezANOVA(
data = df,
dv = {{ y }},
wid = {{ id }},
within = {{ x }},
detailed = TRUE,
return_aov = TRUE
)
}
但这行不通。请注意,数据框已正确清理,因此这不是错误所在。
# using the function
aov_fun(WRS2::WineTasting, Wine, Taste, Taster)
#> # A tibble: 66 x 3
#> Taste Wine Taster
#> <dbl> <fct> <fct>
#> 1 5.4 Wine A 1
#> 2 5.5 Wine B 1
#> 3 5.55 Wine C 1
#> 4 5.85 Wine A 2
#> 5 5.7 Wine B 2
#> 6 5.75 Wine C 2
#> 7 5.2 Wine A 3
#> 8 5.6 Wine B 3
#> 9 5.5 Wine C 3
#> 10 5.55 Wine A 4
#> # ... with 56 more rows
#> Error in ezANOVA_main(data = data, dv = dv, wid = wid, within = within, : "{
#> y
#> }" is not a variable in the data frame provided.
代替dv = {{ y }}
,我也试过-
dv = rlang::as_string(y)
dv = rlang::as_name(y)
dv = rlang::enquo(y)
但是 none 这些工作。
这可以用
更正
aov_fun <- function(data, x, y, id) {
lst1 <- as.list(match.call()[-1])
names(lst1)<- c("data", "dv", "wid", "within")[match(names(lst1),
c("data", "y", "id", "x"))]
df <- data %>%
dplyr::mutate_if(
.tbl = .,
.predicate = purrr::is_bare_character,
.funs = as.factor
) %>%
dplyr::mutate(.data = ., {{ id }} := as.factor({{ id }})) %>%
tibble::as_tibble(.)
do.call(getFromNamespace("ezANOVA", "ez"),
c(lst1, detailed = TRUE, return_aov = TRUE))
}
-测试
aov_fun(WRS2::WineTasting, x = Wine,y = Taste, id = Taster)
#$ANOVA
# Effect DFn DFd SSn SSd F p p<.05 ges
# 1 (Intercept) 1 21 2.005310e+03 4.2186364 9982.254929 1.311890e-29 * 0.99774530
# 2 Wine 2 42 9.371212e-02 0.3129545 6.288308 4.084101e-03 * 0.02026075
# $`Mauchly's Test for Sphericity`
# Effect W p p<.05
# 2 Wine 0.7071776 0.03128132 *
# $`Sphericity Corrections`
# Effect GGe p[GG] p[GG]<.05 HFe p[HF] p[HF]<.05
# 2 Wine 0.7735015 0.008439799 * 0.8233709 0.007188822 *
# $aov
# Call:
# aov(formula = formula(aov_formula), data = data)
# Grand Mean: 5.512121
# Stratum 1: Taster
# Terms:
# Residuals
# Sum of Squares 4.218636
# Deg. of Freedom 21
# Residual standard error: 0.4482047
# Stratum 2: Taster:Wine
# Terms:
# Wine Residuals
# Sum of Squares 0.09371212 0.31295455
# Deg. of Freedom 2 42
# Residual standard error: 0.08632091
# Estimated effects may be unbalanced
每当我想将 rlang
的 NSE 与未明确支持它的功能桥接时,
我发现将程序分为这两个步骤(至少在概念上)总是有帮助的:
- 使用
rlang
函数创建我想要的最终表达式。
- 评估它,如果涉及到问题则使用
rlang::eval_tidy
,否则使用 base::eval
。
在你的情况下,你可能可以用类似的东西来完成你的功能:
# running anova
rlang::eval_tidy(rlang::expr(ez::ezANOVA(
data = df,
dv = {{ y }},
wid = {{ id }},
within = {{ x }},
detailed = TRUE,
return_aov = TRUE
)))
expr
创建表达式并且显然支持 rlang
的 NSE,
eval_tidy
只是计算表达式。
哦,顺便说一句,if ezANOVA
(或任何其他您想与 NSE 一起使用的函数)支持字符串而不是表达式作为输入,
你需要像 rlang::as_string(rlang::enexpr(param))
这样的东西,
首先捕获用户写的内容的表达式 param
,
然后 使用 as_string
转换该表达式。
这是来自 @moody_mudskipper 的 tags package
的 using_bang
的一个很棒的应用程序
aov_fun <- function(data, x, y, id) {
# ...
# code as before
# running anova
tags::using_bang$ezANOVA(
data = df,
dv = {{y}},
wid = {{id}},
within = {{x}},
detailed = TRUE,
return_aov = TRUE
)
}
我正在尝试使用 rlang
+ ez
为 运行 单向受试者内方差分析编写自定义函数。
我期望的输出示例:
# setup
set.seed(123)
library(WRS2)
library(ez)
library(tidyverse)
# getting data in format that `ez` expects
df <- WRS2::WineTasting %>%
dplyr::mutate_if(
.tbl = .,
.predicate = purrr::is_bare_character,
.funs = as.factor
) %>%
dplyr::mutate(.data = ., Taster = as.factor(Taster))
# this works
ez::ezANOVA(
data = df,
dv = Taste,
wid = Taster,
within = Wine,
detailed = TRUE,
return_aov = TRUE
)
#> $ANOVA
#> Effect DFn DFd SSn SSd F p
#> 1 (Intercept) 1 21 2.005310e+03 4.2186364 9982.254929 1.311890e-29
#> 2 Wine 2 42 9.371212e-02 0.3129545 6.288308 4.084101e-03
#> p<.05 ges
#> 1 * 0.99774530
#> 2 * 0.02026075
#>
#> $`Mauchly's Test for Sphericity`
#> Effect W p p<.05
#> 2 Wine 0.7071776 0.03128132 *
#>
#> $`Sphericity Corrections`
#> Effect GGe p[GG] p[GG]<.05 HFe p[HF] p[HF]<.05
#> 2 Wine 0.7735015 0.008439799 * 0.8233709 0.007188822 *
#>
#> $aov
#>
#> Call:
#> aov(formula = formula(aov_formula), data = data)
#>
#> Grand Mean: 5.512121
#>
#> Stratum 1: Taster
#>
#> Terms:
#> Residuals
#> Sum of Squares 4.218636
#> Deg. of Freedom 21
#>
#> Residual standard error: 0.4482047
#>
#> Stratum 2: Taster:Wine
#>
#> Terms:
#> Wine Residuals
#> Sum of Squares 0.09371212 0.31295455
#> Deg. of Freedom 2 42
#>
#> Residual standard error: 0.08632091
#> Estimated effects may be unbalanced
现在这是我编写的一个自定义函数来执行相同的操作,但使用 rlang
中实现的非标准评估:
# custom function
aov_fun <- function(data, x, y, id) {
# getting data in format that `ez` expects
df <- data %>%
dplyr::mutate_if(
.tbl = .,
.predicate = purrr::is_bare_character,
.funs = as.factor
) %>%
dplyr::mutate(.data = ., {{ id }} := as.factor({{ id }})) %>%
tibble::as_tibble(.)
# print the dataframe to see if it was cleaned as expected
print(df)
# running anova
ez::ezANOVA(
data = df,
dv = {{ y }},
wid = {{ id }},
within = {{ x }},
detailed = TRUE,
return_aov = TRUE
)
}
但这行不通。请注意,数据框已正确清理,因此这不是错误所在。
# using the function
aov_fun(WRS2::WineTasting, Wine, Taste, Taster)
#> # A tibble: 66 x 3
#> Taste Wine Taster
#> <dbl> <fct> <fct>
#> 1 5.4 Wine A 1
#> 2 5.5 Wine B 1
#> 3 5.55 Wine C 1
#> 4 5.85 Wine A 2
#> 5 5.7 Wine B 2
#> 6 5.75 Wine C 2
#> 7 5.2 Wine A 3
#> 8 5.6 Wine B 3
#> 9 5.5 Wine C 3
#> 10 5.55 Wine A 4
#> # ... with 56 more rows
#> Error in ezANOVA_main(data = data, dv = dv, wid = wid, within = within, : "{
#> y
#> }" is not a variable in the data frame provided.
代替dv = {{ y }}
,我也试过-
dv = rlang::as_string(y)
dv = rlang::as_name(y)
dv = rlang::enquo(y)
但是 none 这些工作。
这可以用
更正aov_fun <- function(data, x, y, id) {
lst1 <- as.list(match.call()[-1])
names(lst1)<- c("data", "dv", "wid", "within")[match(names(lst1),
c("data", "y", "id", "x"))]
df <- data %>%
dplyr::mutate_if(
.tbl = .,
.predicate = purrr::is_bare_character,
.funs = as.factor
) %>%
dplyr::mutate(.data = ., {{ id }} := as.factor({{ id }})) %>%
tibble::as_tibble(.)
do.call(getFromNamespace("ezANOVA", "ez"),
c(lst1, detailed = TRUE, return_aov = TRUE))
}
-测试
aov_fun(WRS2::WineTasting, x = Wine,y = Taste, id = Taster)
#$ANOVA
# Effect DFn DFd SSn SSd F p p<.05 ges
# 1 (Intercept) 1 21 2.005310e+03 4.2186364 9982.254929 1.311890e-29 * 0.99774530
# 2 Wine 2 42 9.371212e-02 0.3129545 6.288308 4.084101e-03 * 0.02026075
# $`Mauchly's Test for Sphericity`
# Effect W p p<.05
# 2 Wine 0.7071776 0.03128132 *
# $`Sphericity Corrections`
# Effect GGe p[GG] p[GG]<.05 HFe p[HF] p[HF]<.05
# 2 Wine 0.7735015 0.008439799 * 0.8233709 0.007188822 *
# $aov
# Call:
# aov(formula = formula(aov_formula), data = data)
# Grand Mean: 5.512121
# Stratum 1: Taster
# Terms:
# Residuals
# Sum of Squares 4.218636
# Deg. of Freedom 21
# Residual standard error: 0.4482047
# Stratum 2: Taster:Wine
# Terms:
# Wine Residuals
# Sum of Squares 0.09371212 0.31295455
# Deg. of Freedom 2 42
# Residual standard error: 0.08632091
# Estimated effects may be unbalanced
每当我想将 rlang
的 NSE 与未明确支持它的功能桥接时,
我发现将程序分为这两个步骤(至少在概念上)总是有帮助的:
- 使用
rlang
函数创建我想要的最终表达式。 - 评估它,如果涉及到问题则使用
rlang::eval_tidy
,否则使用base::eval
。
在你的情况下,你可能可以用类似的东西来完成你的功能:
# running anova
rlang::eval_tidy(rlang::expr(ez::ezANOVA(
data = df,
dv = {{ y }},
wid = {{ id }},
within = {{ x }},
detailed = TRUE,
return_aov = TRUE
)))
expr
创建表达式并且显然支持 rlang
的 NSE,
eval_tidy
只是计算表达式。
哦,顺便说一句,if ezANOVA
(或任何其他您想与 NSE 一起使用的函数)支持字符串而不是表达式作为输入,
你需要像 rlang::as_string(rlang::enexpr(param))
这样的东西,
首先捕获用户写的内容的表达式 param
,
然后 使用 as_string
转换该表达式。
这是来自 @moody_mudskipper 的 tags package
的using_bang
的一个很棒的应用程序
aov_fun <- function(data, x, y, id) {
# ...
# code as before
# running anova
tags::using_bang$ezANOVA(
data = df,
dv = {{y}},
wid = {{id}},
within = {{x}},
detailed = TRUE,
return_aov = TRUE
)
}