【问题标题】:How to rename selected columns using dplyr with new column names as strings如何使用 dplyr 重命名选定的列,并将新列名作为字符串
【发布时间】:2023-03-10 14:00:01
【问题描述】:

我有以下小标题:

library(tidyverse)
df <- structure(list(Sepal.Length = c(5.1, 4.9, 4.7, 4.6, 5), Sepal.Width = c(3.5, 
3, 3.2, 3.1, 3.6), Petal.Length = c(1.4, 1.4, 1.3, 1.5, 1.4)), .Names = c("Sepal.Length", 
"Sepal.Width", "Petal.Length"), row.names = c(NA, 5L), class = c("tbl_df", 
"tbl", "data.frame"))

看起来像这样:

> df
# A tibble: 5 × 3
  Sepal.Length Sepal.Width Petal.Length
*        <dbl>       <dbl>        <dbl>
1          5.1         3.5          1.4
2          4.9         3.0          1.4
3          4.7         3.2          1.3
4          4.6         3.1          1.5
5          5.0         3.6          1.4

我想要做的是将Sepal.LengthPetal.Length 替换为附加字符串to_app &lt;- ".xxx",结果是:

  Sepal.Length.xxx Sepal.Width Petal.Length.xxx
          5.1         3.5          1.4
          4.9         3.0          1.4
          4.7         3.2          1.3
          4.6         3.1          1.5
          5.0         3.6          1.4

我尝试了这个错误:

>df %>% rename(paste(Sepal.Length,to_app,sep="") = Petal.Length,paste(Sepal.Width,to_app,sep="") = Petal.Length)
Error: unexpected '=' in "df %>% rename(paste(Sepal.Length,to_app,sep="") ="

【问题讨论】:

  • 使用 match - vars &lt;- c("Sepal.Length", "Sepal.Width"); names(df)[match(vars, names(df))] &lt;- paste0(vars, to_app) 的另一种 R 构造

标签: r dplyr


【解决方案1】:

您可以为此使用rename_at() 函数(从dplyr_0.7.0 开始)或rename_with()(从dplyr_1.0.0 开始)。

例如,您可以将要重命名的变量作为字符串传递。在您的示例中,paste0 函数可用于将适当的后缀附加到每列。

cols = c("Sepal.Length", "Petal.Length")
to_app = ".xxx"

对于 dplyr_1.0.0,请使用 rename_with()。函数参数位于列参数之前。您可以使用 tidy-select 函数all_of()(或其他)来选择列。

rename_with(df, .fn = ~paste0(., to_app), .cols = all_of(cols) )

# A tibble: 5 x 3
  Sepal.Length.xxx Sepal.Width Petal.Length.xxx
*            <dbl>       <dbl>            <dbl>
1              5.1         3.5              1.4
2              4.9         3                1.4
3              4.7         3.2              1.3
4              4.6         3.1              1.5
5              5           3.6              1.4

dplyr 的早期版本使用rename_at()。这已在 1.0.0 版本中被取代,这意味着可以使用上述新功能,但此特定功能不会消失。

rename_at(df, cols, list( ~paste0(., to_app) ) )

# A tibble: 5 x 3
  Sepal.Length.xxx Sepal.Width Petal.Length.xxx
*            <dbl>       <dbl>            <dbl>
1              5.1         3.5              1.4
2              4.9         3.0              1.4
3              4.7         3.2              1.3
4              4.6         3.1              1.5
5              5.0         3.6              1.4

您还可以使用 select 辅助函数来选择要重命名的变量,例如contains

rename_at(df, vars( contains("Length") ), list( ~paste0(., ".xxx") ) )

# A tibble: 5 x 3
  Sepal.Length.xxx Sepal.Width Petal.Length.xxx
*            <dbl>       <dbl>            <dbl>
1              5.1         3.5              1.4
2              4.9         3.0              1.4
3              4.7         3.2              1.3
4              4.6         3.1              1.5
5              5.0         3.6              1.4

这个list() 编码替换了从dplyr_0.7.0 开始的之前的funs() 编码。以前,例如,funs( paste0(., to_app) )

【讨论】:

  • 刚刚更新 dplyr 0.8, rename_at(df, cols, list(~paste0(., to_app) ) )
  • dplyr 1.0.0(并使用 stringr::str_c),rename_with(.data = df, .fn = ~ str_c(., to_app), .cols = contains("Length") )。其他 rename_x 函数已被取代。
【解决方案2】:

编辑:这些天来,我建议使用dplyr::rename_with,就像@aosmith's answer 一样。编写一个函数,将您的旧列名作为输入并返回您的新列名作为输出,您就完成了:)

我在这方面有点迟到了,但是在盯着programming vignette很久之后,我在Different input and output variable 中找到了相关的例子。

在我更简单的用例中,我只需要将列重命名为字符串的值:

> df1 = data_frame(index = 1:5, value = c(10, 20, 30, 40, 50))
> df1
# A tibble: 5 x 2
  index value
  <int> <dbl>
1     1    10
2     2    20
3     3    30
4     4    40
5     5    50

> newname = 'blau'
> newname2 = 'wheee'

