使用非标准评估对函数参数的评估不正确?
Incorrect evaluation of the parameters of a function using non standard evaluation?
假设我们有一些向量和数据帧:
a <- c(1, 2, 0, 1)
b <- c(6, 4)
df1 <- data_frame(x = c(6, 8, 12), y = c(24, 18, 16))
我们使用非标准评估编写了一个函数,用于计算数据框列的平均值和向量的平均值。
calculate_means <- function(df, column, vector) {
column <- enquo(column)
summarise(df, mean_column = mean(!!column), mean_vector = mean(vector))
}
calculate_means(df1, x, a)
# A tibble: 1 x 2
mean_column mean_vector
<dbl> <dbl>
1 8.67 1.00
calculate_means(df1, y, b)
# A tibble: 1 x 2
mean_column mean_vector
<dbl> <dbl>
1 19.3 5.00
按预期工作。但是,如果我们编写相同的函数但为参数选择不同的名称会怎样?
calculate_means <- function(df, x, y) {
x <- enquo(x)
summarise(df, mean_column = mean(!!x), mean_vector = mean(y))
}
calculate_means(df1, x, a)
# A tibble: 1 x 2
mean_column mean_vector
<dbl> <dbl>
1 8.67 19.3
calculate_means(df1, y, b)
# A tibble: 1 x 2
mean_column mean_vector
<dbl> <dbl>
1 19.3 19.3
第一个参数的评估与之前相同,但第二个参数始终评估数据帧的列 "y"。
它不应该分别评估向量 "a" 和 "b" 吗?
我们可以使用 globalenv()
获取对象列表,通过将对象名称作为字符串传递来获取对象的值,并在 summarise
语句
中使用它
calculate_means <- function(df, x, y) {
x <- enquo(x)
y <- quo_name(enquo(y))
v1 <- globalenv()[[y]]
df %>%
summarise(mean_column = mean(!! x),
mean_vector = mean(v1))
}
calculate_means(df1, x, a)
# A tibble: 1 x 2
# mean_column mean_vector
# <dbl> <dbl>
#1 8.67 1.00
calculate_means(df1, y, b)
# A tibble: 1 x 2
# mean_column mean_vector
# <dbl> <dbl>
#1 19.3 5.00
假设,如果我们还需要获取'y'列的mean
calculate_means <- function(df, x, y) {
x <- enquo(x)
y <- quo_name(enquo(y))
v1 <- globalenv()[[y]]
df %>%
summarise(mean_column = mean(!! x),
mean_vector = mean(v1),
mean_column2 = mean(.data$y))
}
calculate_means(df1, x, a)
# A tibble: 1 x 3
# mean_column mean_vector mean_column2
# <dbl> <dbl> <dbl>
#1 8.67 1.00 19.3
summarise
的实际参数中的变量首先在 summarise
的第一个参数指定的数据框中查找,并且仅在 summarise
的调用方中查找,如果在该数据框中找不到。因此,通过将 y
硬编码到 summarise
参数中,它将始终首先在 df1
中查找它。
1)我们可以用!!避免这种情况。的论点!!未在数据参数中查找。
calculate_means2 <- function(df, x, y) {
x <- enquo(x)
summarise(df, mean_column = mean(!!x), mean_vector = mean(!!y))
}
calculate_means2(df1, y, b)
# A tibble: 1 x 2
mean_column mean_vector
<dbl> <dbl>
1 19.3 5.00
2) 我们可以用as_quosure
来强调这一点。这会将 y
的值放入 quosure 公式中。在示例中,y <- as_quosure(y)
将导致新的 quosure 包含 ~c(6, 4)
.
calculate_means3 <- function(df, x, y) {
x <- enquo(x)
y <- rlang::as_quosure(y)
summarise(df, mean_column = mean(!!x), mean_vector = mean(!!y))
}
calculate_means3(df1, y, b)
# A tibble: 1 x 2
mean_column mean_vector
<dbl> <dbl>
1 19.3 5.00
3) 当然,我们可以只使用不太可能在数据框中使用的正式参数名称:
calculate_means4 <- function(df, x, y.) {
x <- enquo(x)
summarise(df, mean_column = mean(!!x), mean_vector = mean(y.))
}
calculate_means4(df1, y, b)
# A tibble: 1 x 2
mean_column mean_vector
<dbl> <dbl>
1 19.3 5.00
假设我们有一些向量和数据帧:
a <- c(1, 2, 0, 1)
b <- c(6, 4)
df1 <- data_frame(x = c(6, 8, 12), y = c(24, 18, 16))
我们使用非标准评估编写了一个函数,用于计算数据框列的平均值和向量的平均值。
calculate_means <- function(df, column, vector) {
column <- enquo(column)
summarise(df, mean_column = mean(!!column), mean_vector = mean(vector))
}
calculate_means(df1, x, a)
# A tibble: 1 x 2
mean_column mean_vector
<dbl> <dbl>
1 8.67 1.00
calculate_means(df1, y, b)
# A tibble: 1 x 2
mean_column mean_vector
<dbl> <dbl>
1 19.3 5.00
按预期工作。但是,如果我们编写相同的函数但为参数选择不同的名称会怎样?
calculate_means <- function(df, x, y) {
x <- enquo(x)
summarise(df, mean_column = mean(!!x), mean_vector = mean(y))
}
calculate_means(df1, x, a)
# A tibble: 1 x 2
mean_column mean_vector
<dbl> <dbl>
1 8.67 19.3
calculate_means(df1, y, b)
# A tibble: 1 x 2
mean_column mean_vector
<dbl> <dbl>
1 19.3 19.3
第一个参数的评估与之前相同,但第二个参数始终评估数据帧的列 "y"。 它不应该分别评估向量 "a" 和 "b" 吗?
我们可以使用 globalenv()
获取对象列表,通过将对象名称作为字符串传递来获取对象的值,并在 summarise
语句
calculate_means <- function(df, x, y) {
x <- enquo(x)
y <- quo_name(enquo(y))
v1 <- globalenv()[[y]]
df %>%
summarise(mean_column = mean(!! x),
mean_vector = mean(v1))
}
calculate_means(df1, x, a)
# A tibble: 1 x 2
# mean_column mean_vector
# <dbl> <dbl>
#1 8.67 1.00
calculate_means(df1, y, b)
# A tibble: 1 x 2
# mean_column mean_vector
# <dbl> <dbl>
#1 19.3 5.00
假设,如果我们还需要获取'y'列的mean
calculate_means <- function(df, x, y) {
x <- enquo(x)
y <- quo_name(enquo(y))
v1 <- globalenv()[[y]]
df %>%
summarise(mean_column = mean(!! x),
mean_vector = mean(v1),
mean_column2 = mean(.data$y))
}
calculate_means(df1, x, a)
# A tibble: 1 x 3
# mean_column mean_vector mean_column2
# <dbl> <dbl> <dbl>
#1 8.67 1.00 19.3
summarise
的实际参数中的变量首先在 summarise
的第一个参数指定的数据框中查找,并且仅在 summarise
的调用方中查找,如果在该数据框中找不到。因此,通过将 y
硬编码到 summarise
参数中,它将始终首先在 df1
中查找它。
1)我们可以用!!避免这种情况。的论点!!未在数据参数中查找。
calculate_means2 <- function(df, x, y) {
x <- enquo(x)
summarise(df, mean_column = mean(!!x), mean_vector = mean(!!y))
}
calculate_means2(df1, y, b)
# A tibble: 1 x 2
mean_column mean_vector
<dbl> <dbl>
1 19.3 5.00
2) 我们可以用as_quosure
来强调这一点。这会将 y
的值放入 quosure 公式中。在示例中,y <- as_quosure(y)
将导致新的 quosure 包含 ~c(6, 4)
.
calculate_means3 <- function(df, x, y) {
x <- enquo(x)
y <- rlang::as_quosure(y)
summarise(df, mean_column = mean(!!x), mean_vector = mean(!!y))
}
calculate_means3(df1, y, b)
# A tibble: 1 x 2
mean_column mean_vector
<dbl> <dbl>
1 19.3 5.00
3) 当然,我们可以只使用不太可能在数据框中使用的正式参数名称:
calculate_means4 <- function(df, x, y.) {
x <- enquo(x)
summarise(df, mean_column = mean(!!x), mean_vector = mean(y.))
}
calculate_means4(df1, y, b)
# A tibble: 1 x 2
mean_column mean_vector
<dbl> <dbl>
1 19.3 5.00