是否有使用交替模式重命名列的更简单版本?或者 tidyverse 方法?

Is there a simpler version of renaming columns with alternating patterns? Or tidyverse methods?

我的数据

所以我有一个正在使用的数据框:

structure(list(V1 = c(3L, 3L, 3L, 2L, 4L, 1L), V2 = c(1L, 1L, 
1L, 1L, 1L, 1L), V3 = c(2L, 2L, 2L, 1L, 3L, 2L), V4 = c(2L, 2L, 
3L, 1L, 1L, 1L), V5 = c(3L, 3L, 4L, 1L, 3L, 3L), V6 = c(3L, 3L, 
4L, 3L, 3L, 3L), V7 = c(2L, 2L, 1L, 1L, 3L, 3L), V8 = c(3L, 3L, 
4L, 4L, 3L, 3L), V9 = c(3L, 3L, 3L, 2L, 3L, 3L), V10 = c(2L, 
2L, 1L, 1L, 1L, 1L)), row.names = c(NA, 6L), class = "data.frame")

看起来像这样:

 V1 V2 V3 V4 V5 V6 V7 V8 V9 V10
1  3  1  2  2  3  3  2  3  3   2
2  3  1  2  2  3  3  2  3  3   2
3  3  1  2  3  4  4  1  4  3   1
4  2  1  1  1  1  3  1  4  2   1
5  4  1  3  1  3  3  3  3  3   1
6  1  1  2  1  3  3  3  3  3   1

目前的解决方案

我想出的用于快速重命名变量的最佳代码是:

new_names <- outer("cope",
                   1:10, 
                   paste, 
                   sep="_")
names(data1) <- new_names
data1

这给了我这个数据框:

  cope_1 cope_2 cope_3 cope_4 cope_5 cope_6 cope_7 cope_8 cope_9 cope_10
1      3      1      2      2      3      3      2      3      3       2
2      3      1      2      2      3      3      2      3      3       2
3      3      1      2      3      4      4      1      4      3       1
4      2      1      1      1      1      3      1      4      2       1
5      4      1      3      1      3      3      3      3      3       1
6      1      1      2      1      3      3      3      3      3       1

问题

虽然这足以满足我的目的,但它让我考虑了未来的两个问题。首先,有没有办法简化代码以使其成为一行?如果可能的话,我正在考虑在 dplyr 中工作的东西,因为这是我最习惯使用的东西。

其次,如果有 30 个变量,我预见到即将出现的问题,其中一些变量具有重复模式,而另一些变量是唯一的。像这样重命名变量时最经济的时间使用是什么?我知道 rep 是一种选择,但我只知道它如何重复而不是将值分成多个模式。我在想这样的事情,用某种模式和停止来写会更容易:

names <- c("v1","v2","v3","c1","c2","c3","u","p","z1","z2")

例如:

names <- c("v1","v2","v3","c1","c2","c3","u","p","z1","z2")
colnames(data1) <- names
data1

  v1 v2 v3 c1 c2 c3 u p z1 z2
1   3  1  2  2  3  3 2 3  3  2
2   3  1  2  2  3  3 2 3  3  2
3   3  1  2  3  4  4 1 4  3  1
4   2  1  1  1  1  3 1 4  2  1
5   4  1  3  1  3  3 3 3  3  1
6   1  1  2  1  3  3 3 3  3  1
7   3  1  3  1  3  2 2 2  3  2
8   3  2  1  2  3  2 3 3  2  1
9   3  2  4  1  2  4 2 3  4  1
10  4  2  4  2  3  4 3 3  4  1

手动拼写很费时间:

names <- c("cope_1", "cope_2","cope_3","sad_1","sad_2","sad_3","u","p","zip_1","zip_2")
colnames(data1) <- names
data1

哪个确实能让你得到你想要的,但速度很慢:

  cope_1 cope_2 cope_3 sad_1 sad_2 sad_3 u p zip_1 zip_2
1      3      1      2     2     3     3 2 3     3     2
2      3      1      2     2     3     3 2 3     3     2
3      3      1      2     3     4     4 1 4     3     1
4      2      1      1     1     1     3 1 4     2     1
5      4      1      3     1     3     3 3 3     3     1
6      1      1      2     1     3     3 3 3     3     1

outer 之类的东西似乎不适合这里:

outer("cope",
      1:3,
      paste,
      sep="_",
      "sad",
      1:3,
      paste,
      sep="_",
      "u",
      "p")

因此,如果有更好的方法来命名像​​这样的变量块,那将是一件很棒的事情。

一个解决方案可能是这样的:

library(dplyr)

df %>%
  setNames(paste0("cope_", seq_len(ncol(df))))

  cope_1 cope_2 cope_3 cope_4 cope_5 cope_6 cope_7 cope_8 cope_9 cope_10
1      3      1      2      2      3      3      2      3      3       2
2      3      1      2      2      3      3      2      3      3       2
3      3      1      2      3      4      4      1      4      3       1
4      2      1      1      1      1      3      1      4      2       1
5      4      1      3      1      3      3      3      3      3       1
6      1      1      2      1      3      3      3      3      3       1

如果你有一个包含名称的向量 x 和一个包含重复次数的向量 r,那么你可以这样做:

x <- c("v", "c", "u", "p", "z")
r <- c(3L, 3L, 1L, 1L, 3L)

f <- function(n) if (n > 1L) seq_len(n) else character(n)
paste0(rep(x, r), unlist(lapply(r, f)))
## [1] "v1" "v2" "v3" "c1" "c2" "c3" "u"  "p"  "z1" "z2" "z3"

如果你对"u1""p1"没问题,那么你可以简化一点:

paste0(rep(x, r), unlist(lapply(r, seq_len)))
## [1] "v1" "v2" "v3" "c1" "c2" "c3" "u1" "p1" "z1" "z2" "z3"

还有基数 R make.unique。它更识字,但笨拙地只有数字重复,所以它并不能完全满足你的需求:

make.unique(rep(x, r), sep = "")
## [1] "v"  "v1" "v2" "c"  "c1" "c2" "u"  "p"  "z"  "z1" "z2"

您可以在 dplyr -

中使用 rename_with
library(dplyr)

df %>% rename_with(~paste0('cope_', seq_along(.)))

#  cope_1 cope_2 cope_3 cope_4 cope_5 cope_6 cope_7 cope_8 cope_9 cope_10
#1      3      1      2      2      3      3      2      3      3       2
#2      3      1      2      2      3      3      2      3      3       2
#3      3      1      2      3      4      4      1      4      3       1
#4      2      1      1      1      1      3      1      4      2       1
#5      4      1      3      1      3      3      3      3      3       1
#6      1      1      2      1      3      3      3      3      3       1