“!!”是什么意思 在 R 中做,为什么要使用它?
具体来说,我正在查看一个包含短语a = !!sym("x")where "x"is a string的函数
。我认为sym通过将字符串转换为对象来工作,因此a = sym("x")将设置为a等于 object x。有什么!!用?我读到它没有引用它后面的任何内容,但我认为sym它本身没有引用字符串?
我还看到!!与其他功能一起使用。它在做什么?
使用旧select_()函数,我可以将命名向量传递给select并立即更改位置和列名:
my_data <- data_frame(foo = 0:10, bar = 10:20, meh = 20:30)
my_newnames <- c("newbar" = "bar", "newfoo" = "foo")
move_stuff <- function(df, newnames) {
select_(df, .dots = newnames)
}
move_stuff(my_data, newnames = my_newnames) )
# this is the desired output
# A tibble: 4 x 2
newbar newfoo
<int> <int>
1 10 0
2 11 1
3 12 2
4 13 3
Run Code Online (Sandbox Code Playgroud)
我尝试使用quosures和拼接做类似的事情 - 选择列效果很好,但是矢量的名称(因此同时重命名列)似乎被忽略了.以下两个都返回数据框,列中包含名称bar和foo,但不是newbar和newfoo:
move_stuff2 <- function(df, newnames) …Run Code Online (Sandbox Code Playgroud) 假设我们有一个cols_to_select包含我们想要从数据帧中选择的列的字符向量df,例如
df <- tibble::data_frame(a=1:3, b=1:3, c=1:3, d=1:3, e=1:3)
cols_to_select <- c("b", "d")
Run Code Online (Sandbox Code Playgroud)
假设我们也想使用dplyr::select它,因为它是使用的操作的一部分,%>%因此使用select使代码易于阅读.
似乎有很多方法可以实现,但有些方法比其他方法更强大.请你告诉我哪个是"正确的"版本,为什么?或许还有另一种更好的方法?
dplyr::select(df, cols_to_select) #Fails if 'cols_to_select' happens to be the name of a column in df
dplyr::select(df, !!cols_to_select) # i.e. using UQ()
dplyr::select(df, !!!cols_to_select) # i.e. using UQS()
cols_to_select_syms <- rlang::syms(c("b", "d")) #See [here](https://stackoverflow.com/questions/44656993/how-to-pass-a-named-vector-to-dplyrselect-using-quosures/44657171#44657171)
dplyr::select(df, !!!cols_to_select_syms)
Run Code Online (Sandbox Code Playgroud)
ps我意识到这可以简单地在基础R中实现 df[,cols_to_select]
通过使用dplyr在函数中使用非标准求值,寻找一种更有效/更优雅的方法将多个参数传递给组.我不想使用...运算符,而是单独指定函数.
我的具体用例是一个函数,它接受数据框并创建一个语法更简单的ggplot对象.这是我想用我的函数自动化的代码示例:
# create data frame
my_df <- data.frame(month = sample(1:12, 1000, replace = T),
category = sample(head(letters, 3), 1000, replace = T),
approved = as.numeric(runif(1000) < 0.5))
my_df$converted <- my_df$approved * as.numeric(runif(1000) < 0.5)
my_df %>%
group_by(month, category) %>%
summarize(conversion_rate = sum(converted) / sum(approved)) %>%
ggplot + geom_line(aes(x = month, y = conversion_rate, group = category,
color = category))
Run Code Online (Sandbox Code Playgroud)
我想将group_by,summarize,ggplot和geom_line组合成一个简单的函数,我可以提供x,y和group,并让它执行所有脏工作.这就是我的工作:
# create the function that does the grouping and plotting
plot_lines <- function(df, x, y, group) {
x <- …Run Code Online (Sandbox Code Playgroud) 我可以从文档中看到rlang::enquo()和rlang::quo()在不同的上下文中使用。因此,我rlang::enysm()最近在函数声明中使用了(见下文)。然而,包裹在另一个 SE 函数调用中,我得到了一个意外错误,我猜这与惰性求值有关(如果我force(x)在 中,它就会消失f_enysm())。但似乎我也可以通过简单地使用sym(x)而不是ensym(x)因为x是一个不传达任何关于环境的信息(而不是quosures)的字符串来解决这个问题。
那安全吗?
如果是,我不知道什么时候应该更喜欢ensym(),sym并且建议的用途似乎与quo()/ enquo()、expr()/enexpr()等使用的术语不一致。
library(rlang)
f_ensym <- function(data, x, fun) {
x <- fun(x)
head(dplyr::arrange(data, !!x))
}
f_ensym(mtcars, "cyl", sym)
#> mpg cyl disp hp drat wt qsec vs am gear carb
#> 1 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
#> 2 24.4 4 146.7 …Run Code Online (Sandbox Code Playgroud) 考虑以下:
library(tidyverse)
df <- tibble(x = rnorm(100), y = rnorm(100, 10, 2), z = x * y)
df %>%
mutate_all(funs(avg = mean(.), dev = sd(.), scaled = (. - mean(.)) / sd(.)))
Run Code Online (Sandbox Code Playgroud)
有没有办法通过引用和列来避免调用mean和sd两次.我想到的是类似的东西avgdev
df %>%
mutate_all(funs(avg = mean(.), dev = sd(.), scaled = (. - avg) / dev))
Run Code Online (Sandbox Code Playgroud)
显然,这是行不通的,因为没有列avg和dev,但是x_avg,x_dev,y_avg,y_dev,等.
有一个好办法,内部funs使用rlang的工具以编程方式创建这些列引用,这样我可以参考由以前命名的参数创建的列funs(当.是x,我将引用x_mean和 …
有没有办法来动态/编程产生case_when的条件dplyr有不同的列名和/或不同数量的条件是什么?我有一个交互式脚本,我正在尝试将其转换为函数。case_when语句中有很多重复的代码,我想知道它是否可以以某种方式自动化,而无需一次又一次地从头开始编写所有内容。
这是一个虚拟数据集:
test_df = tibble(low_A=c(5, 15, NA),
low_TOT=c(NA, 10, NA),
low_B=c(20, 25, 30),
high_A=c(NA, NA, 10),
high_TOT=c(NA, 40, NA),
high_B=c(60, 20, NA))
expected_df = tibble(low_A=c(5, 15, NA),
low_TOT=c(NA, 10, NA),
low_B=c(20, 25, 30),
ans_low=c(5, 10, 30),
high_A=c(NA, NA, 10),
high_TOT=c(NA, 40, NA),
high_B=c(60, 20, NA),
ans_high=c(60, 40, 10))
> expected_df
# A tibble: 3 x 8
low_A low_TOT low_B ans_low high_A high_TOT high_B ans_high
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 5 …Run Code Online (Sandbox Code Playgroud) f <- function(x) enquo(x)
e <- f()
#<quosure: empty>
#~
Run Code Online (Sandbox Code Playgroud)
这些都不起作用:
> is_empty(e)
[1] FALSE
> is_missing(e)
[1] FALSE
> is_false(e)
[1] FALSE
> is_quosure(e)
[1] TRUE
Run Code Online (Sandbox Code Playgroud) 我正在尝试编写一个自定义函数,它将根据预定义变量向量(例如vector_heavy)的值计算新变量,然后根据提供给函数的参数(例如,custom_name)命名新变量.
这个变量命名是我的技能失败的地方.任何帮助是极大的赞赏.
library(tidyverse)
vector_heavy <- quos(disp, wt, cyl)
cv_compute <- function(data, cv_name, cv_vector){
cv_name <- enquo(cv_name)
data %>%
rowwise() %>%
mutate(!!cv_name = mean(c(!!!cv_vector), na.rm = TRUE)) %>%
ungroup()
}
d <- cv_compute(mtcars, cv_name = custom_name, cv_vector = vector_heavy)
Run Code Online (Sandbox Code Playgroud)
我的错误消息是:
Error: unexpected '=' in:
" rowwise() %>%
mutate(!!cv_name ="
Run Code Online (Sandbox Code Playgroud)
删除!!之前cv_name的mutate()将导致一个函数计算一个字面命名的新变量cv_name,并忽略custom_name我作为参数包含的内容.
cv_compute <- function(data, cv_name, cv_vector){
cv_name <- enquo(cv_name)
data %>%
rowwise() %>%
mutate(cv_name = mean(c(!!!cv_vector), na.rm = TRUE)) %>%
ungroup()
} …Run Code Online (Sandbox Code Playgroud) 我一直在使用dplyr的quosures:
library(dplyr)
library(ggplot2)
thing <- quo(clarity)
diamonds %>% select(!!thing)
print(paste("looking at", thing))
Run Code Online (Sandbox Code Playgroud)
[1]"看着〜""看清晰度"
我真的想打印出放入现状的字符串值,但只能得到以下内容:
print(thing)
Run Code Online (Sandbox Code Playgroud)
<quosure:global>
〜清晰度
print(thing[2])
Run Code Online (Sandbox Code Playgroud)
明晰()
substr(thing[2],1, nchar(thing[2]))
Run Code Online (Sandbox Code Playgroud)
[1]"清晰度"
有没有更简单的方法来"取消引用"quo()?