当前位置: 首页 > 知识库问答 >
问题:

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

鲜于宏义
2023-03-14

我想使用<code>dplyr::mutate()</code>在数据帧中创建多个新列。应动态生成列名及其内容。

来自iris的示例数据:

library(dplyr)
iris <- as_tibble(iris)

我创建了一个函数,可以从<code>Petal中修改我的新列。宽度变量:

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

如何让< code>mutate()使用我的动态名作为变量名?

共有3个答案

白越
2023-03-14

经过大量的尝试和错误,我发现模式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')

该模式也适用于其他<code>dplyr</code>函数。这里有一个<code>过滤器</code>:

## filter a column by a value 
filter_values <- function(name, value){
  mtcars %>% 
    filter(UQ(rlang::sym(name)) != value)
}
filter_values('gear', 4)

或< code >排列:

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

钮誉
2023-03-14

在< code > dplyr (2017年4月发布的< code>0.6.0)的新版本中,我们还可以进行赋值(< code>:=),并通过取消引用(< code >!!)不评估它

 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的多金属检查输出

identical(iris1, iris2)
#[1] TRUE
丁经国
2023-03-14

由于您将变量名动态构建为字符值,因此使用标准数据进行赋值更有意义。框架索引,允许列名的字符值。例如:

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

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

在最新的dplyr版本中,当使用< code>:=命名参数时,可以使用< code>glue包中的语法。因此,这里名称中的< code>{}通过计算内部的表达式来获取值。

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)

从0.7版开始的dplyr允许您使用:=动态分配参数名称。您可以将您的函数编写为:

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

有关详细信息,请参阅可用的表单小插图(“编程”,“dplyr”)的文档

稍早版本的< code>dplyr(

因此,这里的答案是使用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中也是可能的。它需要仔细使用引号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)
}
 类似资料:
  • 我想使用在数据帧中创建多个新列。列名及其内容应动态生成。 来自IRIS的示例数据: 我创建了一个函数来从变量中更改新列:

  • 我想在使用dplyr时动态创建变量名;不过,我也可以使用非DPLYR解决方案。 例如:

  • 问题内容: 在PHP中,您可以执行以下令人惊奇/可怕的事情: 有没有办法用Java做类似的事情? 例如,如果我有一个名称,可以得到对变量的引用吗? 问题答案: 由于ECMA-/ JavaScript是所有关于和(其也somekind的对象的),每个变量被存储在这样的被称为 可变 (或在功能方面,的情况下, 激活对象 )。 因此,如果您创建这样的变量: 在 全局范围 (= NO函数上下文)中,您将这

  • 我尝试在mutate_()函数(dplyr)中用paste()创建一个变量。 我试图用这个答案修改代码(dplyr-mutate:使用动态变量名),但它不起作用... 注意:nameVarPeriod1是函数的参数。

  • 我想在一个数据帧中创建几个新的空变量,并在向量中指定变量名。如果我只指定了一个变量名,这是可行的,但如果指定了几个,就不行了。我尝试了一些以前的解决方案,但它们似乎在这种情况下不起作用,例如: < li >不硬编码变量名的dplyr > < li >传递带有要变异的名称的向量以创建多个新列 < li>dplyr - mutate:使用动态变量名 期望的输出将是: 我想知道我如何能使这个工作?