【问题标题】:R: dplyr::mutate using an expression consisting of combination of variables passed as stringsR:dplyr::mutate 使用由作为字符串传递的变量组合组成的表达式
【发布时间】:2018-05-25 11:39:54
【问题描述】:

我想编写一个向数据框添加新变量的函数。该新变量由与参数中传递的一组变量(作为字符串向量)相对应的值的串联组成。在基础 R 中,我会写如下内容:

addConcatFields<-function(data,listOfVar)
{
data$uniqueId=data[,listOfVar[1]]
for(elt in listOfVar[2:length(listOfVar)])
{
data$uniqueId=paste(data$uniqueId,data[,elt],sep='_')
}
return(data)
}

addConcatFields(iris,c('Petal.Width','Species'))

# gives:
      Sepal.Length Sepal.Width Petal.Length Petal.Width Species   uniqueId
1          5.1         3.5          1.4         0.2  setosa 0.2_setosa
2          4.9         3.0          1.4         0.2  setosa 0.2_setosa
...

我最初的目标是使用 dplyr::mutate 来实现它,尽管我阅读了 http://127.0.0.1:31671/library/dplyr/doc/programming.html 的编程小插图,但我并没有达到我的目标。因为我想了解我错过的点,所以我想使用 mutate 解决问题,我会很感激建议。

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    解决这个问题的最好方法是使用准引用 - 这篇文章对解释基本原理很有帮助。

    https://dplyr.tidyverse.org/articles/programming.html

    最好的选择是将它们存储为带引号的字符串,而不是将列名存储为字符串,因此:

    varlist <- rlang::quos('Petal.Width', 'Species')
    

    该行为您提供了 2 个 quosures 的列表 - 一个包含 Petal.Width 列,一个包含 Species 列。

    然后你想使用 !!!将 quosures 列表附加到 dplyr 语句(!!!因为您要拼接多个指令)。

    dplyr::select(iris, !!! varlist)
    

    应该会给你想要的结果。

    【讨论】:

    • Thks 这是我第一次采取的方向,但我绝对想保留字符串作为输入
    【解决方案2】:

    使用数据表,我做这样的事情

    library(data.table)
    iris <- data.table(iris)
    
    iris[, uniqueId := do.call(function(...) paste(..., sep = "_"),.SD), .SDcols = c('Petal.Width','Species')]
    

    【讨论】:

      【解决方案3】:

      查看tidyrhere 中的unite 函数。它是tidyverse 的一部分,与dplyr 包含在同一组包中。

      library(tidyr)
      unite(iris,uniqueID,c(Petal.Width,Species))
      #    Sepal.Length Sepal.Width Petal.Length       uniqueID
      #1            5.1         3.5          1.4     0.2_setosa
      #2            4.9         3.0          1.4     0.2_setosa
      #3            4.7         3.2          1.3     0.2_setosa
      #4            4.6         3.1          1.5     0.2_setosa
      

      如果您不想丢失连接的两列,只需包含remove = F

      unite(iris,uniqueID,c(Petal.Width,Species),remove = F)
      #    Sepal.Length Sepal.Width Petal.Length       uniqueID Petal.Width    Species
      #1            5.1         3.5          1.4     0.2_setosa         0.2     setosa
      #2            4.9         3.0          1.4     0.2_setosa         0.2     setosa
      #3            4.7         3.2          1.3     0.2_setosa         0.2     setosa
      #4            4.6         3.1          1.5     0.2_setosa         0.2     setosa
      

      【讨论】:

        【解决方案4】:

        添加到其他答案,因为你说你想使用 dplyr 的mutate 来做。

        这是在mutate 中使用paste 的方法:

        iris %>% mutate(uniqueId= paste(Petal.Width, Species, sep = '_'))
        # gives the following result:
             Sepal.Length Sepal.Width Petal.Length Petal.Width Species uniqueId
         1          5.1         3.5          1.4         0.2 setosa  0.2_setosa
         2          4.9         3            1.4         0.2 setosa  0.2_setosa
         3          4.7         3.2          1.3         0.2 setosa  0.2_setosa
         4          4.6         3.1          1.5         0.2 setosa  0.2_setosa
         5          5           3.6          1.4         0.2 setosa  0.2_setosa
         6          5.4         3.9          1.7         0.4 setosa  0.4_setosa
         7          4.6         3.4          1.4         0.3 setosa  0.3_setosa
         8          5           3.4          1.5         0.2 setosa  0.2_setosa
         9          4.4         2.9          1.4         0.2 setosa  0.2_setosa
        10          4.9         3.1          1.5         0.1 setosa  0.1_setosa
        ...
        

        如果您的函数是自定义函数,您可以对其进行矢量化,然后使用它。 例如,这导致与上面相同的结果:

        concat_fields<-function(var1, var2) {
          return (paste(var1, var2, sep = '_'))
        }
        v_concat_fields <- Vectorize(concat_fields)
        iris %>% mutate(v_concat_fields(Petal.Width, Species))
        

        进入 mutate 的函数将应用于数据帧的列,它具有向量类型的参数,而不是数据帧。

        【讨论】:

        • 我的意思是,我想编写一个函数,使用字符串向量作为变量名称(如我的代码中所示)。
        • 说实话,不太清楚你想做什么。我编辑了我的答案,为自定义函数的情况提供了一个示例,但请不要犹豫,发表评论以澄清您想要实现的目标。
        【解决方案5】:

        好的,考虑到这里是另一种解决方案。

        使用 match 函数将字符串名称转换为列号。

        然后像这样使用列号(将示例中的数字向量替换为匹配的结果):

        df <- tbl_df(df[c(3, 4, 7, 1, 9, 8, 5, 2, 6, 10)])
        

        这还有一个好处是,如果 match 返回任何未找到的值,您可以通过错误中止函数。

        【讨论】:

          猜你喜欢
          • 2018-11-04
          • 2020-04-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多