使用 dplyr 的 do() 在复杂表达式上进行 NSE
NSE on complex expressions with dplyr's do()
当变量引用的形式为 ".$mpg"
时,有人可以帮助我理解 NSE 如何与 dplyr 一起工作。
看完here后,我想用as.name就可以了,因为我有一个字符串,它给出了一个变量名。
例如,这个有效:
mtcars %>%
summarise_(interp(~mean(var), var = as.name("mpg")))
这行不通:
mtcars %>%
summarise_(interp(~mean(var), var = as.name(".$mpg")))
但这确实:
mtcars %>%
summarise(mean(.$mpg))
这也是:
mtcars %>%
summarise(mean(mpg))
我希望能够以 .$mpg
的形式指定变量,这样当我无法像在以下示例:
library(dplyr)
library(broom)
mtcars %>%
tbl_df() %>%
slice(., 1) %>%
do(tidy(prop.test(.$mpg, .$disp, p = .50)))
- 这里选择随机变量是为了演示prop.test函数的工作原理,请不要将此解释为误用测试。
最后,我想把它变成这样的函数:
library(lazyeval)
library(broom)
library(dplyr)
p_test <- function(x, miles, distance){
x %>%
tbl_df() %>%
slice(., 1) %>%
do_(tidy(prop.test(miles, distance, p = .50)))
}
p_test(mtcars, ".$mpg", ".$disp")
我原本以为我必须做这样的事情:
interp(~var, var = as.name(miles)
其中 miles
将被替换为 .$mpg
,但正如我在顶部提到的那样,这似乎不起作用。
原因是 as.name
创建了一个未计算的 变量名 ,但是 .$mpg
在代码中使用时 不是 一个变量名。相反,它是一个复杂的表达式,相当于:
`$`(., mpg)
也就是说,它是对函数 $
的函数调用,带有两个参数。使用 as.name
会导致 R 随后搜索名称为 `.$mpg`
的变量,而不是调用上述函数。
这就是为什么您的尝试不起作用的原因。解决方案相对简单:我们需要创建一个未求值的函数调用表达式,而不是创建一个未求值的变量名。我们可以通过多种方式做到这一点,我将在这里展示两个。
第一个就是调用 parse
:
p_test = function (data, miles, distance) {
x = parse(text = miles)[[1]]
n = parse(text = distance)[[1]]
data %>%
slice(1) %>%
do_(interp(~tidy(prop.test(x, n, p = 0.5)), x = x, n = n))
}
现在您可以调用 p_test(mtcars, '.$mpg', '.$disp')
并获得所需的结果。
然而,更 dplyr-y 做同样事情的方法是将未评估的对象传递给 p_test
:
p_test(mtcars, mpg, disp)
…我们可以通过简单的更改轻松做到这一点:
p_test_ = function (data, var1, var2) {
data %>%
slice(1) %>%
do_(interp(~tidy(prop.test(.$x, .$n, p = 0.5)),
x = as.name(var1), n = as.name(var2)))
}
p_test = function (data, var1, var2) {
p_test_(data, substitute(var1), substitute(var2))
}
现在下面两段代码都可以工作了:
p_test(mtcars, mpg, disp)
p_test_(mtcars, 'mpg', 'disp')
当变量引用的形式为 ".$mpg"
时,有人可以帮助我理解 NSE 如何与 dplyr 一起工作。
看完here后,我想用as.name就可以了,因为我有一个字符串,它给出了一个变量名。
例如,这个有效:
mtcars %>%
summarise_(interp(~mean(var), var = as.name("mpg")))
这行不通:
mtcars %>%
summarise_(interp(~mean(var), var = as.name(".$mpg")))
但这确实:
mtcars %>%
summarise(mean(.$mpg))
这也是:
mtcars %>%
summarise(mean(mpg))
我希望能够以 .$mpg
的形式指定变量,这样当我无法像在以下示例:
library(dplyr)
library(broom)
mtcars %>%
tbl_df() %>%
slice(., 1) %>%
do(tidy(prop.test(.$mpg, .$disp, p = .50)))
- 这里选择随机变量是为了演示prop.test函数的工作原理,请不要将此解释为误用测试。
最后,我想把它变成这样的函数:
library(lazyeval)
library(broom)
library(dplyr)
p_test <- function(x, miles, distance){
x %>%
tbl_df() %>%
slice(., 1) %>%
do_(tidy(prop.test(miles, distance, p = .50)))
}
p_test(mtcars, ".$mpg", ".$disp")
我原本以为我必须做这样的事情:
interp(~var, var = as.name(miles)
其中 miles
将被替换为 .$mpg
,但正如我在顶部提到的那样,这似乎不起作用。
原因是 as.name
创建了一个未计算的 变量名 ,但是 .$mpg
在代码中使用时 不是 一个变量名。相反,它是一个复杂的表达式,相当于:
`$`(., mpg)
也就是说,它是对函数 $
的函数调用,带有两个参数。使用 as.name
会导致 R 随后搜索名称为 `.$mpg`
的变量,而不是调用上述函数。
这就是为什么您的尝试不起作用的原因。解决方案相对简单:我们需要创建一个未求值的函数调用表达式,而不是创建一个未求值的变量名。我们可以通过多种方式做到这一点,我将在这里展示两个。
第一个就是调用 parse
:
p_test = function (data, miles, distance) {
x = parse(text = miles)[[1]]
n = parse(text = distance)[[1]]
data %>%
slice(1) %>%
do_(interp(~tidy(prop.test(x, n, p = 0.5)), x = x, n = n))
}
现在您可以调用 p_test(mtcars, '.$mpg', '.$disp')
并获得所需的结果。
然而,更 dplyr-y 做同样事情的方法是将未评估的对象传递给 p_test
:
p_test(mtcars, mpg, disp)
…我们可以通过简单的更改轻松做到这一点:
p_test_ = function (data, var1, var2) {
data %>%
slice(1) %>%
do_(interp(~tidy(prop.test(.$x, .$n, p = 0.5)),
x = as.name(var1), n = as.name(var2)))
}
p_test = function (data, var1, var2) {
p_test_(data, substitute(var1), substitute(var2))
}
现在下面两段代码都可以工作了:
p_test(mtcars, mpg, disp)
p_test_(mtcars, 'mpg', 'disp')