如何用pivot_longer将含多配对列的宽数据转为指定长格式?
宽表转长表:拆分变量与备注列
问题描述
我查阅了多个相关解决方案,但均不适用,也不清楚如何调整以适配需求。我拥有一个结构极宽的数据表,示例如下(实际表更宽):
Key Metadata Var1 Var1_remark Var2 Var2_remark Var3 Var3_remark Var4 Var4_remark 1 Key1 Metadata1 0.0 <NA> 0.50 Present in A,C,E 0.00 <NA> 0.50 Present in B,D,F 2 Key2 Metadata2 0.0 <NA> 0.33 Present in A 0.33 Present in B 0.33 Present in C 3 Key3 Metadata3 0.5 Present in A 0.50 Present in B 0.00 <NA> 0.00 <NA>
生成示例数据的代码:
Key <- c("Key1", "Key2","Key3") Metadata <- c("Metadata1","Metadata2", "Metadata3") Var1 <- c(0, 0, 0.5) Var1_remark <- c(NA,NA,"Present in A") Var2 <- c(0.5, 0.33, 0.5) Var2_remark <- c("Present in A,C,E", "Present in A", "Present in B") Var3 <- c(0, 0.33, 0) Var3_remark <- c(NA,"Present in B",NA) Var4 <- c(0.5,0.33,0) Var4_remark <- c("Present in B,D,F", "Present in C", NA) wide.data <- data.frame(Key, Metadata, Var1, Var1_remark, Var2, Var2_remark, Var3, Var3_remark, Var4, Var4_remark)
我希望将其转换为如下长格式,列名拆分后对应Parameter(变量名)、Value(变量值)、Remark(备注):
Key Metadata Parameter Value Remark 1 Key1 Metadata1 Var1 0.00 <NA> 2 Key1 Metadata1 Var2 0.50 Present in A,C,E 3 Key1 Metadata1 Var3 0.00 <NA> 4 Key1 Metadata1 Var4 0.50 Present in B,D,F 1 Key2 Metadata2 Var1 0.00 <NA> 2 Key2 Metadata2 Var2 0.33 Present in A 3 Key2 Metadata2 Var3 0.33 Present in B 4 Key2 Metadata2 Var4 0.33 Present in C 1 Key3 Metadata3 Var1 0.50 Present in A 2 Key3 Metadata3 Var2 0.50 Present in B 3 Key3 Metadata3 Var3 0.00 <NA> 4 Key3 Metadata3 Var4 0.00 <NA>
我尝试过melt和pivot_longer多次,但均未得到预期结果:
- Test 1代码缺失Value列
pivot_longer(wide.data, cols=-c('Key','Metadata'), names_to = c('Parameter','.value'), names_sep = '_')
- Test 2代码无法合并Value列
pivot_longer(wide.data, cols=ends_with('_remark'), names_to = c('Parameter','.value'), names_sep = '_')
请问如何基于wide.data得到目标格式?
解决方案
问题出在names_to参数与列选择的匹配逻辑上,以下两种方法可以实现需求:
方法1:使用names_pattern(更灵活适配现有列名)
利用正则表达式匹配变量名和后缀,直接拆分转换:
library(tidyverse) long.data <- wide.data %>% pivot_longer( cols = -c(Key, Metadata), # 保留Key和Metadata作为标识列 names_to = c("Parameter", ".value"), names_pattern = "(Var\\d+)(_remark)?" # 匹配VarX和可选的_remark后缀 ) %>% rename(Value = `NA`, Remark = `_remark`) %>% # 重命名自动生成的列 mutate(Value = as.numeric(Value)) # 确保Value列是数值型
方法2:统一列名后缀后拆分
先给变量值列补全后缀,再按下划线拆分:
library(tidyverse) long.data <- wide.data %>% rename_with(~paste0(., "_value"), starts_with("Var")) %>% # 给VarX列添加_value后缀 pivot_longer( cols = -c(Key, Metadata), names_to = c("Parameter", ".value"), names_sep = "_" # 按下划线拆分列名 ) %>% rename(Value = value) # 重命名为目标列名
转换结果验证
运行上述代码后,得到的long.data即为目标长格式:
# A tibble: 12 × 5 Key Metadata Parameter Value Remark <chr> <chr> <chr> <dbl> <chr> 1 Key1 Metadata1 Var1 0 NA 2 Key1 Metadata1 Var2 0.5 Present in A,C,E 3 Key1 Metadata1 Var3 0 NA 4 Key1 Metadata1 Var4 0.5 Present in B,D,F 5 Key2 Metadata2 Var1 0 NA 6 Key2 Metadata2 Var2 0.33 Present in A 7 Key2 Metadata2 Var3 0.33 Present in B 8 Key2 Metadata2 Var4 0.33 Present in C 9 Key3 Metadata3 Var1 0.5 Present in A 10 Key3 Metadata3 Var2 0.5 Present in B 11 Key3 Metadata3 Var3 0 NA 12 Key3 Metadata3 Var4 0 NA
之前尝试失败的原因
- Test 1:用
names_sep="_"拆分时,Var1会被拆分为Var1和空值,.value无法匹配到对应列名,导致Value列缺失。 - Test 2:仅选择了以
_remark结尾的列,未包含变量值列,自然无法合并出完整结果。
内容的提问来源于stack exchange,提问作者David Inman
相关产品推荐
相关产品推荐

