我正在尝试使用tidyeval(非标准评估)围绕“ lm”编写一个函数。使用基本R NSE,它的工作原理是:
lm_poly_raw <- function(df, y, x, degree = 1, ...){
lm_formula <-
substitute(expr = y ~ poly(x, degree, raw = TRUE),
env = list(y = substitute(y),
x = substitute(x),
degree = degree))
eval(lm(lm_formula, data = df, ...))
}
lm_poly_raw(mtcars, hp, mpg, degree = 2)
Run Code Online (Sandbox Code Playgroud)
但是,我还没有弄清楚如何使用tidyeval和编写此函数rlang。我认为substitute应该用代替enquo,并用代替!!。哈德利的Adv-R有一些提示,但我不知道。
我是整理eval并尝试编写泛型函数的新手 - 我现在正在努力的一件事就是为分类变量编写多个过滤条件.这就是我现在正在使用的 -
create_expr <- function(name, val){
if(!is.null(val))
val <- paste0("c('", paste0(val, collapse = "','"), "')")
paste(name, "%in%", val)
}
my_filter <- function(df, cols, conds){
# Args:
# df: dataframe which is to be filtered
# cols: list of column names which are to be filtered
# conds: corresponding values for each column which need to be filtered
cols <- as.list(cols)
conds <- as.list(conds)
args <- mapply(create_expr, cols, conds, SIMPLIFY = F)
if(!length(args))
stop(cat("No filters provided"))
df <- df …Run Code Online (Sandbox Code Playgroud) 在dplyr v0.7.0中,.data引入了代词,允许我们用字符串引用变量。我只是好奇这种方法是否比“quosure”方法更受欢迎。例如,这是一种使用.data代词的方法:
varname <- "gear"
data_pronoun_method_df <- dplyr::mutate(mtcars, new_col = .data[[varname]] + 2)
Run Code Online (Sandbox Code Playgroud)
这与使用该quosure方法的示例进行了比较:
quo_varname <- rlang::quo(gear)
quo_method_df <- dplyr::mutate(mtcars, new_col = !! quo_varname + 2)
Run Code Online (Sandbox Code Playgroud)
两种方法产生相同的输出:
data_pronoun_method_df
# mpg cyl disp hp drat wt qsec vs am gear carb new_col
# 1 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4 6
# 2 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4 6
# 3 22.8 …Run Code Online (Sandbox Code Playgroud) 我正在绘制一个 y 变量与多个 x 变量的关系图。我有一个使用 lapply 的工作解决方案。但是,我无法将 x 变量的名称写为每个图的 x 标签。这是我所拥有的一个简化示例:
目标是针对每个 x 变量绘制 y 变量,从而生成三个图,并将每个 x 变量的名称添加为 x 轴标签。
生成一个包含 1 个 y 变量和 3 个 x 变量的数据框:
df <- data.frame(y.variable=c(11:20), x1=c(21:30),x2=c(1:10),x3=c(31:40))
Run Code Online (Sandbox Code Playgroud)
一个应该以字符串形式检索变量名称的函数:
get_name <- function(v1) {deparse(substitute(v1))}
Run Code Online (Sandbox Code Playgroud)
生成 y 相对于 x 变量的图的函数:
generate_plot <- function(x.variable) {ggplot(data = df, aes(x.variable, y.variable )) +geom_point() + xlab(get_name(variable.name))}
Run Code Online (Sandbox Code Playgroud)
调用 lapply 对 df 的每一列执行generate_plot:
lapply(df, generate_plot)
Run Code Online (Sandbox Code Playgroud)
这会产生三个图,每个图都将“variable.x”作为其 x 标签,而不是所需的变量名称 x1、x2 和 x3。
这是数据:
library(tidyverse)
data <- tibble::tribble(
~var1, ~var2, ~var3, ~var4, ~var5,
"a", "d", "g", "hello", 1L,
"a", "d", "h", "hello", 2L,
"b", "e", "h", "k", 4L,
"b", "e", "h", "k", 7L,
"c", "f", "i", "hello", 3L,
"c", "f", "i", "hello", 4L
)
Run Code Online (Sandbox Code Playgroud)
和矢量,我想用:
filter_var <- c("hello")
groupby_vars1 <- c("var1", "var2", "var3")
groupby_vars2 <- c("var1", "var2")
joinby_vars1 <- c("var1", "var2")
joinby_vars2 <- c("var1", "var2", "var3")
Run Code Online (Sandbox Code Playgroud)
第2和第5,第3和第4个向量相同,但请假设它们不同并将它们保留为不同的向量.
现在我想创建一个通用函数,我可以在其中获取数据和这些向量来获得结果.
my_fun <- function(data, filter_var, groupby_vars1,groupby_vars2, joinby_vars1, joinby_vars2) {
data2 <- data %>% filter(var4 == filter_var) …Run Code Online (Sandbox Code Playgroud) 有时,在进行探索性分析或生成报告时,我们希望绘制许多变量的单变量分布.我可以在经过一些整洁的伎俩之后面对这个情节,但是有序因素,我想继续按照情节订购.
因此,为了更有效地完成它,我构建了一个简单dplyr/ ggplot基于函数.我使用vcd包的关节炎数据集在下面做了这个例子.
library(dplyr)
library(ggplot2)
data(Arthritis, package = "vcd")
head(Arthritis)
plotUniCat <- function(df, x) {
x <- enquo(x)
df %>%
filter(!is.na(!!x)) %>%
count(!!x) %>%
mutate(prop = prop.table(n)) %>%
ggplot(aes(y=prop, x=!!x)) +
geom_bar(stat = "identity")
}
plotUniCat(Arthritis, Improved)
Run Code Online (Sandbox Code Playgroud)
我可以用很短的方式绘制格式化的图形,这很酷,但只有一个变量.
我尝试使用for循环调用多个变量,但它不起作用.代码运行,但没有任何反应.
variables <- c("Improved", "Sex", "Treatment")
for (i in variables) {
plotUniCat(Arthritis, noquote(i))
}
Run Code Online (Sandbox Code Playgroud)
我搜索了这个,但对我来说仍然不清楚.有人知道我做错了什么或如何使它有效?
提前致谢.
我没有一个紧迫的用例,但想了解整齐的eval和data.table如何协同工作.
我有替代解决方案,所以我最感兴趣的是为什么,因为我希望能够更好地理解整齐的eval,这将有助于我在各种各样的用例中使用.
如何使用group by进行data.table +整理eval工作?
在以下示例中,我使用了rlang的开发版本.
我根据Stefan F的答案和我的进一步探索更新了我的原始问题:我不再认为插入的〜是问题的重要部分,因为它也存在于dplyr代码中,但我有一个特定的代码:data.table + group by + quo我不明白为什么不起作用.
# setup ------------------------------------
suppressPackageStartupMessages(library("data.table"))
suppressPackageStartupMessages(library("rlang"))
suppressPackageStartupMessages(library("dplyr"))
#> Warning: package 'dplyr' was built under R version 3.5.1
dt <- data.table(
num_campaign = 1:5,
id = c(1, 1, 2, 2, 2)
)
df <- as.data.frame(dt)
# original question ------------------------
aggr_expr <- quo(sum(num_campaign))
q <- quo(dt[, aggr := !!aggr_expr][])
e <- quo_get_expr(q)
e
#> dt[, `:=`(aggr, ~sum(num_campaign))][]
dt[, `:=`(aggr, ~sum(num_campaign))][]
#> Error in `[.data.table`(dt, , `:=`(aggr, ~sum(num_campaign))): RHS of …Run Code Online (Sandbox Code Playgroud) 我想创建一个生成ggplot图的函数,并为方面变量提供可选参数facet_grid()。
特别是,如果可能的话,我想纳入条件逻辑里面 facet_grid。我也想使用整洁的评估框架-所以没有公式字符串!
但是,我所有的尝试都失败了。
library(tidyverse)
iris <- iris %>% add_column(idx = rep(1:2, 75))
Run Code Online (Sandbox Code Playgroud)
我的第一次尝试失败,因为facet_grid试图找到一个名为NULL(带有反引号)的变量。
plot_iris <- function(df_in, facet_var = NULL){
ggplot(df_in) +
geom_point(aes(Sepal.Length, Sepal.Width)) +
facet_grid(vars(!!enquo(facet_var)), vars(idx))
}
plot_iris(iris)
#> Error: At least one layer must contain all faceting variables: `NULL`.
#> * Plot is missing `NULL`
#> * Layer 1 is missing `NULL`
Run Code Online (Sandbox Code Playgroud)
plot_iris(iris, Species)但是,运行正常。
我的第二次尝试也失败了,但是有不同的错误消息。
plot_iris2 <- function(df_in, facet_var = NULL){
facet_quo <- enquo(facet_var)
ggplot(df_in) …Run Code Online (Sandbox Code Playgroud) 本文阐述了一种新的卷曲卷曲整洁评价方法。给出了几个示例,说明了这种风格的非标准评估(NSE)的使用。
library(tidyverse)
# Example 1 --------------------------
max_by <- function(data, var, by) {
data %>%
group_by({{ by }}) %>%
summarise(maximum = max({{ var }}, na.rm = TRUE))
}
starwars %>% max_by(height)
starwars %>% max_by(height, by = gender)
# Example 2 --------------------------
summarise_by <- function(data, ..., by) {
data %>%
group_by({{ by }}) %>%
summarise(...)
}
starwars %>%
summarise_by(average = mean(height, na.rm = TRUE),
maximum = max(height, na.rm = TRUE),
by = gender)
Run Code Online (Sandbox Code Playgroud)
我创建了一些自己的函数,实际上这是一个更容易开发的框架,而不用担心所有的夸张和爆炸。
但是,同一篇文章说明我们还没有完全走出困境:
当您需要以某种方式修改输入或输入名称时,只需要使用引号和取消引号(带有复数形式的enquos()和!!!)。
...,但未提供示例。不抱怨,只是问是否有人可以填补空白并提供示例。由于我对Tidy的评估不流利,所以我真的不明白作者对那句话的理解(对不起)。
我正在尝试生成具有重要恒星的相关矩阵。采取以下数据框:
df <- tibble(stub = c(1,2,3,4),
stub_pvalue = c(.00, .04, .07,.2))
Run Code Online (Sandbox Code Playgroud)
我想编写一个函数,如果stub_pvalue小于.01,则粘贴任何与“ ***”连接的列(例如本例中的stub),否则直接粘贴stub。就像是:
assign_stars <- function(var) {
if (paste0(var,"_pvalue") < .01) {
paste0(var, "***")
} else {
paste0(var)
}
}
df %>%
mutate(col_with_stars = map_chr(col, assign_stars))
Run Code Online (Sandbox Code Playgroud)
但是,我不知道如何在var +“ _pvalue”上评估if的第一个逻辑条件。有人可以帮忙吗?