pivot_longer() 处理多组列

编程语言 2026-07-12

我找了一些资料,但还是没搞清楚我这特定情况的语法。

我需要按下面这样的方式对数据进行分组:

library(tibble)

data_example <- tribble(
~drug_name, ~ecoli_median_molar, ~saureus_median_molar, ~ecoli_mad_molar, ~saureus_mad_molar,
"drug1", 1, 2, 0.5, 0.25,
"drug2", 4, 8, 2, 1
)

变成这样:

data_example_longer <- tribble(
~drug_name, ~pathogen, ~median, ~mad,
"drug1", "ecoli", 1, 0.5,
"drug1", "saureus", 2, 0.25,
"drug2", "ecoli", 4, 2, 
"drug2", "saureus", 8, 1
)

我知道这是一种正则表达式的模式,但找不到解释语法以及如何告诉R 哪些列该放在哪里的答案。我的实际数据中病原体更多,但遵循与上面相同的模式。

解决方案

你需要的正则模式需要两个捕获组 ():一个用于病原体列名,另一个用于median|mad值:

library(tidyr)

data_example |>
  pivot_longer(
    cols = -drug_name,
    names_to = c("pathogen", ".value"),
    names_pattern = "^(pathogen\\d+)_(median|mad)_molar"
  )
# A tibble: 4 × 4
#   drug_name pathogen  median   mad
#   <chr>     <chr>      <dbl> <dbl>
# 1 drug1     pathogen1      1  0.5 
# 2 drug1     pathogen2      2  0.25
# 3 drug2     pathogen1      4  2   
# 4 drug2     pathogen2      8  1

正则表达式的工作原理大致如下:

  • 从列名字符串的起始处 ^
  • (pathogen\\d+) 仅在后跟一个或多个数字 \\d+ 时,捕获字面量字符串 "pathogen"
  • _(median|mad)_molar 捕获任何在字面量 "_" 与 "_molar" 之间、且值为字面量 "median" 或 "mad" 的列

names_to = 参数中的元素,按顺序对应每个捕获组。".value" 允许你对第二个捕获组中找到的每个唯一字符串创建一个透视列。在你的情况下,与包含 "median" 或 "mad" 的列名相关的值将拥有自己的列。

基于你的评论,下面是当病原体名称变化时的一个解决方案:

data_example <- tribble(
  ~drug_name, ~ecoli_median_molar, ~saureus_median_molar, ~ecoli_mad_molar, ~saureus_mad_molar,
  "drug1", 1, 2, 0.5, 0.25,
  "drug2", 4, 8, 2, 1
)

data_example |>
  pivot_longer(
    cols = -drug_name,
    names_to = c("pathogen", ".value"),
    names_pattern = "^([^_]+)_(median|mad)_molar"
  )

# # A tibble: 4 × 4
#   drug_name pathogen median   mad
#   <chr>     <chr>     <dbl> <dbl>
# 1 drug1     ecoli         1  0.5
# 2 drug1     saureus       2  0.25
# 3 drug2     ecoli         4  2
# 4 drug2     saureus       8  1

唯一的差别在于第一捕获组的定义方式:

  • 从列名字符串的开头 ^
  • ([^_]+) 捕获一个或多个字符 +,这些字符不是下划线 [^_]

其余逻辑保持不变。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章