在`dplyr'中使用动态变量名`
我想使用在`dplyr'中使用动态变量名`,r,dplyr,r-faq,R,Dplyr,R Faq,我想使用dplyr::mutate()在数据帧中创建多个新列。应动态生成列名及其内容 来自iris的示例数据: library(dplyr) iris <- as_tibble(iris) 现在,我创建一个循环来构建我的列: for(i in 2:5) { iris <- multipetal(df=iris, n=i) } for(2:5中的i){ iris由于您正在动态地将变量名构建为字符值,因此使用标准data.frame索引进行赋值更为合理,该索引允许列名的字符值
dplyr::mutate()
在数据帧中创建多个新列。应动态生成列名及其内容
来自iris的示例数据:
library(dplyr)
iris <- as_tibble(iris)
现在,我创建一个循环来构建我的列:
for(i in 2:5) {
iris <- multipetal(df=iris, n=i)
}
for(2:5中的i){
iris由于您正在动态地将变量名构建为字符值,因此使用标准data.frame索引进行赋值更为合理,该索引允许列名的字符值。例如:
multipetal <- function(df, n) {
varname <- paste("petal", n , sep=".")
df[[varname]] <- with(df, Petal.Width * n)
df
}
dplyr版本>=0.7
dplyr
从0.7版开始允许您使用:=
动态分配参数名称。您可以将函数编写为:
# --- dplyr version 0.7+---
multipetal <- function(df, n) {
varname <- paste("petal", n , sep=".")
mutate(df, !!varname := Petal.Width * n)
}
dplyr<0.3
注意:这在最初提出问题时存在的较旧版本的dplyr
中也是可能的。它需要仔细使用quote
和setName
:
# --- dplyr versions < 0.3 ---
multipetal <- function(df, n) {
varname <- paste("petal", n , sep=".")
pp <- c(quote(df), setNames(list(quote(Petal.Width * n)), varname))
do.call("mutate", pp)
}
#--dplyr版本<0.3---
多金属我还添加了一个答案,这个答案稍微增加了一点,因为我在搜索答案时找到了这个条目,这个条目几乎满足了我的需要,但我需要更多,这是通过@MrFlik的答案和R lazyeval vignettes获得的
我想做一个函数,它可以接受一个数据帧和一个列名向量(作为字符串),我想将其从字符串转换为日期对象。我不知道如何使成为.Date()
接受一个字符串参数并将其转换为列,所以我按照如下所示进行了操作
下面是我是如何通过SE mutate(mutate_389;()
)和.dots
参数来做到这一点的。欢迎对这一点提出批评
library(dplyr)
dat <- data.frame(a="leave alone",
dt="2015-08-03 00:00:00",
dt2="2015-01-20 00:00:00")
# This function takes a dataframe and list of column names
# that have strings that need to be
# converted to dates in the data frame
convertSelectDates <- function(df, dtnames=character(0)) {
for (col in dtnames) {
varval <- sprintf("as.Date(%s)", col)
df <- df %>% mutate_(.dots= setNames(list(varval), col))
}
return(df)
}
dat <- convertSelectDates(dat, c("dt", "dt2"))
dat %>% str
库(dplyr)
dat这是另一个版本,可以说更简单一些
multipetal <- function(df, n) {
varname <- paste("petal", n, sep=".")
df<-mutate_(df, .dots=setNames(paste0("Petal.Width*",n), varname))
df
}
for(i in 2:5) {
iris <- multipetal(df=iris, n=i)
}
> head(iris)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species petal.2 petal.3 petal.4 petal.5
1 5.1 3.5 1.4 0.2 setosa 0.4 0.6 0.8 1
2 4.9 3.0 1.4 0.2 setosa 0.4 0.6 0.8 1
3 4.7 3.2 1.3 0.2 setosa 0.4 0.6 0.8 1
4 4.6 3.1 1.5 0.2 setosa 0.4 0.6 0.8 1
5 5.0 3.6 1.4 0.2 setosa 0.4 0.6 0.8 1
6 5.4 3.9 1.7 0.4 setosa 0.8 1.2 1.6 2
multipetal虽然我喜欢使用dplyr进行交互,但我发现使用dplyr进行交互非常困难,因为要使用lazyeval::interp()、setNames等变通方法,您必须经历很多困难
这是一个使用base R的简单版本,在这个版本中,将循环放在函数中似乎更直观,至少对我来说是这样,它扩展了@MrFlicks的解决方案
multipetal <- function(df, n) {
for (i in 1:n){
varname <- paste("petal", i , sep=".")
df[[varname]] <- with(df, Petal.Width * i)
}
df
}
multipetal(iris, 3)
multimetal在新发布的dplyr
(0.6.0
将于2017年4月发布)中,我们还可以执行赋值(:=
)并通过取消引用(!!
)将变量作为列名传递,以避免对其求值
library(dplyr)
multipetalN <- function(df, n){
varname <- paste0("petal.", n)
df %>%
mutate(!!varname := Petal.Width * n)
}
data(iris)
iris1 <- tbl_df(iris)
iris2 <- tbl_df(iris)
for(i in 2:5) {
iris2 <- multipetalN(df=iris2, n=i)
}
经过大量的尝试和错误,我发现模式UQ(rlang::sym(“此处的某些字符串”))
对于处理字符串和dplyr动词非常有用。它似乎在很多令人惊讶的情况下都能工作
下面是一个使用mutate
的示例。我们希望创建一个将两列相加的函数,将两个列名作为字符串传递给函数。我们可以使用此模式,以及赋值运算符:=
,来完成此操作
## Take column `name1`, add it to column `name2`, and call the result `new_name`
mutate_values <- function(new_name, name1, name2){
mtcars %>%
mutate(UQ(rlang::sym(new_name)) := UQ(rlang::sym(name1)) + UQ(rlang::sym(name2)))
}
mutate_values('test', 'mpg', 'cyl')
或排列
:
## transform a variable and then sort by it
arrange_values <- function(name, transform){
mtcars %>%
arrange(UQ(rlang::sym(name)) %>% UQ(rlang::sym(transform)))
}
arrange_values('mpg', 'sin')
您可能会喜欢这个软件包,它为新用户/临时用户提供了简化的tidy eval API和文档
您正在创建希望变异为列名的字符串。因此,使用friendlyeval
可以编写:
multipetal <- function(df, n) {
varname <- paste("petal", n , sep=".")
df <- mutate(df, !!treat_string_as_col(varname) := Petal.Width * n)
df
}
for(i in 2:5) {
iris <- multipetal(df=iris, n=i)
}
multimetal我们有卷曲操作符({{}
),这使得这非常容易。当动态列名显示在赋值的左侧时,使用:=
library(dplyr)
library(rlang)
iris1 <- tbl_df(iris)
multipetal <- function(df, n) {
varname <- paste("petal", n , sep=".")
mutate(df, {{varname}} := Petal.Width * n)
}
multipetal(iris1, 4)
# A tibble: 150 x 6
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species petal.4
# <dbl> <dbl> <dbl> <dbl> <fct> <dbl>
# 1 5.1 3.5 1.4 0.2 setosa 0.8
# 2 4.9 3 1.4 0.2 setosa 0.8
# 3 4.7 3.2 1.3 0.2 setosa 0.8
# 4 4.6 3.1 1.5 0.2 setosa 0.8
# 5 5 3.6 1.4 0.2 setosa 0.8
# 6 5.4 3.9 1.7 0.4 setosa 1.6
# 7 4.6 3.4 1.4 0.3 setosa 1.2
# 8 5 3.4 1.5 0.2 setosa 0.8
# 9 4.4 2.9 1.4 0.2 setosa 0.8
#10 4.9 3.1 1.5 0.1 setosa 0.4
# … with 140 more rows
另一种选择是:在引号内使用{}
来轻松创建动态名称。这与其他解决方案类似,但并不完全相同,我发现这更容易
library(dplyr)
library(tibble)
iris <- as_tibble(iris)
multipetal <- function(df, n) {
df <- mutate(df, "petal.{n}" := Petal.Width * n) ## problem arises here
df
}
for(i in 2:5) {
iris <- multipetal(df=iris, n=i)
}
iris
库(dplyr)
图书馆(tibble)
iris谢谢你,这很有帮助。顺便说一句,我总是创建非常戏剧性的变量。呵呵。这可能是我最近最喜欢的打字错误之一。我想我会留下它。do.call()
可能没有你想象的那样做:。另请参阅dplyr开发版本中的nse小插曲。因此,如果我理解你的观点@hadley,我已经更新了上面的do.call
以使用do.call(“mutate”)
并在列表中引用df
。这就是你的建议吗?当lazyeval
版本的dplyr
是发布的版本时,然后mutate(df,.dots=setNames(list(~Petal.Width*n),varname))
会是一个更好的解决方案吗?如果我不仅需要在赋值的左侧,而且还需要在右侧使用变量列标题怎么办?例如mutate(df,!!newVar:=(!!var1+!!var2)/2)
不起作用:(我相信在vignette中甚至没有提到mutate\uu
,从其他函数中也看不出如何使用它。多年来,我一直在努力理解quosure
等文档。虽然上面的vignette链接不再有效,但这条评论让我得出了这个总结,以进行评估:。我最终我明白了!谢谢。dplyr
提供了这方面的内容。+1,虽然我在非交互式设置中仍然经常使用dplyr
,但在函数中与variabel输入一起使用它会使用非常笨拙的语法。您的提示非常有效,但我有一个小问题。我将初始列mycl
更改为url(例如),并用新名称复制数据帧df
末尾的旧列myclinicialvalue
发回MyClinicialValue的列。
我还没有写问题,因为我没有找到reprex。我的目标是DT::datatable()
的escape
参数。我使用escape=FALSE
等待它。对于常量,它也不起作用,但似乎也得到了坏列。:)我的问题似乎不是动态变量的原因。(顺便说一句,reprex补充道)谢谢你的回答!这里有一个超级简单的例子说明我是如何使用它的:varname=sym(“Petal.Width”);ggplot(iris,aes(x=!!varname))+geom_histogram()
这在公式中对我有效!
## filter a column by a value
filter_values <- function(name, value){
mtcars %>%
filter(UQ(rlang::sym(name)) != value)
}
filter_values('gear', 4)
## transform a variable and then sort by it
arrange_values <- function(name, transform){
mtcars %>%
arrange(UQ(rlang::sym(name)) %>% UQ(rlang::sym(transform)))
}
arrange_values('mpg', 'sin')
## select a column
select_name <- function(name){
mtcars %>%
select(!!name)
}
select_name('mpg')
multipetal <- function(df, n) {
varname <- paste("petal", n , sep=".")
df <- mutate(df, !!treat_string_as_col(varname) := Petal.Width * n)
df
}
for(i in 2:5) {
iris <- multipetal(df=iris, n=i)
}
library(dplyr)
library(rlang)
iris1 <- tbl_df(iris)
multipetal <- function(df, n) {
varname <- paste("petal", n , sep=".")
mutate(df, {{varname}} := Petal.Width * n)
}
multipetal(iris1, 4)
# A tibble: 150 x 6
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species petal.4
# <dbl> <dbl> <dbl> <dbl> <fct> <dbl>
# 1 5.1 3.5 1.4 0.2 setosa 0.8
# 2 4.9 3 1.4 0.2 setosa 0.8
# 3 4.7 3.2 1.3 0.2 setosa 0.8
# 4 4.6 3.1 1.5 0.2 setosa 0.8
# 5 5 3.6 1.4 0.2 setosa 0.8
# 6 5.4 3.9 1.7 0.4 setosa 1.6
# 7 4.6 3.4 1.4 0.3 setosa 1.2
# 8 5 3.4 1.5 0.2 setosa 0.8
# 9 4.4 2.9 1.4 0.2 setosa 0.8
#10 4.9 3.1 1.5 0.1 setosa 0.4
# … with 140 more rows
multipetal <- function(df, name, n) {
mutate(df, {{name}} := Petal.Width * n)
}
multipetal(iris1, temp, 3)
# A tibble: 150 x 6
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species temp
# <dbl> <dbl> <dbl> <dbl> <fct> <dbl>
# 1 5.1 3.5 1.4 0.2 setosa 0.6
# 2 4.9 3 1.4 0.2 setosa 0.6
# 3 4.7 3.2 1.3 0.2 setosa 0.6
# 4 4.6 3.1 1.5 0.2 setosa 0.6
# 5 5 3.6 1.4 0.2 setosa 0.6
# 6 5.4 3.9 1.7 0.4 setosa 1.2
# 7 4.6 3.4 1.4 0.3 setosa 0.900
# 8 5 3.4 1.5 0.2 setosa 0.6
# 9 4.4 2.9 1.4 0.2 setosa 0.6
#10 4.9 3.1 1.5 0.1 setosa 0.3
# … with 140 more rows
multipetal(iris1, "temp", 3)
library(dplyr)
library(tibble)
iris <- as_tibble(iris)
multipetal <- function(df, n) {
df <- mutate(df, "petal.{n}" := Petal.Width * n) ## problem arises here
df
}
for(i in 2:5) {
iris <- multipetal(df=iris, n=i)
}
iris