为什么整洁的评估会抛出错误,除非打印或强制参数?
Why does tidy evaluation throw an error unless an argument is printed or forced?
代码
## 1. Get Hours into Tibble
## ---------------------
hrsThreshold <- function(input_data, group1, group2, group2_String) {
# print ({{group2}}) # for some ridiculous reason, code doesn't work without this print statement in!
# Hours
hrs <-
# thresholds
input_data %>%
mutate( score = rowSums(select(., starts_with("less_than")), na.rm = TRUE)) %>%
# scores & summary
group_by({{ group1 }}, {{ group2 }}, score) %>%
summarise(n_points = n()) %>%
mutate(percent = n_points / sum(n_points)) %>%
mutate(score = as_factor(score)) %>%
# add percentage labels.
group_by({{ group1 }}, {{ group2 }}) %>%
mutate(ymax = cumsum(percent),
ymin = c(0, head(cumsum(percent), n = -1))) %>%
mutate(label_pos = (ymax+ymin) / 2,
label = ifelse(percent < 0.01, "", paste0(round(percent*100, 0), "%"))) %>%
ungroup()
hrs
# Hours All
hrs_all <-
hrs %>%
drop_na( {{ group2 }} ) %>%
select(-label) %>%
# Sum n_points
group_by({{ group1 }}, score) %>%
summarise_at(
vars(n_points),
.funs = sum) %>%
mutate(percent = n_points / sum(n_points)) %>%
# redo geometry of rectangles.
group_by({{ group1 }}) %>%
mutate(ymax = cumsum(percent),
ymin = c(0, head(cumsum(percent), n = -1))) %>%
mutate(label_pos = (ymax+ymin) / 2,
label = ifelse(percent < 0.01, "", paste0(round(percent*100, 0), "%"))) %>%
# Change room_type = All
mutate({{ group2 }} := "all")
# Join All with Variable
hrs_by_room <- full_join(hrs_all, hrs)
return(hrs_by_room)
}
# Debug Code
analysis_vars <- c("room_type", "tenure")
analysis_index <- 2
# Dynamic Variable
mytempVar <- analysis_vars[analysis_index]
mytempVarTitle <- mytempVar
mytempVarTitle <- str_replace(mytempVarTitle, "[_]", " ")
mytempVarTitle <- str_to_title(mytempVarTitle)
mytempVar_ <- sym(mytempVar)
# run command
hrs_by_room <- hrsThreshold(risk_assigned, hhi, mytempVar_, c({{mytempVar_}}))
问题描述
上面的代码仅在以下行时有效:
print ({{group2}})
未评论!!!从表面上看,这个命令什么都不做。但是如果我的机器上没有它,就会出现以下错误:
Error: Must group by variables found in `.data`.
* Column `mytempVar_` is not found.
Run `rlang::last_error()` to see where the error occurred.
> rlang::last_error()
<error/rlang_error>
Must group by variables found in `.data`.
* Column `mytempVar_` is not found.
Backtrace:
1. global::hrsThreshold(...)
11. dplyr:::group_by.data.frame(...)
12. dplyr::group_by_prepare(.data, ..., .add = .add, caller_env = caller_env())
Run `rlang::last_trace()` to see the full context.
> rlang::last_trace()
<error/rlang_error>
Must group by variables found in `.data`.
* Column `mytempVar_` is not found.
Backtrace:
x
1. +-global::hrsThreshold(...)
2. | \-`%>%`(...)
3. +-dplyr::ungroup(.)
4. +-dplyr::mutate(...)
5. +-dplyr::mutate(...)
6. +-dplyr::group_by(...)
7. +-dplyr::mutate(., score = as_factor(score))
8. +-dplyr::mutate(., percent = n_points/sum(n_points))
9. +-dplyr::summarise(., n_points = n())
10. +-dplyr::group_by(...)
11. \-dplyr:::group_by.data.frame(...)
12. \-dplyr::group_by_prepare(.data, ..., .add = .add, caller_env = caller_env())
我已经确认这是导致我的整个报告应用程序在多个功能中崩溃了好几天的问题。我只是通过不小心放入打印语句来调试问题才最终得到它的工作。于是它神秘地开始工作了。到底是怎么回事?
源文件
library(tidyverse)
risk_assigned <- read.csv( text="hhi,device_id,rental_type,room,room_type,ts,temp,less_than_21,less_than_18,less_than_16,less_than_12
MyOrg,2C7970,Council Rental,Lounge,living,1598291349,18.3,1,NA,NA,NA
MyOrg,2C7970,Council Rental,Lounge,living,1598292249,18.3,1,NA,NA,NA
MyOrg,2C7970,Council Rental,Lounge,living,1598293149,18.3,1,NA,NA,NA
MyOrg,2C7970,Council Rental,Lounge,living,1598294049,18.3,1,NA,NA,NA
MyOrg,2C7970,Council Rental,Lounge,living,1598294949,18.2,1,NA,NA,NA
MyOrg,2C7970,Council Rental,Lounge,living,1598353449,18.5,1,NA,NA,NA
MyOrg,2C7970,Council Rental,Lounge,living,1598354354,18.5,1,NA,NA,NA
MyOrg,2C7970,Council Rental,Lounge,living,1598355254,18.5,1,NA,NA,NA
MyOrg,2C7970,Council Rental,Lounge,living,1598356154,18.5,1,NA,NA,NA
MyOrg,2C7970,Council Rental,Lounge,living,1598357054,18.5,1,NA,NA,NA
MyOrg,2C7970,Council Rental,Lounge,living,1598357954,18.5,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598358854,18.5,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598359754,18.6,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598360654,18.5,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598361554,18.5,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598362454,18.4,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598363354,18.4,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598364254,18.4,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598365154,18.4,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598366054,18.3,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598366954,18.2,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598367850,18.2,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598368750,18.1,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598369650,18.1,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598370550,18,1,NA,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598371450,17.9,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598372350,17.9,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598373250,17.8,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598374150,17.8,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598375050,17.8,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598375950,17.7,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598376850,17.6,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598377750,17.6,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598378650,17.6,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598379553,17.5,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598380453,17.5,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598381353,17.4,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598439851,17.7,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598440751,17.7,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598441651,17.6,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598442551,17.6,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598443451,17.5,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598444351,17.5,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598445251,17.4,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598446151,17.4,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598447051,17.3,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598447951,17.3,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598448851,17.1,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598449751,17.1,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598450651,17.1,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598451554,17.1,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598452454,17.1,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598453354,17.1,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598454254,17.1,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598455154,17.1,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598456054,17,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598456954,17,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598457854,16.9,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598458754,16.9,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598459654,16.9,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598460554,16.9,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598461454,16.8,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598462354,16.8,1,1,NA,NA
MyOrg,2C7974,Council Rental,Lounge,living,1598463254,16.7,1,1,NA,NA
MyOrg,2C7974,Council Rental,Lounge,living,1598464154,16.8,1,1,NA,NA
MyOrg,2C7974,Council Rental,Lounge,living,1598465051,16.7,1,1,NA,NA
MyOrg,2C7974,Council Rental,Lounge,living,1598465951,16.8,1,1,NA,NA
MyOrg,2C7974,Council Rental,Lounge,living,1598466851,16.7,1,1,NA,NA")
为什么会失败?
这是一个最小的例子:
var <- rlang::sym("cyl")
fn <- function(var, force) {
if (force) {
force(var)
}
dplyr::group_by(mtcars, {{ var }})
}
预期的行为是:
fn(var, force = FALSE)
#> Error: Must group by variables found in `.data`.
#> * Column `var` is not found.
这是意外行为:
fn(var, force = TRUE)
#> # A tibble: 32 × 11
#> # Groups: cyl [3]
#> mpg cyl disp hp drat wt qsec vs am gear carb
#> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 21 6 160 110 3.9 2.62 16.5 0 1 4 4
#> 2 21 6 160 110 3.9 2.88 17.0 0 1 4 4
#> 3 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1
#> 4 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1
#> # … with 28 more rows
造成这种意外行为的原因有两个。
断章取义使用{{
等同于强行争论。所以 print({{ var }})
等价于 force(var)
。参见 https://rlang.r-lib.org/reference/topic-inject-out-of-context.html。
无法化解强行争论。而且因为编译器从 promises 中解包常量,所以我们无法检测到这种情况而抛出错误。这就是为什么强制参数被注入而不是化解的原因。参见 https://rlang.r-lib.org/reference/topic-embrace-non-args.html。
我们无法修复 (1) 或 (2),因为 tidy evaluation 不是在核心语言中实现的,而是在它之上实现的。
我该怎么办?
在您的示例中,您似乎希望通过参数将列名传递给您的函数。
首先要注意的是,由于该参数是通过 {{
传递给 group_by()
的,因此您的函数继承了 group_by()
的所有行为。它采用不带引号的列名并支持所有整洁的评估功能。
当字符串中有列名时,传递它的规范方法是使用 .data
代词:
var <- "cyl"
fn <- function(var) {
dplyr::group_by(mtcars, {{ var }})
}
fn(var)
#> Error: Must group by variables found in `.data`.
#> * Column `var` is not found.
fn(.data[[var]])
#> # A tibble: 32 × 11
#> # Groups: cyl [3]
#> mpg cyl disp hp drat wt qsec vs am gear carb
#> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 21 6 160 110 3.9 2.62 16.5 0 1 4 4
#> 2 21 6 160 110 3.9 2.88 17.0 0 1 4 4
#> 3 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1
#> 4 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1
#> # … with 28 more rows
代码
## 1. Get Hours into Tibble
## ---------------------
hrsThreshold <- function(input_data, group1, group2, group2_String) {
# print ({{group2}}) # for some ridiculous reason, code doesn't work without this print statement in!
# Hours
hrs <-
# thresholds
input_data %>%
mutate( score = rowSums(select(., starts_with("less_than")), na.rm = TRUE)) %>%
# scores & summary
group_by({{ group1 }}, {{ group2 }}, score) %>%
summarise(n_points = n()) %>%
mutate(percent = n_points / sum(n_points)) %>%
mutate(score = as_factor(score)) %>%
# add percentage labels.
group_by({{ group1 }}, {{ group2 }}) %>%
mutate(ymax = cumsum(percent),
ymin = c(0, head(cumsum(percent), n = -1))) %>%
mutate(label_pos = (ymax+ymin) / 2,
label = ifelse(percent < 0.01, "", paste0(round(percent*100, 0), "%"))) %>%
ungroup()
hrs
# Hours All
hrs_all <-
hrs %>%
drop_na( {{ group2 }} ) %>%
select(-label) %>%
# Sum n_points
group_by({{ group1 }}, score) %>%
summarise_at(
vars(n_points),
.funs = sum) %>%
mutate(percent = n_points / sum(n_points)) %>%
# redo geometry of rectangles.
group_by({{ group1 }}) %>%
mutate(ymax = cumsum(percent),
ymin = c(0, head(cumsum(percent), n = -1))) %>%
mutate(label_pos = (ymax+ymin) / 2,
label = ifelse(percent < 0.01, "", paste0(round(percent*100, 0), "%"))) %>%
# Change room_type = All
mutate({{ group2 }} := "all")
# Join All with Variable
hrs_by_room <- full_join(hrs_all, hrs)
return(hrs_by_room)
}
# Debug Code
analysis_vars <- c("room_type", "tenure")
analysis_index <- 2
# Dynamic Variable
mytempVar <- analysis_vars[analysis_index]
mytempVarTitle <- mytempVar
mytempVarTitle <- str_replace(mytempVarTitle, "[_]", " ")
mytempVarTitle <- str_to_title(mytempVarTitle)
mytempVar_ <- sym(mytempVar)
# run command
hrs_by_room <- hrsThreshold(risk_assigned, hhi, mytempVar_, c({{mytempVar_}}))
问题描述
上面的代码仅在以下行时有效:
print ({{group2}})
未评论!!!从表面上看,这个命令什么都不做。但是如果我的机器上没有它,就会出现以下错误:
Error: Must group by variables found in `.data`.
* Column `mytempVar_` is not found.
Run `rlang::last_error()` to see where the error occurred.
> rlang::last_error()
<error/rlang_error>
Must group by variables found in `.data`.
* Column `mytempVar_` is not found.
Backtrace:
1. global::hrsThreshold(...)
11. dplyr:::group_by.data.frame(...)
12. dplyr::group_by_prepare(.data, ..., .add = .add, caller_env = caller_env())
Run `rlang::last_trace()` to see the full context.
> rlang::last_trace()
<error/rlang_error>
Must group by variables found in `.data`.
* Column `mytempVar_` is not found.
Backtrace:
x
1. +-global::hrsThreshold(...)
2. | \-`%>%`(...)
3. +-dplyr::ungroup(.)
4. +-dplyr::mutate(...)
5. +-dplyr::mutate(...)
6. +-dplyr::group_by(...)
7. +-dplyr::mutate(., score = as_factor(score))
8. +-dplyr::mutate(., percent = n_points/sum(n_points))
9. +-dplyr::summarise(., n_points = n())
10. +-dplyr::group_by(...)
11. \-dplyr:::group_by.data.frame(...)
12. \-dplyr::group_by_prepare(.data, ..., .add = .add, caller_env = caller_env())
我已经确认这是导致我的整个报告应用程序在多个功能中崩溃了好几天的问题。我只是通过不小心放入打印语句来调试问题才最终得到它的工作。于是它神秘地开始工作了。到底是怎么回事?
源文件
library(tidyverse)
risk_assigned <- read.csv( text="hhi,device_id,rental_type,room,room_type,ts,temp,less_than_21,less_than_18,less_than_16,less_than_12
MyOrg,2C7970,Council Rental,Lounge,living,1598291349,18.3,1,NA,NA,NA
MyOrg,2C7970,Council Rental,Lounge,living,1598292249,18.3,1,NA,NA,NA
MyOrg,2C7970,Council Rental,Lounge,living,1598293149,18.3,1,NA,NA,NA
MyOrg,2C7970,Council Rental,Lounge,living,1598294049,18.3,1,NA,NA,NA
MyOrg,2C7970,Council Rental,Lounge,living,1598294949,18.2,1,NA,NA,NA
MyOrg,2C7970,Council Rental,Lounge,living,1598353449,18.5,1,NA,NA,NA
MyOrg,2C7970,Council Rental,Lounge,living,1598354354,18.5,1,NA,NA,NA
MyOrg,2C7970,Council Rental,Lounge,living,1598355254,18.5,1,NA,NA,NA
MyOrg,2C7970,Council Rental,Lounge,living,1598356154,18.5,1,NA,NA,NA
MyOrg,2C7970,Council Rental,Lounge,living,1598357054,18.5,1,NA,NA,NA
MyOrg,2C7970,Council Rental,Lounge,living,1598357954,18.5,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598358854,18.5,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598359754,18.6,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598360654,18.5,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598361554,18.5,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598362454,18.4,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598363354,18.4,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598364254,18.4,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598365154,18.4,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598366054,18.3,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598366954,18.2,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598367850,18.2,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598368750,18.1,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598369650,18.1,1,NA,NA,NA
MyOrg,2C7971,Private Rental,Lounge,living,1598370550,18,1,NA,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598371450,17.9,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598372350,17.9,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598373250,17.8,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598374150,17.8,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598375050,17.8,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598375950,17.7,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598376850,17.6,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598377750,17.6,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598378650,17.6,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598379553,17.5,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598380453,17.5,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598381353,17.4,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598439851,17.7,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598440751,17.7,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598441651,17.6,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598442551,17.6,1,1,NA,NA
MyOrg,2C7972,Private Rental,Lounge,living,1598443451,17.5,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598444351,17.5,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598445251,17.4,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598446151,17.4,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598447051,17.3,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598447951,17.3,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598448851,17.1,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598449751,17.1,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598450651,17.1,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598451554,17.1,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598452454,17.1,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598453354,17.1,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598454254,17.1,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598455154,17.1,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598456054,17,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598456954,17,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598457854,16.9,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598458754,16.9,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598459654,16.9,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598460554,16.9,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598461454,16.8,1,1,NA,NA
MyOrg,2C7973,Council Rental,Lounge,living,1598462354,16.8,1,1,NA,NA
MyOrg,2C7974,Council Rental,Lounge,living,1598463254,16.7,1,1,NA,NA
MyOrg,2C7974,Council Rental,Lounge,living,1598464154,16.8,1,1,NA,NA
MyOrg,2C7974,Council Rental,Lounge,living,1598465051,16.7,1,1,NA,NA
MyOrg,2C7974,Council Rental,Lounge,living,1598465951,16.8,1,1,NA,NA
MyOrg,2C7974,Council Rental,Lounge,living,1598466851,16.7,1,1,NA,NA")
为什么会失败?
这是一个最小的例子:
var <- rlang::sym("cyl")
fn <- function(var, force) {
if (force) {
force(var)
}
dplyr::group_by(mtcars, {{ var }})
}
预期的行为是:
fn(var, force = FALSE)
#> Error: Must group by variables found in `.data`.
#> * Column `var` is not found.
这是意外行为:
fn(var, force = TRUE)
#> # A tibble: 32 × 11
#> # Groups: cyl [3]
#> mpg cyl disp hp drat wt qsec vs am gear carb
#> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 21 6 160 110 3.9 2.62 16.5 0 1 4 4
#> 2 21 6 160 110 3.9 2.88 17.0 0 1 4 4
#> 3 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1
#> 4 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1
#> # … with 28 more rows
造成这种意外行为的原因有两个。
断章取义使用
{{
等同于强行争论。所以print({{ var }})
等价于force(var)
。参见 https://rlang.r-lib.org/reference/topic-inject-out-of-context.html。无法化解强行争论。而且因为编译器从 promises 中解包常量,所以我们无法检测到这种情况而抛出错误。这就是为什么强制参数被注入而不是化解的原因。参见 https://rlang.r-lib.org/reference/topic-embrace-non-args.html。
我们无法修复 (1) 或 (2),因为 tidy evaluation 不是在核心语言中实现的,而是在它之上实现的。
我该怎么办?
在您的示例中,您似乎希望通过参数将列名传递给您的函数。
首先要注意的是,由于该参数是通过 {{
传递给 group_by()
的,因此您的函数继承了 group_by()
的所有行为。它采用不带引号的列名并支持所有整洁的评估功能。
当字符串中有列名时,传递它的规范方法是使用 .data
代词:
var <- "cyl"
fn <- function(var) {
dplyr::group_by(mtcars, {{ var }})
}
fn(var)
#> Error: Must group by variables found in `.data`.
#> * Column `var` is not found.
fn(.data[[var]])
#> # A tibble: 32 × 11
#> # Groups: cyl [3]
#> mpg cyl disp hp drat wt qsec vs am gear carb
#> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 21 6 160 110 3.9 2.62 16.5 0 1 4 4
#> 2 21 6 160 110 3.9 2.88 17.0 0 1 4 4
#> 3 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1
#> 4 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1
#> # … with 28 more rows