小编典典

在`dplyr`中为新列/变量使用动态名称

all

我想用来dplyr::mutate()在数据框中创建多个新列。列名及其内容应该是动态生成的。

来自 iris 的示例数据:

library(dplyr)
iris <- as_tibble(iris)

我创建了一个函数来改变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()使用我的动态名称作为变量名?


阅读 136

收藏
2022-05-29

共1个答案

小编典典

由于您将变量名称动态构建为字符值,因此使用标准 data.frame 索引进行分配更有意义,该索引允许列名的字符值。例如:

multipetal <- function(df, n) {
    varname <- paste("petal", n , sep=".")
    df[[varname]] <- with(df, Petal.Width * n)
    df
}

mutate函数使通过命名参数命名新列变得非常容易。但这假设您在键入命令时知道名称。如果要动态指定列名,则还需要构建命名参数。


dplyr 版本 >= 1.0

使用最新的 dplyr 版本,您可以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从 0.7 版开始,您可以使用:=动态分配参数名称。您可以将函数编写为:

# --- dplyr version 0.7+---
multipetal <- function(df, n) {
    varname <- paste("petal", n , sep=".")
    mutate(df, !!varname := Petal.Width * n)
}

有关详细信息,请参阅可用的文档表格vignette("programming", "dplyr")


dplyr (>=0.3 & <0.7)

(>=0.3 <0.7)的稍早版本dplyr,鼓励使用“标准评估”替代许多功能。有关更多信息,请参阅非标准评估小插图 (
vignette("nse"))。

所以在这里,答案是使用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 < 0.3

dplyr请注意,这在最初提出问题时存在的旧版本中也是可能的。它需要仔细使用quoteand 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)
}
2022-05-29