我想用来dplyr::mutate()在数据框中创建多个新列。列名及其内容应该是动态生成的。
dplyr::mutate()
来自 iris 的示例数据:
library(dplyr) iris <- as_tibble(iris)
我创建了一个函数来改变Petal.Width变量中的新列:
Petal.Width
multipetal <- function(df, n) { varname <- paste("petal", n , sep=".") df <- mutate(df, varname = Petal.Width * n) ## problem arises here df }
现在我创建一个循环来构建我的列:
for(i in 2:5) { iris <- multipetal(df=iris, n=i) }
然而,由于 mutate 认为 varname 是一个字面变量名,因此循环只创建一个新变量(称为 varname)而不是四个(称为petal.2 -petal.5)。
我怎样才能mutate()使用我的动态名称作为变量名?
mutate()
由于您将变量名称动态构建为字符值,因此使用标准 data.frame 索引进行分配更有意义,该索引允许列名的字符值。例如:
multipetal <- function(df, n) { varname <- paste("petal", n , sep=".") df[[varname]] <- with(df, Petal.Width * n) df }
该mutate函数使通过命名参数命名新列变得非常容易。但这假设您在键入命令时知道名称。如果要动态指定列名,则还需要构建命名参数。
mutate
使用最新的 dplyr 版本,您可以glue在使用:=. 所以这里的{}名字通过评估里面的表达式来获取值。
glue
:=
{}
multipetal <- function(df, n) { mutate(df, "petal.{n}" := Petal.Width * n) }
如果要将列名传递给函数,则可以{{}}在字符串中使用,也可以在列名中使用
{{}}
meanofcol <- function(df, col) { mutate(df, "Mean of {{col}}" := mean({{col}})) } meanofcol(iris, Petal.Width)
dplyr从 0.7 版开始,您可以使用:=动态分配参数名称。您可以将函数编写为:
dplyr
# --- dplyr version 0.7+--- multipetal <- function(df, n) { varname <- paste("petal", n , sep=".") mutate(df, !!varname := Petal.Width * n) }
有关详细信息,请参阅可用的文档表格vignette("programming", "dplyr")。
vignette("programming", "dplyr")
(>=0.3 <0.7)的稍早版本dplyr,鼓励使用“标准评估”替代许多功能。有关更多信息,请参阅非标准评估小插图 ( vignette("nse"))。
vignette("nse")
所以在这里,答案是使用mutate_()而不是mutate()做:
mutate_()
# --- dplyr version 0.3-0.5--- multipetal <- function(df, n) { varname <- paste("petal", n , sep=".") varval <- lazyeval::interp(~Petal.Width * n, n=n) mutate_(df, .dots= setNames(list(varval), varname)) }
dplyr请注意,这在最初提出问题时存在的旧版本中也是可能的。它需要仔细使用quoteand setName:
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) }