You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在R中转换含多行表头的Excel实验室数据为长格式数据框?

处理多表头Excel数据并转换为长格式数据框

我有多个Excel工作表,每个表包含约120项实验室结果和150位患者的矩阵数据。实验室结果从第4行开始存储,患者列则在第1至3行有额外表头数据,希望将其读取并转换为长格式/规范化的数据框。

我尝试使用pivot_longer或melt处理,但左上角的空单元格带来问题:实验室结果的列表头从第4行开始,患者列从C列开始。患者列名固定从D列开始,但具体患者ID(如EXA_2665、EXA_2707等)无法预先知晓。

目前尝试的代码

library(tidyverse)
library(readxl)
library(dplyr)
library(tidyr)

##xls_data <- read_excel(path = "lab2_exafinal.xlsx", sheet = "Labata")
## TEST hardcoded data for testing purposes
xls_data2 <- read.table(text = "
...1,...2,Patient-Id,EXA_2665,EXA_2707,EXA_2971
,,Tube,87019054,87065976,87093024
,,Tube-Pos,C12,D01,D02
LabId,LabDescr,WeightFact,,,
9,HbA1c,1.00,1.784,0.419,1.045
37,HDL-Chol,1.00,0.684,2.172,1.954
38,LDL-Chol,1.00,2.438,1.995,0.806
41,Glucose,1.00,1.366,1.47,0.978
", header = TRUE, sep = ",", na.strings = "")

library(reshape)
df_melt <- melt(xls_data, id.vars=c("...1", "...2"))
# error: names do not match previous names

pivoted_data <- pivot_longer(
  xls_data,
  cols = names(xls_data[3,]),
  names_to = "patient",
  values_to = "value" 
  )
#no error but not quite the desired result

补充数据结构(dput输出)

编辑补充:经建议使用dput分享read_excel读取后的准确数据结构,同时注意患者标签名可能包含-字符。

#xls_data <- read_excel(path = "lab2_exafinal.xlsx", sheet = "Labata")
#dput(xls_data)
xls_data <- structure(
  list(
    ...1 = c(NA, NA, "LabId", "9", "37", "38", "41"),
    ...2 = c(NA, NA, "LabDescr", "HbA1c", "HDL-Chol", "LDL-Chol", "Glucose"),
    ...3 = c("Tube", "Tube-Pos", "WeightFact", "1,00", "1,00", "1,00", "1,00"),
    EXA_2665 = c("87019054", "C12", NA, "1.784", "0.68400000000000005", "2.4380000000000002", "1.3660000000000001"),
    EXA_2707 = c("87065976", "D01", NA, "0.41899999999999998", "2.1720000000000002", "1.9950000000000001", "1.47"),
    EXA_2971 = c("87093024", "D02", NA, "1.0449999999999999", "1.954", "0.80600000000000005", "0.97799999999999998")
    ),
    class = c("tbl_df", "tbl", "data.frame"),
    row.names = c(NA, -7L)
  )

遇到的问题

使用readxl::read_excel读取Excel表时,前两列为...1、...2。尝试用melt时将它们设为id.vars出现错误;pivot_longer运行无错但结果不符合预期,问题在于存在额外表头行,不知如何处理或移除。

我想到两种思路但不知如何在RStudio中实现:

  • 将患者数据(C1..F3)和实验室数值(A4..F8)分别读取为两个数据框,再合并。
  • 先将患者表头名(如EXA_2665)复制到空的第4行,再重新读取A4..F8区域。

请问还有哪些可行的解决方法?


解决方案

方法一:拆分表头与数据,分别处理后合并

直接拆分患者元数据和实验室结果,整理后关联:

library(tidyverse)

# 1. 提取并整理患者元数据(Tube、Tube-Pos信息)
patient_meta <- xls_data %>%
  slice(1:2) %>%
  pivot_longer(cols = starts_with("EXA"), names_to = "patient_id", values_to = "value") %>%
  pivot_wider(names_from = ...3, values_from = value) %>%
  select(patient_id, Tube, `Tube-Pos`)

# 2. 提取并整理实验室结果数据
lab_data <- xls_data %>%
  slice(4:n()) %>%
  rename(
    LabId = ...1,
    LabDescr = ...2,
    WeightFact = ...3
  ) %>%
  mutate(WeightFact = as.numeric(str_replace(WeightFact, ",", ".")))

# 3. 转为长格式并关联患者元数据
final_long_data <- lab_data %>%
  pivot_longer(cols = starts_with("EXA"), names_to = "patient_id", values_to = "lab_result") %>%
  mutate(lab_result = as.numeric(lab_result)) %>%
  left_join(patient_meta, by = "patient_id")

# 查看最终结果
print(final_long_data)

方法二:重构表头后读取数据

先合并表头信息,再提取数据转为长格式:

# 重构患者列的表头(合并ID、Tube、Tube-Pos)
new_colnames <- c("LabId", "LabDescr", "WeightFact",
                  paste(names(xls_data)[4:ncol(xls_data)],
                        xls_data[1,4:ncol(xls_data)],
                        xls_data[2,4:ncol(xls_data)],
                        sep = "_"))

# 提取数据行并设置新表头
clean_lab_data <- xls_data %>%
  slice(4:n()) %>%
  set_names(new_colnames) %>%
  mutate(across(c(WeightFact, starts_with("EXA")), ~as.numeric(str_replace(., ",", "."))))

# 拆分表头转为长格式
final_long_data2 <- clean_lab_data %>%
  pivot_longer(cols = starts_with("EXA"), 
               names_to = c("patient_id", "Tube", "Tube-Pos"),
               names_sep = "_",
               values_to = "lab_result")

方法三:分区域读取Excel文件

直接指定Excel区域分别读取元数据和结果,避免混合表头问题:

# 读取患者元数据(C1到F3区域)
patient_meta_range <- read_excel("lab2_exafinal.xlsx", sheet = "Labata", range = "C1:F3", col_names = FALSE) %>%
  pivot_longer(cols = 2:ncol(.), names_to = "col_idx", values_to = "value") %>%
  pivot_wider(names_from = 1, values_from = value) %>%
  rename(patient_id = `...1`)

# 读取实验室数据(A4到F8区域)
lab_data_range <- read_excel("lab2_exafinal.xlsx", sheet = "Labata", range = "A4:F8")

# 转为长格式并合并
final_long_data3 <- lab_data_range %>%
  pivot_longer(cols = starts_with("EXA"), names_to = "patient_id", values_to = "lab_result") %>%
  left_join(patient_meta_range, by = "patient_id")

内容的提问来源于stack exchange,提问作者BdR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 00:23:13