R语言数据表重塑:将多组相邻Euros/N列转为按指标分行格式
错误根因定位
你之前执行spread(mydatatable, Euros, N)得不到预期结果的核心问题:
- 原始表是多组Euros、N列并排的非规范宽表,R读取时会自动给重名列加序号后缀(如
Euros、Euros.1、Euros.2),本身就不满足spread函数要求的「长表键值对」输入格式 - 你写的spread逻辑本身和目标反向:spread的作用是把长表的某列唯一值转成宽表的列名、取对应值列的内容填单元格,按照你写的参数,自然会把所有Euros的数值当列名、对应N的数值填在列下,完全偏离“按指标类型拆分ID行、保留所有横向位置原始值”的目标
- 这个场景下不需要强行走「长表转宽表」的流程,因为所有同类型的列本来就是按位置一一对齐的,硬用melt+spread的流程反而容易出现列错位、重复匹配的问题
正确实现方法
直接拆分聚合同类型指标列即可得到目标结构,以tidyverse生态为例的可复现代码如下:
- 模拟和你示例一致的真实读入数据结构
library(tidyverse) mydatatable <- tibble( ID = c("A", "C"), Euros = c("133.911,20", "9.470,35"), N = c(451, 2856), Euros.1 = c("134.208,78", "26,18"), N.1 = c(450, 2721), Euros.2 = c("442,03", "26,28"), N.2 = c(328, 2699) )
- 分别抽取两类指标的列,统一列名、添加指标类型标识
- 抽取所有列名带
Euros的列,给这部分行统一标记Var1 = "Euros",把数值列统一命名为位置序列 - 抽取所有列名带
N的列,用完全相同的位置序列命名数值列,给这部分行统一标记Var1 = "N"
# 拆分Euros维度的数据块,把数值列统一命名为位置序列 euros_block <- mydatatable %>% select(ID, starts_with("Euros")) %>% mutate(Var1 = "Euros") %>% set_names(c("ID", paste0("pos_", 1:(ncol(.) - 1)))) # 拆分N维度的数据块,用和上面完全一致的位置列名,保证纵向合并时列对齐 n_block <- mydatatable %>% select(ID, starts_with("N")) %>% mutate(Var1 = "N") %>% set_names(c("ID", paste0("pos_", 1:(ncol(.) - 1))))
- 纵向合并两个数据块,调整列顺序、重命名数值列匹配目标结构
final_res <- bind_rows(euros_block, n_block) %>% # 按ID排序,保证同一个ID的Euros、N两行记录挨在一起 arrange(ID) %>% # 把指标列Var1调整到ID后面的位置 relocate(Var1, .after = ID) %>% # 从第三列开始按顺序重命名为Var2、Var3...,匹配目标表列名 set_names(c("ID", "Var1", paste0("Var", 2:(ncol(.)-1))))
最终输出的表结构和你给出的目标表完全一致:
# A tibble: 4 × 5 ID Var1 Var2 Var3 Var4 <chr> <chr> <chr> <chr> <chr> 1 A Euros 133.911,20 134.208,78 442,03 2 A N 451 450 328 3 C Euros 9.470,35 26,18 26,28 4 C N 2856 2721 2699
注:如果后续列数更多,只要替换
starts_with()里的匹配前缀即可,代码不需要做其他修改,不会出现列错位的问题。
内容的提问来源于stack exchange,提问作者Eduardo
相关产品推荐
相关产品推荐

