如何动态构建字符串并将其传递给 R 中 dplyr 的 mutate() 函数?
How can I dynamically build a string and pass it to dplyr's mutate() function in R?
我之前问过类似的问题()。给定的答案工作正常。然而,事实证明,它并不完全适用于我的用例。
请考虑以下最小工作示例:
library(RSQLite)
library(dplyr)
library(dbplyr)
library(DBI)
library(stringr)
con <- DBI::dbConnect(RSQLite::SQLite(), path = ":memory:")
copy_to(con, mtcars, "mtcars", temporary = FALSE)
db <- tbl(con, "mtcars") %>%
select(carb) %>%
distinct(carb) %>%
arrange(carb) %>%
mutate(Q1=1, Q2=2, Q3=3, Q4=4) %>%
collect()
我对动态构建字符串 Q1=1, Q2=2, Q3=3, Q4=4
感兴趣,它可以是 Q1=1, Q2=2, ..., Qn = n
.
我的一个想法是构建这样的字符串:
n_par <- 4
str_c('Q', 1:n_par, ' = ', 1:n_par, collapse = ', ')
这样 n_par 可以是任何正数。但是,由于 dplyr 的非标准评估,我不能让它那样工作。然而,这正是我需要的。
有人可以帮忙吗?
这在你的数据库中有效吗?
library(tidyverse)
q_n <- function(n) {
str_c('Q', 1:n, ' = ', 1:n, collapse = ', ')
}
create_n_string <- function(data,n = 5,string = "Q"){
data %>%
mutate(new_col = str_flatten(1:n,collapse = "_")) %>%
separate(new_col,into = string %>% str_c(1:n),sep = "_")
}
mtcars %>%
select(carb) %>%
distinct(carb) %>%
arrange(carb) %>%
create_n_string()
#> carb Q1 Q2 Q3 Q4 Q5
#> 1 1 1 2 3 4 5
#> 2 2 1 2 3 4 5
#> 3 3 1 2 3 4 5
#> 4 4 1 2 3 4 5
#> 5 6 1 2 3 4 5
#> 6 8 1 2 3 4 5
由 reprex package (v0.3.0)
于 2020 年 1 月 22 日创建
生成和评估字符串
Q1 = 1, Q2 = 2, Q3 = 3, Q4 = 4
与 "Q1 = 1, Q2 = 2, Q3 = 3, Q4 = 4"
不是字符串的方式不同。有一些 R 函数会接受一个字符串对象并将其计算为代码。例如:
> eval(parse(text="print('hello world')"))
#> [1] "hello world"
不过,这在dbplyr
翻译里面可能不太好玩。如果您设法使这种方法起作用,那么最好将其作为答案发布。
使用循环
与其将其作为单个字符串执行,还不如使用循环:
db <- tbl(con, "mtcars") %>%
select(carb) %>%
distinct(carb) %>%
arrange(carb)
for(i in 1:n){
var = paste0("Q",i)
db <- db %>%
mutate(!!sym(var) := i)
}
db <- collect(db)
需要 !!sym()
来告诉 dplyr
您希望将文本参数视为变量。没有它,惰性求值会给你带来奇怪的结果。 :=
赋值是必需的,因为需要评估 LHS。
这种方法大致相当于每个变量的一个 mutate 语句(下面的示例),但 dbplyr
翻译可能看起来不如在单个 mutate 语句中完成所有操作那么优雅。
db <- tbl(con, "mtcars") %>%
select(carb) %>%
distinct(carb) %>%
arrange(carb) %>%
mutate(Q1 = 1) %>%
mutate(Q2 = 2) %>%
...
mutate(Qn = n) %>%
collect()
我最近阅读了有关该主题的更多信息,我发现以下代码工作得很好,使 dbplyr 编写了更清晰的 SQL 代码。
# Libraries
library(RSQLite)
library(dplyr)
library(dbplyr)
library(DBI)
# Example database
con <- DBI::dbConnect(RSQLite::SQLite(), path = ":memory:")
copy_to(con, mtcars, "mtcars", temporary = FALSE)
# Parameter for number of variables to be created
n <- 4
# Variable list
var <- list()
for(i in 1:n){
j <- paste0("Q", i)
var[[j]] <- i
}
# Query/computation
db <- tbl(con, "mtcars") %>%
select(carb) %>%
distinct(carb) %>%
arrange(carb) %>%
mutate(!!! var) %>%
show_query() %>%
collect()
诀窍是用专有名称构建一个列表,然后使用 !!!
将其放入 mutate()
函数中。此外,我读到应该避免解析和评估字符串,所以我切换到列表。
我之前问过类似的问题(
请考虑以下最小工作示例:
library(RSQLite)
library(dplyr)
library(dbplyr)
library(DBI)
library(stringr)
con <- DBI::dbConnect(RSQLite::SQLite(), path = ":memory:")
copy_to(con, mtcars, "mtcars", temporary = FALSE)
db <- tbl(con, "mtcars") %>%
select(carb) %>%
distinct(carb) %>%
arrange(carb) %>%
mutate(Q1=1, Q2=2, Q3=3, Q4=4) %>%
collect()
我对动态构建字符串 Q1=1, Q2=2, Q3=3, Q4=4
感兴趣,它可以是 Q1=1, Q2=2, ..., Qn = n
.
我的一个想法是构建这样的字符串:
n_par <- 4
str_c('Q', 1:n_par, ' = ', 1:n_par, collapse = ', ')
这样 n_par 可以是任何正数。但是,由于 dplyr 的非标准评估,我不能让它那样工作。然而,这正是我需要的。
有人可以帮忙吗?
这在你的数据库中有效吗?
library(tidyverse)
q_n <- function(n) {
str_c('Q', 1:n, ' = ', 1:n, collapse = ', ')
}
create_n_string <- function(data,n = 5,string = "Q"){
data %>%
mutate(new_col = str_flatten(1:n,collapse = "_")) %>%
separate(new_col,into = string %>% str_c(1:n),sep = "_")
}
mtcars %>%
select(carb) %>%
distinct(carb) %>%
arrange(carb) %>%
create_n_string()
#> carb Q1 Q2 Q3 Q4 Q5
#> 1 1 1 2 3 4 5
#> 2 2 1 2 3 4 5
#> 3 3 1 2 3 4 5
#> 4 4 1 2 3 4 5
#> 5 6 1 2 3 4 5
#> 6 8 1 2 3 4 5
由 reprex package (v0.3.0)
于 2020 年 1 月 22 日创建生成和评估字符串
Q1 = 1, Q2 = 2, Q3 = 3, Q4 = 4
与 "Q1 = 1, Q2 = 2, Q3 = 3, Q4 = 4"
不是字符串的方式不同。有一些 R 函数会接受一个字符串对象并将其计算为代码。例如:
> eval(parse(text="print('hello world')"))
#> [1] "hello world"
不过,这在dbplyr
翻译里面可能不太好玩。如果您设法使这种方法起作用,那么最好将其作为答案发布。
使用循环
与其将其作为单个字符串执行,还不如使用循环:
db <- tbl(con, "mtcars") %>%
select(carb) %>%
distinct(carb) %>%
arrange(carb)
for(i in 1:n){
var = paste0("Q",i)
db <- db %>%
mutate(!!sym(var) := i)
}
db <- collect(db)
需要 !!sym()
来告诉 dplyr
您希望将文本参数视为变量。没有它,惰性求值会给你带来奇怪的结果。 :=
赋值是必需的,因为需要评估 LHS。
这种方法大致相当于每个变量的一个 mutate 语句(下面的示例),但 dbplyr
翻译可能看起来不如在单个 mutate 语句中完成所有操作那么优雅。
db <- tbl(con, "mtcars") %>%
select(carb) %>%
distinct(carb) %>%
arrange(carb) %>%
mutate(Q1 = 1) %>%
mutate(Q2 = 2) %>%
...
mutate(Qn = n) %>%
collect()
我最近阅读了有关该主题的更多信息,我发现以下代码工作得很好,使 dbplyr 编写了更清晰的 SQL 代码。
# Libraries
library(RSQLite)
library(dplyr)
library(dbplyr)
library(DBI)
# Example database
con <- DBI::dbConnect(RSQLite::SQLite(), path = ":memory:")
copy_to(con, mtcars, "mtcars", temporary = FALSE)
# Parameter for number of variables to be created
n <- 4
# Variable list
var <- list()
for(i in 1:n){
j <- paste0("Q", i)
var[[j]] <- i
}
# Query/computation
db <- tbl(con, "mtcars") %>%
select(carb) %>%
distinct(carb) %>%
arrange(carb) %>%
mutate(!!! var) %>%
show_query() %>%
collect()
诀窍是用专有名称构建一个列表,然后使用 !!!
将其放入 mutate()
函数中。此外,我读到应该避免解析和评估字符串,所以我切换到列表。