簡體   English   中英

如何使用 dplyr 重命名具有數字列名的多個列?

[英]How to rename multiple columns that have numeric column names using dplyr?

設置

假設我有一個 dataframe,其中有幾列將實際數值作為列名而不是基於文本的列名。 例如,列名將是`2015`而不是"2015"

這是一個可重現的例子:

my_df = structure(list(Col1 = c('a', 'b', 'c'), 
                       Col2 = c('d', 'e', 'f'), 
                       `2015` = c('g','h','i'), 
                       `2016` = c('j','k','l'), 
                       `2017` = c('m','n','o'), 
                       `2018` = c('p','q','r'), 
                       `2019` = c('s','t','u'), 
                       `2020` = c('v','w','x'), 
                       `2021` = c('y','z','zz')), 
               row.names = c(NA, -3L), 
               class = c("tbl_df", "tbl", "data.frame"))

問題

進一步假設我想將所有數字列名稱重命名為更友好的名稱。 例如,從`2015`"XYZ_2015" (注意轉換為字符串)以及對列`2016``2017` 、... `2021`的類似轉換。

如何以使用 dplyr 的管道運算符 ( %>% ) 的方式執行此列重命名,而不需要我手動將它們全部寫出來?

我目前的解決方案

到目前為止,我的方法是“手動”執行此操作,分別重命名每一列:

new_df = my_df %>%
  rename(XYZ_2015 = `2015`,
         XYZ_2016 = `2016`,
         XYZ_2017 = `2017`,
         XYZ_2018 = `2018`,
         XYZ_2019 = `2019`,
         XYZ_2020 = `2020`,
         XYZ_2021 = `2021`)

但是,這種方法比較麻煩,而且容易出錯。 有沒有辦法讓我以更自動化的方式這樣做? 我覺得 for 循環可以在這里工作,但我無法弄清楚使 for 循環的變量與反引號配合得很好的語法。

例如,我試過這個:

for(year in 2015:2021){
  print(year)
  new_colname = paste0('XYZ_',year)
  my_df = my_df %>% rename(`new_colname` = `year`)
}

但這會產生一個錯誤:

Error in `stop_subscript()`:
! Can't rename columns that don't exist.
x Location 2015 doesn't exist.
i There are only 9 columns.
---
Backtrace:
  1. my_df %>% rename(new_colname = year)
  3. dplyr:::rename.data.frame(., new_colname = year)
  4. tidyselect::eval_rename(expr(c(...)), .data)
  5. tidyselect:::rename_impl(...)
  6. tidyselect:::eval_select_impl(...)
 15. tidyselect:::vars_select_eval(...)
 16. tidyselect:::loc_validate(pos, vars, call = error_call)
 17. vctrs::vec_as_location(pos, n = length(vars))
 18. vctrs `<fn>`()
 19. vctrs:::stop_subscript_oob(...)
 20. vctrs:::stop_subscript(...)

我們可以使用rename_withpastestr_c )帶有列名( .x )的前綴XYZ_僅適用於與從開始( ^ )到結束( $ )的 4 位( \\d{4} )列名matches的列名字符串的

library(dplyr)
library(stringr)
my_df %>%
   rename_with(~ str_c("XYZ_", .x), matches("^\\d{4}$"))

-輸出

# A tibble: 3 × 9
  Col1  Col2  XYZ_2015 XYZ_2016 XYZ_2017 XYZ_2018 XYZ_2019 XYZ_2020 XYZ_2021
  <chr> <chr> <chr>    <chr>    <chr>    <chr>    <chr>    <chr>    <chr>   
1 a     d     g        j        m        p        s        v        y       
2 b     e     h        k        n        q        t        w        z       
3 c     f     i        l        o        r        u        x        zz      

請注意, rename_with用法是

rename_with(.data, .fn, .cols = everything(), ...)

.cols指定為

.cols - <<tidy-select>> 要重命名的列; 默認為所有列。

這意味着我們可以使用任何tidy-select輔助函數( matches/starts_with/ends_with/everything() )等來選擇列


或者使用base R

names(my_df) <- sub("^X", "XYZ_", make.names(names(my_df)))

不是那么優雅和有點hacky的方式:

library(dplyr)
my_colnames <- paste("XYZ", colnames(my_df[-c(1:2)]))

my_df %>% 
  rename(!!!setNames(names(.[-c(1:2)]), my_colnames))
  Col1  Col2  `XYZ 2015` `XYZ 2016` `XYZ 2017` XYZ 2…¹ XYZ 2…² XYZ 2…³ XYZ 2…⁴
  <chr> <chr> <chr>      <chr>      <chr>      <chr>   <chr>   <chr>   <chr>  
1 a     d     g          j          m          p       s       v       y      
2 b     e     h          k          n          q       t       w       z      
3 c     f     i          l          o          r       u       x       zz     
# … with abbreviated variable names ¹​`XYZ 2018`, ²​`XYZ 2019`, ³​`XYZ 2020`,

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM