r - Tidyverse、Rlang 和 tidyeval:Bang bang (!!) 在函数内部失败,但它似乎在没有引号的情况下工作
问题描述
我在具有两个主要组的长数据库(full_database)上运行一个函数,我需要在每个组的多个子集上执行各种线性模型。
然后,我将 R^2、调整后的 R^2 和 p.value 提取到一个数据框中,其中每一行对应一个比较。由于有 30 种不同的情况,我有另一个 tibble 列出了函数参数所在的所有可能性(可能性)。
原始函数的脚本是:
database_correlation <- function(id, group) {
require(dplyr)
require(tidyr)
require(rlang)
id_name <- quo_name(id)
id_var <- enquo(id)
group_name <- quo_name(group)
group_var <- enquo(group)
corr_db <- full_database %>%
filter(numid==!!id_name) %>%
filter(major_group==!!group_name) %>%
droplevels()
correlation <- summary(lm(yvar~xvar, corr_db))
id.x <- as.character(!!id_var) #Gives out an error: "invalid argument type"
group.x <- as.character(!!group_var) #Gives out an error: "invalid argument type"
r_squared <- correlation$r.squared
r_squared_adj <- correlation$adj.r.squared
p_value <- correlation$coefficients[2,4]
data.frame(id.x, group.x, r_squared, r_squared_adj, p_value, stringsAsFactors=FALSE)
}
然后我运行该函数:
correlation_all <- lapply(seq(nrow(possibilities)), function(index) {
current <- possibilities[index,]
with(current, database_correlation(id, database))
}) %>%
bind_rows()
我已经评论了出现错误的部分(id.x 和 group.x 分配),并且我尝试了多种替代方法(我将使用 id.x 作为示例):
- id_var <- enquo(id) & id.x <- print(!!id_var)
- id_var <- sym(id) & id.x <- as.character(!!id_var)
- id_var <- sym(id) & id.x <- print(!!id_var)
- 没有 id_var & id.x <- !!id_name
- 没有 id_var & id.x <- id_name
最后一个选项(粗体)即使没有取消引号也可以工作,如果我在过滤full_database时删除 bang bang (!!) 也是如此,直接使用filter(numid==id_name)但我只是可以不明白为什么。通过使用 TRUE 和 FALSE 进行测试,R 可能会将 bang bang 解释为双重否定,并且由于它期待一个布尔值,它会抛出一个错误。
感谢您的帮助!
解决方案
直接使用id
and group
- 我假设这些是传入的字符串,所以我认为没有必要将 quosure 强制为字符串。此外, !!
可以在支持整洁评估的函数内部使用。确定这一点的简单第一步是“来自基本 R 包的函数”。as.character()
是,所以它不起作用。
如果您确定要将quosure转换为字符串,则可以使用rlang::as_name()
将相应的符号检索为字符串。这是这样做的推荐方式。
通过使用 TRUE 和 FALSE 进行测试,R 可能会将 bang bang 解释为双重否定,并且由于它期待一个布尔值,它会抛出一个错误。
你的假设是正确的。
最后一个选项(粗体)即使没有取消引号也可以工作,如果我在过滤 full_database 时删除 bang bang (!!) 也是如此,使用 filter(numid==id_name)
Tidy-evaluation 的核心是在正确的环境中评估符号,或者至少这是我的看法。这filter()
是有效的,因为它查找符号id_name
,在数据中没有找到它(它首先查找的位置),然后在封闭环境中查找,找到它并评估语句。
想象一下,如果您有一个id_name
在数据中命名的列。您将如何区分数据id_name
和封闭环境中的数据。好吧,如果你想要数据的价值,你可以使用.data$id_name
(另一个 rlang 结构)。如果您想要数据之外的值,请使用!!
. 这告诉支持整洁评估的函数查看 quosure。quosure 标识它是在哪个环境中定义的。然后它在该环境中评估该符号,确保与数据中的名称没有冲突。
推荐阅读
- java - .noSuchElementException 询问用户输入时
- algorithm - 在每个语句的末尾给出次数。对于循环头的情况,只需给出将被检查的次数
- vue.js - 如何多次添加vue.js组件@click?
- css - 为什么高像素密度的小屏幕会呈现错误的媒体查询?
- reactjs - 打字稿,样式组件错误:TS2769:没有重载匹配此调用。重载 1 of 2
- django - Docker-compose:使用 Bolt 从 Web 容器到 Neo4j 容器的 db 连接
- c# - Set-Cookie 中的 Cookie 被浏览器忽略
- jenkins - Jenkins 启动失败 - 验证您是否有足够的权限来启动系统服务
- r - 如何创建堆叠和分组图表?
- elm - 如何在 elm 中为 http get 请求编写测试