pivot_longer: 基于列名作为输入的模式

pivot_longer: pattern based on column names as input

我有一个包含以下模式列的宽数据框:a1_var1a2_var1a3_var1a1_var2a2_var2a3_var2,等等。我想将其转向更长的时间,创建一个名为 a 的新变量,其中包含“a”后面的数字值(1、2、3)以及 [= 的所有值21=] 包含在列 var1 中(对于 var2 也是如此)。

考虑这个示例数据:

df <- data.frame(`id` = seq(1:3),
                 a1_var1 = c(111, 211, 311),
                 a2_var1 = c(121, 221, 321),
                 a3_var1 = c(131, 231, 331),
                 a1_var2 = c(112, 212, 312),
                 a2_var2 = c(122, 222, 322),
                 a3_var2 = c(132, 232, 332)) # first number is ID, second number is "a[x]" value, third number is var[x] 

我现在想将数据转换为具有以下列的长格式:id(每行不再唯一),a(包含从中获取变量的数字,例如 a1_var2a = 1),var1(包含来自 ax_var1 列的所有值,即 x11x21x31) 和 var2(包含来自 ax_var2 列的所有值,即 x12x22x32)。

我想实现如下结构:

id   a   var1 var2
1    1    111  112
1    2    121  122
1    3    131  132
2    1    211  212
2    2    221  222
2    3    231  232
3    1    311  312
3    2    321  322
3    3    331  332

到目前为止,我正在对每个 varx 进行硬编码,如下所示:

df %>% select(-c(ends_with("var2"))) %>% 
  pivot_longer(cols = c("a1_var1", "a2_var1", "a3_var1"), names_to = "a", values_to = "var1") %>% 
  mutate(a=str_extract(a, "a\d"),
         a=str_extract(a, "\d"))

但是由于我有很多 varx 列,这有点麻烦 - 有人可以指出实现上述结果的更好方法吗?

我们可以在 pivot_longer 本身中执行此操作 - 即指定 names_toc("a", ".value"),其中 'a' 将是列中前缀子字符串的列名reshapeed 和 .value 表示列值。在 names_pattern 中,捕获列名的子字符串,即 'a' 之后的数字 (\d+) 和 _

之后的第二个捕获组
library(dplyr)
library(tidyr)
df %>% 
  pivot_longer(cols = -id, names_to = c("a", ".value"), 
      names_pattern = "a(\d+)_(.*)")

-输出

# A tibble: 9 × 4
     id a      var1  var2
  <int> <chr> <dbl> <dbl>
1     1 1       111   112
2     1 2       121   122
3     1 3       131   132
4     2 1       211   212
5     2 2       221   222
6     2 3       231   232
7     3 1       311   312
8     3 2       321   322
9     3 3       331   332