用 str_replace_all() 更改 data.frame() 中的几个列名称()

change several column names() in data.frame() with str_replace_all()

我读了这个 并练习了匹配模式,但我仍然没有弄明白。

我有一个具有相同尺寸的面板,每年数次。现在,我想以合乎逻辑的方式重命名它们。我的原始数据看起来有点像这样,

set.seed(667)
dta <- data.frame(id = 1:6,
                  R1213 =  runif(6), 
                  R1224 = runif(6, 1, 2),
                  R1255 = runif(6, 2, 3),
                  R1235 = runif(6, 3, 4))

# install.packages(c("tidyverse"), dependencies = TRUE)
require(tidyverse)
(tbl <- dta %>% as_tibble())
#> # A tibble: 6 x 5
#>      id R1213 R1224 R1255 R1235
#>   <int> <dbl> <dbl> <dbl> <dbl>
#> 1     1 0.488  1.60  2.07  3.07
#> 2     2 0.692  1.42  2.76  3.19
#> 3     3 0.262  1.34  2.33  3.82
#> 4     4 0.330  1.77  2.61  3.93
#> 5     5 0.582  1.92  2.15  3.86
#> 6     6 0.930  1.88  2.56  3.59    

现在,我使用str_replace_all()重命名它们,这里我使用pate的地方只有一个变量,一切都很好(也可以通过其他方式优化它,如果可以,请感觉让我知道),

names(tbl) <- tbl %>% names() %>% 
               str_replace_all('^R1.[125].$', 'A') %>% 
               str_replace_all('^R1.[3].$', paste0('A.2018.', 1))
tbl
#> # A tibble: 6 x 5
#>      id     A     A     A A.2018.1
#>   <int> <dbl> <dbl> <dbl>    <dbl>
#> 1     1 0.488  1.60  2.07     3.07
#> 2     2 0.692  1.42  2.76     3.19
#> 3     3 0.262  1.34  2.33     3.82
#> 4     4 0.330  1.77  2.61     3.93
#> 5     5 0.582  1.92  2.15     3.86
#> 6     6 0.930  1.88  2.56     3.59

Eveything call A实际上是同一年,假设是2017年,但后缀.1.2等需要附加。我一遍又一遍地使用 paste0('A.2017.', 1:3),但这次有三个就足够了,

tbl <- dta %>% as_tibble()
names(tbl) <- tbl %>% names() %>% 
               str_replace_all('^R1.[125].$', paste0('A.2017.', 1:3)) %>% 
               str_replace_all('^R1.[7].$', paste0('A.2018.', 1))
tbl
#> Warning message:
#> In stri_replace_all_regex(string, pattern, fix_replacement(replacement),  :
#>   longer object length is not a multiple of shorter object length
#> > tbl
#> # A tibble: 6 x 5
#>      id A.2017.2 A.2017.3 A.2017.1 R1235
#>   <int>    <dbl>    <dbl>    <dbl> <dbl>
#> 1     1    0.488     1.60     2.07  3.07
#> 2     2    0.692     1.42     2.76  3.19
#> 3     3    0.262     1.34     2.33  3.82
#> 4     4    0.330     1.77     2.61  3.93
#> 5     5    0.582     1.92     2.15  3.86
#> 6     6    0.930     1.88     2.56  3.59

这确实出来了,但是顺序颠倒了,我被告知 longer object length is not a multiple of shorter object length,但是 3 长度不对吗?我希望以一种更清洁、更简单的方式来做到这一点。另外,我不太喜欢names(tbl) <-,如果能以更优雅的方式做到这一点的话。

根据 David 的建议 - 使用 dplyr::rename_at 的类似下面的内容怎么样?

library(dplyr)

## Get data
set.seed(667)
dta <- data.frame(id = 1:6,
                  R1213 =  runif(6), 
                  R1224 = runif(6, 1, 2),
                  R1255 = runif(6, 2, 3),
                  R1235 = runif(6, 3, 4)) %>% 
  as_tibble()


## Rename
dta <- dta %>% 
  rename_at(.vars = grep('^R1.[125].$', names(.)), 
            .funs = ~paste0("A.2017.", 1:length(.)))

dta            
#> # A tibble: 6 x 5
#>      id A.2017.1 A.2017.2 A.2017.3 R1235
#>   <int>    <dbl>    <dbl>    <dbl> <dbl>
#> 1     1    0.196     1.74     2.51  3.49
#> 2     2    0.478     1.85     2.06  3.69
#> 3     3    0.780     1.32     2.21  3.26
#> 4     4    0.705     1.49     2.49  3.33
#> 5     5    0.942     1.59     2.66  3.58
#> 6     6    0.906     1.90     2.87  3.93

多种模式的矢量化解决方案

对于可用于多种模式和替换的完整解决方案,我们可以使用 purr::map2_dfc 如下。

library(dplyr)
library(purrr)

## Get data
set.seed(667)
dta <- data.frame(id = 1:6,
                  R1213 =  runif(6), 
                  R1224 = runif(6, 1, 2),
                  R1255 = runif(6, 2, 3),
                  R1235 = runif(6, 3, 4)) %>% 
  as_tibble()

## Define a function to keep a hold out data set, then rename iteratively for each pattern and replacement.
rename_multiple_years <- function(df, patterns, 
                                  replacements,
                                  hold_out_var = "id") {

  hold_out_df <- df %>% 
    select_at(.vars = hold_out_var)

  rename_df <- map2_dfc(patterns, replacements, function(pattern, replacement) {
    df %>% 
      rename_at(.vars = grep(pattern, names(.)), 
                .funs = ~paste0(replacement, 1:length(.))) %>% 
      select_at(.vars = grep(replacement, names(.)))
  })

  final_df <- bind_cols(hold_out_df, rename_df)

  return(final_df)
}

## Call function on specified patterns and replacements
renamed_dta <- dta %>% 
  rename_multiple_years(patterns = c("^R1.[125].$", "^R1.[3].$"),
                        replacements = c("A.2017.", "A.2018."))
renamed_dta
#> # A tibble: 6 x 5
#>      id A.2017.1 A.2017.2 A.2017.3 A.2018.1
#>   <int>    <dbl>    <dbl>    <dbl>    <dbl>
#> 1     1    0.196     1.74     2.51     3.49
#> 2     2    0.478     1.85     2.06     3.69
#> 3     3    0.780     1.32     2.21     3.26
#> 4     4    0.705     1.49     2.49     3.33
#> 5     5    0.942     1.59     2.66     3.58
#> 6     6    0.906     1.90     2.87     3.93

走向整洁的数据

现在变量已重命名,您可能会发现以整洁的格式整理数据很有用。以下使用 tidyr::gather 可能会有用。

library(tidyr)
library(dplyr)

#Use tidy dataframe gather all variables, split by "." and drop A column (or keep if a measurement id)
renamed_dta %>% 
  gather(key = "measure", value = "value", -id) %>% 
  separate(measure, c("A", "year", "measure"), "[[.]]") %>% 
  select(-A)
#> # A tibble: 24 x 4
#>       id year  measure value
#>    <int> <chr> <chr>   <dbl>
#>  1     1 2017  1       0.196
#>  2     2 2017  1       0.478
#>  3     3 2017  1       0.780
#>  4     4 2017  1       0.705
#>  5     5 2017  1       0.942
#>  6     6 2017  1       0.906
#>  7     1 2017  2       1.74 
#>  8     2 2017  2       1.85 
#>  9     3 2017  2       1.32 
#> 10     4 2017  2       1.49 
#> # ... with 14 more rows