asn*_*snr 50 r lazy-evaluation dplyr
我想使用下面的计算参数化dplyr,找出哪些值Sepal.Length与多个值相关联Sepal.Width:
library(dplyr)
iris %>%
group_by(Sepal.Length) %>%
summarise(n.uniq=n_distinct(Sepal.Width)) %>%
filter(n.uniq > 1)
Run Code Online (Sandbox Code Playgroud)
通常我会写这样的东西:
not.uniq.per.group <- function(data, group.var, uniq.var) {
iris %>%
group_by(group.var) %>%
summarise(n.uniq=n_distinct(uniq.var)) %>%
filter(n.uniq > 1)
}
Run Code Online (Sandbox Code Playgroud)
但是,这种方法会因为dplyr使用非标准评估而引发错误.应该如何编写这个函数?
asn*_*snr 48
您需要使用dplyr函数的标准评估版本(只需将'_'附加到函数名称,即.group_by_&summarise_)并将字符串传递给您的函数,然后您需要将其转换为符号.要参数化summarise_的参数,您需要使用interp(),它在lazyeval包中定义.具体来说:
library(dplyr)
library(lazyeval)
not.uniq.per.group <- function(df, grp.var, uniq.var) {
df %>%
group_by_(grp.var) %>%
summarise_( n_uniq=interp(~n_distinct(v), v=as.name(uniq.var)) ) %>%
filter(n_uniq > 1)
}
not.uniq.per.group(iris, "Sepal.Length", "Sepal.Width")
Run Code Online (Sandbox Code Playgroud)
有关详细信息,请参阅非标准评估的dplyr 插图.
Pau*_*aul 18
与最高0.5的旧dplyr版本一样,新的dplyr具有标准评估(SE)和非标准评估(NSE)的功能.但他们的表达方式与之前不同.
如果您需要NSE功能,则传递裸表达式并使用enquo将其捕获为quosures.如果您想要SE功能,则省略sym()并直接传递quosures(或符号).以下是该问题的SE解决方案:
library(tidyverse)
library(rlang)
f1 <- function(df, grp.var, uniq.var) {
df %>%
group_by(!!grp.var) %>%
summarise(n_uniq = n_distinct(!!uniq.var)) %>%
filter(n_uniq > 1)
}
a <- f1(iris, quo(Sepal.Length), quo(Sepal.Width))
b <- f1(iris, sym("Sepal.Length"), sym("Sepal.Width"))
identical(a, b)
#> [1] TRUE
Run Code Online (Sandbox Code Playgroud)
请注意SE版本如何使您能够使用字符串参数 - 首先使用它们将它们转换为符号sym().有关更多信息,请参阅使用dplyr vignette 编程.
Moo*_*per 15
这是使用curl卷曲 {{伪运算符从rlang 0.4执行此操作的方法:
library(dplyr)
not.uniq.per.group <- function(data, group.var, uniq.var) {
data %>%
group_by({{group.var}}) %>%
summarise(n.uniq=n_distinct({{uniq.var}})) %>%
filter(n.uniq > 1)
}
iris %>% not.uniq.per.group(Sepal.Length, Sepal.Width)
#> # A tibble: 25 x 2
#> Sepal.Length n.uniq
#> <dbl> <int>
#> 1 4.4 3
#> 2 4.6 4
#> 3 4.8 3
#> 4 4.9 5
#> 5 5 8
#> 6 5.1 6
#> 7 5.2 4
#> 8 5.4 4
#> 9 5.5 6
#> 10 5.6 5
#> # ... with 15 more rows
Run Code Online (Sandbox Code Playgroud)
akr*_*run 11
在devel版本dplyr(即将发布0.6.0)中,我们也可以使用稍微不同的语法来传递变量.
f1 <- function(df, grp.var, uniq.var) {
grp.var <- enquo(grp.var)
uniq.var <- enquo(uniq.var)
df %>%
group_by(!!grp.var) %>%
summarise(n_uniq = n_distinct(!!uniq.var)) %>%
filter(n_uniq >1)
}
res2 <- f1(iris, Sepal.Length, Sepal.Width)
res1 <- not.uniq.per.group(iris, "Sepal.Length", "Sepal.Width")
identical(res1, res2)
#[1] TRUE
Run Code Online (Sandbox Code Playgroud)
这里enquo接受参数并quosure通过懒惰地评估函数参数并在汇总内部将值返回为(类似于基本R中的替换),我们要求它取消引用(!!或UQ)以便对其进行评估.
在dplyr(0.7.4)的当前版本中,不建议使用标准评估函数版本(例如,在函数名称后附加“ _” group_by_)。相反,编写函数时应依靠tidyeval。
这是函数的外观示例:
# definition of your function
not.uniq.per.group <- function(data, group.var, uniq.var) {
# enquotes variables to be used with dplyr-functions
group.var <- enquo(group.var)
uniq.var <- enquo(uniq.var)
# use '!!' before parameter names in dplyr-functions
data %>%
group_by(!!group.var) %>%
summarise(n.uniq=n_distinct(!!uniq.var)) %>%
filter(n.uniq > 1)
}
# call of your function
not.uniq.per.group(iris, Sepal.Length, Sepal.Width)
Run Code Online (Sandbox Code Playgroud)
如果您想了解所有细节,有一个极好的小插曲由dplyr队在这如何工作的。
| 归档时间: |
|
| 查看次数: |
25684 次 |
| 最近记录: |