> df1 %>% rename(!!newname := value, !!newname2 := index)
# A tibble: 5 x 2
  wheee  blau
  <int> <dbl>
1     1    10
2     2    20
3     3    30
4     4    40
5     5    50

因此,如果您愿意手动执行此操作,您可以:

df %>%
  rename(!!paste("Sepal.Length", "xxx", sep = ".") := Sepal.Length)

但是,如果您需要自动将".xxx" 附加到提供给它的任何列名,我建议您仔细查看该部分。不幸的是,这仍然有点超出我的想象,但我可以看到它是可行的>_>

【讨论】:

    【解决方案3】:

    如果你想使用 dplyr 的 rename 函数,最好创建一个命名向量/列表,并在标准评估版本中使用 .dots 参数调用它:

    cols <- c("Sepal.Length", "Petal.Length")
    to_app <- ".xxx"
    cols <- setNames(cols, paste0(cols, to_app))
    
    df %>% rename_(.dots = cols)
    
    ## A tibble: 5 × 3
    #  Sepal.Length.xxx Sepal.Width Petal.Length.xxx
    #*            <dbl>       <dbl>            <dbl>
    #1              5.1         3.5              1.4
    #2              4.9         3.0              1.4
    #3              4.7         3.2              1.3
    #4              4.6         3.1              1.5
    #5              5.0         3.6              1.4
    

    但是请注意,这种方法可能会随着 dplyr 的下一个版本 0.6.0 发生变化(参见例如 http://blog.rstudio.org/2017/04/13/dplyr-0-6-0-coming-soon/http://dplyr.tidyverse.org/articles/programming.html)。

    【讨论】:

      【解决方案4】:
      df %>% setNames(paste0(names(.), to.app))
      
      # A tibble: 5 × 3
        Sepal.Length.xxx Sepal.Width.xxx Petal.Length.xxx
      *            <dbl>           <dbl>            <dbl>
      1              5.1             3.5              1.4
      2              4.9             3.0              1.4
      3              4.7             3.2              1.3
      4              4.6             3.1              1.5
      5              5.0             3.6              1.4
      

      编辑:

      抱歉没有正确阅读。这是一个带有 data.table 包的解决方案。

      var <- names(df)[c(1,3)]
      df %>% setnames(., var, paste0(var, to.app))
      df
      
      # A tibble: 5 × 3
        Sepal.Length.xxx Sepal.Width Petal.Length.xxx
      *            <dbl>       <dbl>            <dbl>
      1              5.1         3.5              1.4
      2              4.9         3.0              1.4
      3              4.7         3.2              1.3
      4              4.6         3.1              1.5
      5              5.0         3.6              1.4
      

      【讨论】:

      • 我不想要所有列,但选定的列(Sepal.Length 和 Petal.Length)请再次查看我的 OP。
      【解决方案5】:

      假设目标是重命名所有包含“长度”的列:

      colnames(df) <- ifelse(grepl("Length", colnames(df)), 
                             paste0(colnames(df), to_app), 
                             colnames(df))
      

      【讨论】:

        【解决方案6】:

        我能在dplyr的开发版中做到最好(5月11日发布):

        cols <- c("Sepal.Length", "Petal.Length")
        to_app <- ".xxx"
        ns <- paste0(cols, to_app)
        
        rename(df, 
               !!ns[1] := !!as.name(cols[1]), 
               !!ns[2] := !!as.name(cols[2]))
        

        要完全以编程方式执行此操作,需要改用quos

        xx <- do.call(quos, setNames(map(cols, as.name), ns))
        rename(df, !!!xx)
        

        两者都给出:

        # A tibble: 5 × 3
          Sepal.Length.xxx Sepal.Width Petal.Length.xxx
        *            <dbl>       <dbl>            <dbl>
        1              5.1         3.5              1.4
        2              4.9         3.0              1.4
        3              4.7         3.2              1.3
        4              4.6         3.1              1.5
        5              5.0         3.6              1.4
        

        一个班轮:

        rename(df, !!!do.call(quos, setNames(map(cols, as.name), paste0(cols, to_app))))
        

        【讨论】:

        • 那么问题是,如果不单独调用每一列,如何做到这一点?我认为这可能是!!! 而不是!!
        • 是的,我已经为此添加了 a 解决方案,但不确定是否有办法避免出现do.call 和/或setNames
        • 很高兴看到这个例子,但我希望这不会是自 imho 以来的最终版本,对于一个相当简单的列重命名来说太复杂了
        • 我同意!有些事情变得更好了,但我看不到使用tidyeval/rlang 的便捷方法。不过我不会说这很可怕。也许@hadley 可以告诉我们他对此的看法。
        • [tongue-in-cheek] 并认为 Hadley 曾经认为在 data.table 中需要学习 "cryptic shorcuts"... 更不用说 := 看起来有点熟悉一些神秘的包裹,我不记得它的名字了....
        猜你喜欢
        • 2014-12-15
        • 2015-03-08
        • 1970-01-01
        • 2021-10-30
        • 1970-01-01
        • 1970-01-01
        • 2023-01-10
        • 2017-09-26
        • 2020-09-19
        相关资源
        最近更新 更多