R语言处理双表头CSV:将分组表头转为列及spread报错解决
报错原因
你执行转换时报错的核心原因是:gather 操作没有保留原始数据的行索引,导致同一个run + variable组合对应了多个重复的观测值,spread 函数无法判断这些重复值应该对应输出的哪一行,因此抛出key重复的错误。
解决方案
方案1:修正原有gather+separate+spread写法
只需要在转换前增加原始行号作为分组标识即可:
library(dplyr) library(tidyr) df_fix <- df %>% # 新增行号列,标识同批次的同一行观测 mutate(row_id = row_number()) %>% gather(key = "key", value = "value", -row_id) %>% separate(key, into = c('run', 'variable'), sep = "_") %>% # 可选:提取run的纯数字编号 mutate(run = as.integer(gsub("Run #", "", run))) %>% spread(variable, value) %>% # 删除不需要的行号列 select(-row_id)
方案2:使用新版tidyr的pivot函数(更简洁)
tidyr 1.0.0之后推出的pivot_longer可以一步完成列名拆分和表转换,不需要多步操作:
library(dplyr) library(tidyr) df_fix <- df %>% pivot_longer( cols = everything(), names_to = c("run", ".value"), names_sep = "_" ) %>% # 可选:提取run的纯数字编号 mutate(run = as.integer(gsub("Run #", "", run)))
其中.value是特殊参数,会自动将列名拆分后的第二部分作为新的列名,直接生成你需要的宽表结构。
其他可选方案:读取阶段直接处理表头
你也可以在读取CSV时直接合并表头,省去两次scan的操作:
library(readr) library(janitor) # 读取全部内容,不跳过表头 raw_df <- read_csv(file, col_names = FALSE, show_col_types = FALSE) # 合并前两行作为列名 colnames(raw_df) <- paste(raw_df[1,], raw_df[2,], sep = "_") # 删除前两行表头行,转换列类型 df <- raw_df[-c(1,2), ] %>% mutate(across(everything(), as.numeric))
之后再用上述任意转换方法处理即可得到目标结构。
内容的提问来源于stack exchange,提问作者protoperidinium
相关产品推荐
相关产品推荐

