【问题标题】:Extract parts of column names for renaming提取部分列名进行重命名
【发布时间】:2021-12-28 14:08:27
【问题描述】:

我有一个数据框,其中一些列被命名为日期。例如,像这样:

df_1 <- data_frame("id" = c('a','b','c','d'),
                 "gender" = c('m','f','f','m'),
                 "05/16/2017" = c(1,2,3,4),
                 "11/08/2016" = c(1,2,3,4),
                 "08/15/2016" = c(1,2,3,4))

df_1
# A tibble: 4 x 5
  id    gender `05/16/2017` `11/08/2016` `08/15/2016`
  <chr> <chr>         <dbl>        <dbl>        <dbl>
1 a     m                 1            1            1
2 b     f                 2            2            2
3 c     f                 3            3            3
4 d     m                 4            4            4

对于当前为日期的列,格式为mm/dd/yyyy,我想提取mmyyyy 组件并使用它们将列重命名为election_yyyy_mm。 IE。我最终会得到如下所示的 df:

df_2 <- data_frame("id" = c('a','b','c','d'),
                 "gender" = c('m','f','f','m'),
                 "election_2017_05" = c(1,2,3,4),
                 "election_2016_11" = c(1,2,3,4),
                 "election_2016_08" = c(1,2,3,4))

df_2
# A tibble: 4 x 5
  id    gender election_2017_05 election_2016_11 election_2016_08
  <chr> <chr>             <dbl>            <dbl>            <dbl>
1 a     m                     1                1                1
2 b     f                     2                2                2
3 c     f                     3                3                3
4 d     m                     4                4                4

我想我有一个涉及stringr 的部分解决方案,但目前我必须运行str_extract 两次才能分别获得mmyyyy 组件。我也不确定如何将向量传递给rename()

这是我目前拥有的两个 sn-ps:

stringr::str_extract(c("05/16/2017", "11/08/2016", "08/15/2016"), "^[^/]+")
[1] "05" "11" "08"

stringr::str_extract(c("05/16/2017", "11/08/2016", "08/15/2016"), "[0-9]{4}")
[1] "2017" "2016" "2016"

谁能帮我a)在一次调用str_extract(或其他函数)中提取两个元素(yyyymm位),b)将结果向量传递给rename

【问题讨论】:

    标签: r date rename stringr


    【解决方案1】:

    我们可以使用rename_with 来重命名一个函数。 在重命名函数中,我们可以先用mdy()将字符解析为日期,然后提取month()year()。最后,glue() 将元素重新组合在一起。

    library(dplyr)
    library(glue)
    library(lubridate)
    
    df_1 %>% rename_with( ~glue('election_{year(mdy(.x))}_{month(mdy(.x))}'),
                          matches("\\d{2}/\\d{2}/\\d{4}"))
    
    

    输出

    # A tibble: 4 × 5
      id    gender election_2017_5 election_2016_11 election_2016_8
      <chr> <chr>            <dbl>            <dbl>           <dbl>
    1 a     m                    1                1               1
    2 b     f                    2                2               2
    3 c     f                    3                3               3
    4 d     m                    4                4               4
    

    我们也可以使用stringr::string_extract_all 来处理向量而不是单个字符元素。使用来自 OP 尝试的修改后的正则表达式,我们可以在一次调用中提取月份和年份。只需从字符串的开头 (^) 或结尾 ($) 中提取 (|) 数字 (\\d+):"^\\d+|\\d+$"

    答案是这样的:

    df_1 %>% rename_with( ~stringr::str_extract_all(.x, "^\\d+|\\d+$") %>%
                                  map_chr(~glue('election_{.x[2]}_{.x[1]}')),
                          matches("\\d{2}/\\d{2}/\\d{4}"))
    

    【讨论】:

      【解决方案2】:

      使用 tidyverse(dplyr 和 stringr),我们可以像这样重命名列:

      library(dplyr)
      
      df_1 %>% 
        rename_with(
          .cols = contains("/"), # selects only the date columns
          ~ paste0(
            "election_",  
            stringr::str_sub(.x, -4, -1), # last 4 digits/letters
            "_",
            stringr::str_sub(.x, 1, 2) # first 2 digits/letters
          )
        )
      

      结果:

      # A tibble: 4 x 5
        id    gender election_2017_05 election_2016_11 election_2016_08
        <chr> <chr>             <dbl>            <dbl>            <dbl>
      1 a     m                     1                1                1
      2 b     f                     2                2                2
      3 c     f                     3                3                3
      4 d     m                     4                4                4
      

      【讨论】:

        【解决方案3】:

        这是一个使用正则表达式的单行代码:

        names(df_1) <- sub("(\\d+).*?(\\d+)$", "election_\\2_\\1", names(df_1))
        

        这是如何工作的: 首先,将列名分为两个捕获组:

        • (\\d+):第一个抓包,抓到前两位
        • .*? 此后直到...
        • (\\d+)$: ...第二个捕获组,捕获最后一个数字。

        然后,使用sub 的替换参数,将字符串election_ 添加到匹配的名称中,并使用反向引用\\1\\2 以相反的顺序引用两个捕获组。

        使用stringr

        library(stringr)
        names(df_1) <- str_replace(names(df_1), "(\\d+).*?(\\d+)$", "election_\\2_\\1")
        

        结果:

        df_1 
        # A tibble: 4 × 5
          id    gender election_2017_05 election_2016_11 election_2016_08
          <chr> <chr>             <dbl>            <dbl>            <dbl>
        1 a     m                     1                1                1
        2 b     f                     2                2                2
        3 c     f                     3                3                3
        4 d     m                     4                4                4
        

        【讨论】:

          【解决方案4】:

          这是另一种方法:

          library(dplyr)
          library(stringr)
          df_1 %>% 
            rename_with(~str_c('election',str_sub(.x, -4,-1),str_sub(.x,-10,-9), sep = "_"), where(is.numeric))
          
            id    gender election_2017_05 election_2016_11 election_2016_08
            <chr> <chr>             <dbl>            <dbl>            <dbl>
          1 a     m                     1                1                1
          2 b     f                     2                2                2
          3 c     f                     3                3                3
          4 d     m                     4                4                4
          

          【讨论】:

            【解决方案5】:

            使用dplyr 但没有stringr 的另一种方法。

            这里使用rename_with 选择带有/ 的列,拆分/ 上的字符串并使用 sapply 将拆分的结果连接在一起作为可用于重命名的向量。

            
            df_1 %>%
                rename_with(.cols = contains('/'),
                ~ strsplit(.x, '/') %>% 
                sapply(
                  function(x) paste0('election_',x[3],'_',x[2]),
                  simplify=TRUE)
                )
            
            

            编辑删除 @GuedesBF 在 cmets 中解释的 as.character 调用。

            【讨论】:

            • 我认为我们可以从这个答案中删除“as.character”。默认情况下,'paste0' 已经强制转换为字符(并且这些元素已经是字符串)
            • 感谢@GuedesBF,不知道paste0,更新了我的答案以反映您的cmets。
            猜你喜欢
            • 1970-01-01
            • 2021-12-16
            • 2017-03-05
            • 2013-12-05
            • 1970-01-01
            • 2022-07-28
            • 2016-07-24
            • 2020-01-29
            • 2019-05-12
            相关资源
            最近更新 更多