R – dplyr – mutate – 使用dynamicvariables名称

我想使用dplyr的 mutate()在数据框中创build多个新列。 列名和它们的内容应该是dynamic生成的。

来自虹膜的示例数据:

 require(dplyr) data(iris) iris <- tbl_df(iris) 

我创build了一个函数来从Petal.Widthvariables中改变我的新列:

 multipetal <- function(df, n) { varname <- paste("petal", n , sep=".") df <- mutate(df, varname = Petal.Width * n) ## problem arises here df } 

现在我创build一个循环来build立我的列:

 for(i in 2:5) { iris <- multipetal(df=iris, n=i) } 

然而,由于mutate认为varname是一个文字variables名,循环只创build一个新variables(称为varname)而不是四个(称为petal.2 – petal.5)。

我怎样才能mutate()使用我的dynamic名称作为variables名?

由于您正在急剧地将variables名称构build为字符值,因此使用标准数据框架索引(允许列名的字符值)进行分配更有意义。 例如

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

mutate函数使得通过命名参数命名新列非常容易。 但是,假设您input命令时知道名称。 如果要dynamic指定列名称,则还需要构build命名参数。

最新版本的dplyr(0.7)通过使用:=来dynamic分配参数名称。 你可以写你的function

 # --- 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)鼓励使用“标准评估”替代许多function。 有关更多信息,请参阅非标准评估小插图( vignette("nse") )。

所以在这里,答案是使用mutate_()而不是mutate()和do

 # --- 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

请注意,在问题最初出现时存在的旧版本的dplyr中也可以这样做。 它需要谨慎使用quotesetName

 # --- 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 (2017年4月发布的0.6.0版本)中,我们也可以做一个赋值( := ),并通过不加引号( !! )来传递variables作为列名

  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) } 

根据应用于'iris1'上的@ MrFlick的multipetal检查输出结果

 identical(iris1, iris2) #[1] TRUE 

这是另一个版本,可以说更简单一些。

 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 

我也增加了一个答案,这增加了一点,因为我来到这个条目时,search一个答案,这几乎我所需要的,但我需要更多一点,我通过@MrFlik的答案和R lazyeval小插曲。

我想创build一个函数,它可以将一个数据框和一个列名称的向量(作为string),我想从一个string转换为一个Date对象。 我无法弄清楚如何使as.Date()采取一个string的参数,并将其转换为列,所以我做了如下所示。

下面是我通过SE mutate( mutate_() )和.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进行交互式使用,但是我发现使用dplyr来执行此操作非常棘手,因为您必须通过lazyeval :: interp(),setNames等方法来解决这个问题。

这是一个更简单的版本,使用base R,至less在我看来,它更直观,可以将循环放入函数中,并且扩展@ MrFlicks的解决scheme。

 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)