tidy evaluation
sunqi
2020/8/5
概述
也称作非标准评估
代码
代码语言:javascript复制rm(list = ls())
library("tidyverse")
library(rlang)
# 在编写代码时遇到不同数据集或者不同变量的操作比如
iris %>%
group_by(Species) %>%
summarise(mean=mean(Sepal.Length))
代码语言:javascript复制## # A tibble: 3 x 2
## Species mean
## <fct> <dbl>
## 1 setosa 5.01
## 2 versicolor 5.94
## 3 virginica 6.59
代码语言:javascript复制# 如果换个变量,那么就需要重新编写代码
# 于是乎,想到了用自定义函数进行重复性的操作
# 但是R语言函数的传递和python是不一样的
# 因此,在tidyverse中,对这种情况进行了解决
# !!对表达式求解
# quo 生成表达式
group_mean <- function(data, var_group,varname, var_mean) {
data %>%
# 对变量进行!!
group_by(!!var_group) %>%
summarise(!!varname:=mean(!!var_mean))
}
# 调用的时候使用quo函数
group_mean(data=iris,
var_group=quo(Species),
varname="mean_sepal.length",
var_mean=quo(Sepal.Length))
代码语言:javascript复制## # A tibble: 3 x 2
## Species mean_sepal.length
## <fct> <dbl>
## 1 setosa 5.01
## 2 versicolor 5.94
## 3 virginica 6.59
代码语言:javascript复制# 上述函数实现了对字符和函数名的调用
# 但是输入的时候需要书写quo
# 这个时候可以使用enquo
group_mean <- function(data, var_group,varname, var_mean) {
var_group <- enquo(var_group)
var_mean <- enquo(var_mean)
data %>%
group_by(!!var_group) %>%
summarise(!!varname:=mean(!!var_mean))
}
group_mean(data=iris,
var_group=Species,
varname="mean_sepal.length",
var_mean=Sepal.Length)
代码语言:javascript复制## # A tibble: 3 x 2
## Species mean_sepal.length
## <fct> <dbl>
## 1 setosa 5.01
## 2 versicolor 5.94
## 3 virginica 6.59
代码语言:javascript复制## 上述代码的两次引用还是不太方便
## 使用大括号
## 大括号同时包含的转换表达式和求解表达式
group_mean <- function(data, var_group,varname, var_mean) {
data %>%
group_by({{var_group}}) %>%
summarise({{varname}}:= mean ({{var_mean}}))
}
group_mean(data=iris,
var_group=Species,
varname="mean_sepal.length",
var_mean=Sepal.Length)
代码语言:javascript复制## # A tibble: 3 x 2
## Species mean_sepal.length
## <fct> <dbl>
## 1 setosa 5.01
## 2 versicolor 5.94
## 3 virginica 6.59
代码语言:javascript复制# 现版本的tidyverse还可以这样写函数
# across函数支持对队列执行相同的操作
sum_group_vars <- function(data,
group_vars,
sum_vars){
data %>%
group_by(across({{ group_vars }})) %>%
summarise(n = n(),
across({{ sum_vars }},
list(mean = mean, sd = sd))
)
}
# 调用函数
sum_group_vars(mpg, c(model, year), c(hwy, cty)) %>% head()
代码语言:javascript复制## # A tibble: 6 x 7
## # Groups: model [3]
## model year n hwy_mean hwy_sd cty_mean cty_sd
## <chr> <int> <int> <dbl> <dbl> <dbl> <dbl>
## 1 4runner 4wd 1999 4 19 1.41 15.2 0.5
## 2 4runner 4wd 2008 2 18.5 2.12 15 1.41
## 3 a4 1999 4 27.5 1.73 18.2 2.06
## 4 a4 2008 3 29.3 2.08 19.7 1.53
## 5 a4 quattro 1999 4 25.2 0.5 16.5 1.29
## 6 a4 quattro 2008 4 26.2 1.5 17.8 2.22
代码语言:javascript复制# 处理多个参数
# 使用... 代替传递参数
grouped_mean <- function(df, summary_var, ...) {
summary_var <- enquo(summary_var)
group_var <- enquos(...)
df %>%
group_by(!!!group_var) %>%
summarise(mean = mean(!!summary_var))
}
# 运行函数
# 这里传递两个分组变量
grouped_mean(mtcars, disp, cyl, am)
代码语言:javascript复制## # A tibble: 6 x 3
## # Groups: cyl [3]
## cyl am mean
## <dbl> <dbl> <dbl>
## 1 4 0 136.
## 2 4 1 93.6
## 3 6 0 205.
## 4 6 1 155
## 5 8 0 358.
## 6 8 1 326
代码语言:javascript复制## 试试ggplot
## 编写一个绘制iris箱式图的函数
box <- function(data, var_group, var_target) {
data %>% ggplot(aes(x={{var_group}},y={{var_target}}))
geom_boxplot()
}
box(data = iris,var_group = Species,var_target = Sepal.Length)
结束语
这么久以来,这是我最喜欢的一个R脚本,解决了我一直以来函数编写的问题,以前都是使用eval(parse(text=“代码字符串”))来实现自定义函数的传递功能,另外R for data science,这本书贵不贵?,想买一本看看。
love&peace