☰
TCGA甲基化数据导入实战:从IDAT文件到Sample Sheet构建与ChAMP流程
2026/10/24 4:55:09 网站建设 项目流程

1. 项目整体设计与思路拆解

1.1 项目背景

做TCGA甲基化数据挖掘的同学,应该都经历过这个阶段:从GDC Portal或者Firehose下载了一堆.idat文件,满心欢喜准备跑ChAMP流程,结果一加载数据就报错,提示找不到Sample Sheet,或者样本信息对不上。这时候你才意识到,TCGA给的数据可不像GEO那样自带一份整理好的矩阵,所有样本的芯片位置、样本类型、平台信息都得自己从文件名和metadata里扒出来。

这个项目解决的就是这件事:把TCGA下载的.idat原始文件,通过ChAMP包的champ.load函数正确导入,并在此之前构建出一份合法可用的Sample Sheet。说白了,这是整个甲基化分析流程的第一步,也是决定后续所有分析能否进行的关键一步。

我知道很多人图省事,直接去GEO搜同一个项目的甲基化矩阵数据,下载现成的beta值矩阵来分析。这当然可行,但如果你需要做更精细的质控、需要原始的探针信号强度、需要自己决定过滤参数,那从.idat原始文件走一遍ChAMP的标准流程是更稳妥的选择。而且TCGA官方推荐的处理流程,也是从原始.idat开始,用统一的流程重新处理,而不是直接使用已经处理过的Level 3数据。

这个项目适合以下人群参考:刚接触甲基化数据挖掘的研究生、准备做TCGA甲基化泛癌分析的科研人员、以及需要在多个数据集上跑ChAMP流程的老手。我会把从下载到导入的整个流程拆开讲,包括Sample Sheet的每个字段怎么填、为什么这么填、champ.load内部做了什么,以及那些网上资料很少提到的坑。

1.2 ChAMP流程与Sample Sheet的关系

ChAMP包(Chip Analysis Methylation Pipeline)是英国团队开发的一套甲基化芯片分析流程,它整合了从数据导入、质控、归一化到差异甲基化分析的全套功能。它的设计思路是“一切从原始数据开始”,所以第一步就是用champ.load读入.idat文件和配套的Sample Sheet。

在这个流程里,Sample Sheet不仅仅是给样本做个注释表那么简单。ChAMP会根据Sample Sheet里的信息,自动完成以下操作:

  1. 读取.idat文件时,根据Basename列定位文件路径,根据Sentrix_ID和Sentrix_Position校验芯片与阵列位置。
  2. 去除质量控制不合格的样本和探针。
  3. 根据Sample_Name和其他列信息,自动推断样本分组关系。
  4. 生成后续分析用的beta值矩阵、M值矩阵和intensity矩阵。

如果你提供的Sample Sheet信息不全或者格式不对,champ.load大概率直接报错,或者更隐蔽地——导入成功但样本顺序全乱了、分组信息全错,后面的差异分析结果完全是错的。我在实际项目中就遇到过这种情况,最后花了一整天排查,结果发现是Sample Sheet里有两行样本的Sentrix_Position写反了,导致那两列数据被调换了。

所以,构建一份准确完整的Sample Sheet,绝不是简单填个表的事。它决定了整个分析流程的正确性,值得认真对待。

2. TCGA甲基化数据下载与文件结构解析

2.1 TCGA甲基化数据有哪些常见来源

TCGA甲基化数据主要有三个获取渠道,我分别说下它们的优缺点和适用场景。

GDC Data Portal(官方数据门户):这是TCGA项目官方提供的数据下载平台。在这里可以下载到最原始的.idat文件,以及配套的临床信息、样本信息。优点是数据最全且更新及时,缺点是下载流程繁琐,需要手动勾选一长串选项,而且下载的压缩包内部目录结构很绕,不方便自动处理。

GDC Data Transfer Tool(命令行工具):同样是官方的,用命令行方式下载数据。如果你要下载几百个样本的甲基化数据,用图形界面一个个点是会崩溃的,这时候命令行工具就省力得多。可以配合manifest文件批量下载,也支持断点续传。但就是需要学一下它的命令行参数,初期有点上手成本。

Firehose / Broad Institute GDAC:这个渠道现在已经停止更新了,但历史数据还在。它提供的是处理好的Level 3数据,不是原始.idat文件。如果你只是想快速看个结果,这个渠道够用。但如果你要跑ChAMP全流程,还是得从原始数据走起。

以我的经验,最靠谱的组合是:用GDC的manifest文件配合命令行工具批量下载.idat文件,然后用GDC提供的metadata文件来构建Sample Sheet。这样既保证了数据的原始性,又能自动对齐样本的临床信息。

2.2 .idat文件的目录结构与命名规则

从GDC下载的TCGA甲基化数据,经过解压后,目录结构大概是这样:

TCGA-BRCA/ ├── 0001/ │ ├── 205765520053_R01C01_Grn.idat │ ├── 205765520053_R01C01_Red.idat │ ├── 205765520053_R02C01_Grn.idat │ ├── 205765520053_R02C01_Red.idat │ └── ... ├── 0002/ │ └── ... └── metadata.tsv

这里有几个关键信息要搞清楚:

第一,每个样本包含两个.idat文件,一个是_Grn.idat(绿色通道),一个是_Red.idat(红色通道)。这两个文件必须放在同一个目录下,ChAMP读取的时候会自动识别配对关系。千万不能分开存放,否则会报“找不到对应的Red文件”之类的错误。

第二,文件名中间的205765520053_R01C01是两个关键信息的拼接:前面的数字(比如205765520053)是芯片的Sentrix ID(即芯片批号),后面的是Sentrix Position(即该样本在芯片上的物理位置)。R01C01表示第1行第1列,R02C01表示第2行第1列。这个命名规则直接对应了Sample Sheet里的Sentrix_ID和Sentrix_Position列。

第三,目录名的四位数字(比如0001、0002)是样本的编号,它对应TCGA样本条形码(barcode)的一部分。你可以通过metadata文件里的file_name列和cases.submitter_id列来建立目录和TCGA样本ID的对应关系。

注意:TCGA的甲基化数据有两种芯片平台:450K(Infinium HumanMethylation450 BeadChip)和EPIC(Infinium MethylationEPIC BeadChip,也叫850K)。两者芯片尺寸和探针数量不同,Sample Sheet里的Sentrix_ID区段也不一样。如果一批数据混用了两种平台,ChAMP是无法直接合并分析的,需要分开处理。这个后面会详细说。

2.3 metadata文件的价值

很多人下载完.idat文件后,顺手把metadata.tsv文件扔到一边,只想着赶紧跑分析。但我建议你先别急着关掉它,这份metadata文件可是构建Sample Sheet的重要依据。

metadata文件里包含每个文件的UUID、文件名、关联的casesubmitter_id(就是TCGA样本条形码,比如TCGA-XX-XXXX-01)、样本类型(primary tumor、solid tissue normal等)、芯片平台(450K或EPIC)等关键信息。

通过这份metadata文件,你可以:

  1. 建立.idat文件名和TCGA样本ID的映射关系,知道哪个文件是哪个样本的。
  2. 获取每个样本的肿瘤类型、样本类型(肿瘤/正常),用于后续的分组分析。
  3. 识别芯片平台,提前判断是否混合使用了450K和EPIC。

这个文件是构建Sample Sheet的“原材料”,后面构建过程中我们会反复用到它。

3. Sample Sheet的构建:字段解析与生成方法

3.1 Sample Sheet的核心字段

一份ChAMP能正常识别的Sample Sheet,至少要包含以下几列:

字段名含义必需性示例
Sample_Name样本名称,建议用TCGA样本条形码或自定义名称必需TCGA-XX-0001-01
Basename.idat文件的完整路径(不含_Grn/_Red后缀和扩展名)必需/data/TCGA-BRCA/205765520053_R01C01
Sentrix_ID芯片批号必需205765520053
Sentrix_Position芯片上的阵列位置必需R01C01
Sample_Group样本分组信息强力建议Tumor / Normal
Sample_Plate芯片板信息可选Plate1
Pool_ID池编号可选-

这里面最关键的是Basename、Sentrix_ID和Sentrix_Position这三列。为什么?因为ChAMP内部读取数据时,会先用Basename拼接出.idat的完整路径,然后用正则表达式从文件路径中反解析出Sentrix_ID和Sentrix_Position。这三列如果填写不一致,champ.load就会认为给定的文件与Sample Sheet中的记录不匹配,直接报错。

Sample_Group这列容易被忽略,但实际很重要。它在后续的champ.DMP(差异甲基化位置)分析中直接作为分组依据。如果你不在Sample Sheet阶段就整理好样本分组,后面跑差异分析时还得回头补,很麻烦。而且ChAMP的质控图形展示也会按Group着色,没有分组信息的话,画的图全是同一个颜色,美化效果和可读性都会差很多。

3.2 R脚本构建Sample Sheet的完整流程

这里我直接提供一个经过多次验证的R脚本,你可以根据自己的数据调整路径和字段。

# 加载必要的包 library(dplyr) library(stringr) # 设定路径 idat_dir <- "/path/to/your/idat/files" metadata_file <- file.path(idat_dir, "metadata.tsv") # 读取metadata文件 metadata <- read.delim(metadata_file, stringsAsFactors = FALSE) # 从文件名中提取Sentrix_ID和Sentrix_Position # 文件名格式:205765520053_R01C01_Grn.idat extract_sentrix <- function(file_name) { # 移除_Grn.idat或_Red.idat后缀 basename_clean <- gsub("_(Grn|Red)\\.idat$", "", file_name) # 提取Sentrix_ID(下划线前的数字) sentrix_id <- str_extract(basename_clean, "^\\d+") # 提取Sentrix_Position(下划线后的部分) sentrix_position <- str_extract(basename_clean, "R\\d+C\\d+$") # 注意:GDC下载的文件名格式可能是UUID格式,需要特殊处理 # 如果提取失败,尝试从file_id列关联回去 list(sentrix_id = sentrix_id, sentrix_position = sentrix_position, basename = file.path(idat_dir, basename_clean)) } # 对每个文件提取信息 metadata$sentrix_id <- sapply(metadata$file_name, function(x) { # 这里根据实际文件名格式调整正则 gsub("_.*$", "", x) }) metadata$sentrix_position <- sapply(metadata$file_name, function(x) { tmp <- gsub("^\\d+_", "", x) gsub("_(Grn|Red)\\.idat$", "", tmp) }) # 构建Sample Sheet sample_sheet <- metadata %>% # 每个样本有Grn和Red两个文件,需要去重 distinct(cases.submitter_id, .keep_all = TRUE) %>% transmute( Sample_Name = cases.submitter_id, Basename = file.path(idat_dir, gsub("_(Grn|Red)\\.idat$", "", file_name)), Sentrix_ID = sentrix_id, Sentrix_Position = sentrix_position, Sample_Group = ifelse(grepl("-11", cases.submitter_id), "Normal", "Tumor"), Sample_Plate = "GDC_TCGA", Pool_ID = NA ) # 输出Sample Sheet write.csv(sample_sheet, file.path(idat_dir, "sample_sheet.csv"), row.names = FALSE)

这里有几个细节需要特别说明:

第一,关于Basename的构造。ChAMP的champ.load函数内部会用paste0(Basename, "_Grn.idat")来定位文件,所以Basename绝不能包含_Grn或_Red后缀。很多新手在这里栽跟头,喜欢把整个文件名填进去,结果怎么都读不到数据。

第二,关于重复文件名的处理。GDC的metadata文件里,同一个样本的Grn和Red文件占两行,如果不distinct去重,生成的Sample Sheet会包含重复行,后面champ.load就会报“Sample Name重复”的错误。但实际上,由于TCGA部分样本有多个.idat文件(比如同一个样本测了两次,或者补充了重复实验),仅用cases.submitter_id去重会出问题。更好的做法是用samples.sample_id列去重,或者干脆用文件名的Sentrix_ID和Sentrix_Position组合去重,确保每个芯片位置只保留一个文件。

第三,关于Sample_Group的推断。TCGA样本条形码的最后两位数字表示样本类型:01表示原发性实体瘤,11表示实体组织正常,02表示转移性肿瘤。所以简单地用grepl("-11", cases.submitter_id)来判断Normal和Tumor是有效的,但这只适用于BRCA、LUAD这类既有肿瘤又有正常组织的项目。像GBM这类几乎没有正常组织的项目,分组就得靠其他方式(比如分子亚型、IDH突变状态等),你需要在Sample Sheet构建完成后手动修改Sample_Group列。

3.3 手动构建Sample Sheet的场景

是不是所有场景都需要用脚本自动构建?倒也不是。如果你的样本量很小(比如几十个以内),手动建立一份Excel表可能更快。

手动构建时,最关键的是把.idat文件所在目录里每个文件的Sentrix_ID和Sentrix_Position逐个填进去。此时要注意:

  1. 同一样本的两个文件(Grn和Red)的Sentrix_ID和Sentrix_Position必须完全一致,这是芯片本身的属性,跟哪个通道无关。
  2. 如果TCGA下载的是GDC的“bcr”渠道数据,文件名可能是UUID形式(比如a1b2c3d4-..._Grn.idat),这时Sentrix_ID和Sentrix_Position在文件名中找不到,需要进入.idat文件内部去解析。这种情况通常出现在直接从GDC的“Files”页面下载而非通过manifest批量下载的场景。好在ChAMP较新版本提供了readidat函数可以读取.idat文件的核心信息,但前提是Basename列还是得填对。
  3. 建议用Excel处理时,将Sentrix_ID列设为文本格式,避免Excel自动把长数字转成科学计数法。205765520053这个15位数字一旦被转成2.05765520053E+14,就彻底毁了。

提示:无论用哪种方式构建Sample Sheet,只要动手做完,都建议随手把文件放到与.idat文件相同的目录或者一个专门的数据目录下。很多教程喜欢把Sample Sheet放到项目根目录,但我习惯放在idata目录下,因为这样在换机器、换环境时,不容易出现路径对不上的问题。

4. champ.load导入的实操与参数选择

4.1 最基础的加载方法

Sample Sheet构建完成后,接下来就是导入环节。先用最基础的方式跑一遍:

library(ChAMP) myLoad <- champ.load(directory = "/path/to/your/idat/files", method = "ChAMP", methyArray = NULL, filterXY = TRUE, arraytype = "450K")

这里的几个参数说明一下:

  • directory:.idat文件的存放目录,ChAMP会自动在该目录下寻找sample_sheet.csv文件,并根据Basename列定位.idat文件。
  • method = "ChAMP":指定读取方法。ChAMP也支持读取其他格式,比如minfi方法,但既然用ChAMP流程,就用默认的ChAMP方法就好。
  • filterXY = TRUE:过滤性染色体上的探针。这是标准步骤,因为性染色体上的甲基化信号差异主要是X失活引起的,不反映疾病相关变化,留在数据里只会增加噪声。但注意,如果你研究的是与性别相关的疾病(比如乳腺癌、前列腺癌),这个参数可能需要酌情调整,因为有些研究想保留性染色体探针来观察特定的调控模式。
  • arraytype = "450K":指定芯片类型。如果你的数据是EPIC芯片,这里要改成"EPIC"。如果两个类型的数据混在一起,得分开导入,不能混在一个项目里。

跑完这段代码,正常情况下你会看到类似这样的输出:

[ Section 1: Read IDAT files ] ........ [ Section 2: Filter probes ] ... [ Section 3: Generate beta value matrix ] ...

然后变量myLoad中会包含beta(甲基化水平矩阵)、intensity(信号强度数据)、pd(phenotype data,即样本信息)等元素。myLoad$pd实际上就是你的Sample Sheet内容,只不过ChAMP可能做了一些标准化处理。

4.2 当文件名是UUID格式时的处理

前面提到,GDC下载的文件名有时是UUID格式,而不是SentrixID_RC_通道.idat的常规格式。这种文件的文件名里根本没有Sentrix_ID和Sentrix_Position信息,此时Sample Sheet怎么填?

有两个解决思路:

思路一:从.idat文件内部提取信息。

.idat文件虽然是以二进制格式存储的,但头部有一个manifest信息,可以通过R的IlluminaBeadArrayFiles或者ChAMP自带的readidat函数来读取。只是这个操作比较复杂,而且每次只能读一个文件,不适合批量处理。

思路二:先用minfi包读入一个样本,获取Sentrix_ID和Sentrix_Position。

这是我比较推荐的做法,实操起来效率更高。思路是:

library(minfi) # 选一个Grn.idat文件 idat_file <- list.files("/path/to/idat", pattern = "_Grn\\.idat$", full.names = TRUE)[1] # 读取该文件的头部信息 rgset <- read.metharray(idat_file) # 从RGChannelSet的注释中获取芯片信息(实际项目中可以查看pData(rgset)获取sentrix信息)

代码只是示意,不同版本的minfi或新开发的sesame包,输出格式有差异。但核心思路是:只要有任何一个.idat文件能被正确读取,你就能从中解析出Sentrix_ID和Sentrix_Position,然后填充到Sample Sheet里。

实际上,我后来发现,GDC UUID格式的文件名中,经过manifest重新下载的文件是可以直接和Sample Sheet匹配上的,因为ChAMP的champ.load查到Sample Sheet里Basename列之后,会自己尝试拼接_Grn.idat和_Red.idat来定位文件。如果文件名不是这个规则,它会尝试用项目内的ID匹配逻辑。但为了避免折腾,我一般建议在构建Sample Sheet时就直接把文件名重新映射一下,或者下载时在GDC的界面里勾选“合并IDAT”的选项,让文件名保持可解析的样子。可惜GDC不同版本界面不一样,这一点要具体情况具体分析。

4.3 自动检测芯片平台的重要性

TCGA早期项目主要用450K芯片,后期项目(比如2017年后新增的样本)用EPIC芯片。如果你从TCGA批量下载了不同批次的样本,很可能混入两种平台的芯片。

一个简单的检测方法是看Sentrix_ID的长度:450K芯片的Sentrix_ID通常是9到10位数字,EPIC芯片的Sentrix_ID是10位数字,但并不可靠。最稳妥的方法是查看.idat文件大小——EPIC的.idat文件通常约5MB,450K约2.5MB。当然,最正规的方法还是使用minfi的read.metharray函数,它能直接告诉你芯片的注释版本是IlluminaHumanMethylation450k还是IlluminaHumanMethylationEPIC。

ChAMP导入时,arraytype参数必须和实际芯片平台完全一致。填错了虽然不会直接报错,但内部注释文件匹配会出问题,结果就是探针ID无法对应到基因注释,后续所有分析全部白给。一个可以跳过识别过程的偷懒做法是:将arraytype设为"auto",但老版本的ChAMP不支持这个参数,新版本也没见到全面支持,所以还是老老实实手动指定更稳。

4.4 champ.load后的样本质控

数据导入成功不代表什么,紧接着要做的是用ChAMP自带的质控功能检查样本质量。

champ.QC(intensity = myLoad$intensity, pheno = myLoad$pd$Sample_Group)

质控会输出两张图:一张是样本信号强度分布(通常是两种颜色对应Grn和Red两通道),另一张是样本间甲基化水平的相关性热图。你要关注的关键指标是:是否有样本的强度明显偏低、是否存在信号异常的离群样本。

我实际跑过的TCGA数据里,十个项目里总会有一两个样本的芯片质量不过关,强度分布呈一条水平线,或者相关性矩阵中呈现明显暗色。如果发现这样的样本,建议直接在后续的champ.filter阶段把这些样本标记为剔除,或者直接在Sample Sheet里删除对应行重跑一遍。

提示:ChAMP的质控图尽量在导入后立刻跑,不要拖到归一化之后再做。因为归一化会调整原始信号,有时会把质量差的样本“修正”得不那么显眼,反而掩盖了问题。先看原始质量,再决定要不要剔除,是更合理的工作流。

5. 常见问题与排查技巧实录

5.1 报错排查速查表

我把实践和网上反馈中常见的报错整理成了速查表,可以直接对照解决。

报错信息常见原因解决方法
Error in read.idat: Cannot find file XXXBasename路径不对,或者文件名拼写与目录不一致检查Basename是否包含_Grn/_Red后缀;确认真实文件路径与Basename拼接后的路径一致
Error: Sample_Name duplicatedSample Sheet中有重复样本行用distinct()去重;检查是否把同一对Grn/Red文件写成了两行
Error: No sample_sheet.csv found目录下没有sample_sheet.csv,或命名不精确确保证文件名是sample_sheet.csv而非SampleSheet.csv;确认当前工作目录与directory参数一致
Warning: Sentrix_ID and Sentrix_Position do not match the idat filesSample Sheet中的Sentrix信息与文件名不一致检查是否写错了一列,比如把Sentrix_ID和Sentrix_Position写反;检查是否有混平台样本
Error in .getManifest: No arraytype matchedarraytype参数填错,或数据平台确实不同检查芯片平台,改用相应地450K或EPIC
导入成功但beta矩阵的样本数小于Sample Sheet行数部分样本QC未通过被自动剔除查看champ.load的输出日志,确认哪些样本被剔除;也可调整QC参数关闭自动过滤

5.2 我踩过的一个典型坑:Sentrix_Position的字母大小写

这个看起来是小细节,但真的坑过不少人。有人从别处整理的Sample Sheet里,把Sentrix_Position写成了小写,比如r01c01,而ChAMP在匹配时是区分大小写的。

R01C01和r01c01在语法上并不是同一个值,ChAMP匹配时会匹配不上。好在TCGA原始文件名里的位置信息是标准的大写格式,所以只要你是从文件名直接提取的,一般不会出问题。但如果你手动填写的,或者从Excel自动补全的,就可能被统一成小写格式。建议在填完Sample Sheet后,加一步检查:

sample_sheet$Sentrix_Position <- toupper(sample_sheet$Sentrix_Position)

顺手做个大写转换,一劳永逸。

5.3 另一个隐蔽坑:不同文件夹的.idat文件混在一起导入

有时候你把不同批次下载的TCGA数据混在一个目录里,比如BRCA项目早期下载的和后期补测的样本放一起,但两批文件的子目录结构不同——有的直接放在根目录,有的放在子文件夹里。这时候Sample Sheet里的Basename就会很混乱,一半是对的,一半是错的。

解决办法是:在构建Sample Sheet时,不要用相对路径,统一用绝对路径。而且最好在写Sample Sheet之前,先用下面的代码检查一下所有Basename对应的文件是否实际存在:

check_files <- file.exists(paste0(sample_sheet$Basename, "_Grn.idat")) & file.exists(paste0(sample_sheet$Basename, "_Red.idat")) table(check_files)

如果有一部分返回FALSE,说明路径构造确实有问题,趁早排查,别等champ.load跑一半才报错。

5.4 ChAMP与minfi的关系

你可能会问:既然minfi包也能读取.idat文件并构建甲基化数据对象,为什么还要用ChAMP的champ.load?

我的理解是:minfi是更底层的工具库,功能全面,但你要自己写很多代码来完成质控、归一化、差异分析等一整套流程。而ChAMP更像是把这些步骤集成封装好的流水线,对流程标准化更友好。两者不是竞争关系,ChAMP内部很多功能其实也依赖minfi来读取数据。

实际工作中,我会先把数据用ChAMP跑一遍标准流程,看看整体情况;再根据研究需要,用minfi或sesame做特定的预处理和可视化。尤其是在处理TCGA数据时,如果你的样本量很大(比如几百个样本),我会更推荐ChAMP,因为它的内存管理更友好,某些流程函数会自动分批处理,不易爆内存;minfi在处理大样本量时更容易出现内存不足。

6. 从champ.load到后续分析的衔接

6.1 champ.load之后的数据格式

champ.load返回的是一个列表,叫myLoad,里面包含几个核心元素:

  • myLoad$beta:样本×探针的甲基化水平矩阵,数值范围0到1,0代表未甲基化,1代表完全甲基化。
  • myLoad$M:M值矩阵,是beta值经过logit变换后的结果,范围从负无穷到正无穷。差异分析通常用M值,因为它的统计分布更接近正态分布。
  • myLoad$intensity:各样本的甲基化和非甲基化信号强度总和。
  • myLoad$pd:样本信息表(即Sample Sheet)。
  • myLoad$details:包含QC统计信息和过滤过程的相关细节。

从这里就可以进入标准的ChAMP后续流程:

# 归一化 myNorm <- champ.norm(beta = myLoad$beta, arraytype = "450K", method = "BMIQ") # 差异甲基化分析(比较Tumor vs Normal) myDMP <- champ.DMP(beta = myNorm, pheno = myLoad$pd$Sample_Group, compare.group = c("Normal", "Tumor")) # 差异甲基化区域分析 myDMR <- champ.DMR(beta = myNorm, pheno = myLoad$pd$Sample_Group, method = "Bumphunter") # 功能富集分析 myGSEA <- champ.GSEA(beta = myNorm, DMP = myDMP, arraytype = "450K")

整个流程在ChAMP的框架下天然衔接,这也是从一开始就坚持用ChAMP导入的意义所在。

6.2 Sample Sheet没构建好,后续分析会怎样?

如果我们在Sample Sheet阶段偷懒,导入时用了不完整的信息,后续分析会有哪些具体的异常表现?这里说几个我实际见过的场景。

场景一:Sample_Group列缺失或乱填。导入不报错,甚至质控图看着也没什么问题,但跑champ.DMP时会提示无分组信息,或者跑完看结果发现所有比较都是以“A组”和“B组”这种无意义名称呈现,你得再费半天劲儿去映射哪个组是肿瘤、哪个是正常。

场景二:样本顺序和临床信息没对应上。如果你自己整理了一份临床信息表(比如生存时间、分期等),想和甲基化数据合并做生存分析,如果Sample Sheet里的样本顺序与临床表的顺序不一致,合并时就容易出错。TCGA样本名可以作为连接键,但在Sample Sheet里用自定义短名称(比如BRCA_01)的情况下,连接时会遇到对应不上的情况。

场景三:正常组织判断失误。TCGA的样本条形码后缀“11”表示正常,“01”表示肿瘤,但有一种特殊情况是“06”(转移性肿瘤)和“10”(血液来源正常,用于白血病等)。如果你的项目是白血病(LAML),用-11判断正常就不适用了,因为正常的对照血液样本后缀是-10。遇到这种情况,建议认真看metadata文件里的样本类型描述,直接使用官方分类字段,不要自己用正则硬拆。

6.3 一个建议:Sample Sheet用共享链接或version控制保存

在TCGA甲基化分析这种偏合作的科研项目中,Sample Sheet往往需要在组内多人之间来回传递。很多人喜欢用微信或邮件发Excel文件,但版本混乱的问题随之而来:今天张三改了分组,明天李四更新了路径,等文件传回你手上的时候,你根本不知道谁改了什么。

我自己的做法是:把Sample Sheet和构建脚本一起放到项目的Git仓库里,每次修改都留下commit记录。这样做有三点好处:

  1. 每一步操作都可追溯,万一分析结果不对,能回溯到数据处理的哪个环节出了问题。
  2. 样本的分组、QC、剔除等操作记录一目了然,写论文方法部分的时候能准确描述每一步做了什么。
  3. 换电脑、换服务器时不会丢文件,也不怕误删。

这个经验是踩了多次坑之后总结出来的。第一次是没有保存构建脚本,只留了Sample Sheet,后来发现一个样本分组写错了,想改却发现根本不知道当初是怎么分组的。第二次是Sample Sheet被多轮修改后产生了多个版本,最后拿到的版本连Sentrix_Position都被Excel自动格式化成乱码了。自从把构建流程脚本化并纳入版本管理后,这类问题基本消失了。

6.4 内存管理与批量操作经验

如果你同时处理多个TCGA项目(比如做泛癌分析),一次性把所有项目的.idat都导入ChAMP,内存很容易爆掉。我实测了一个约300个样本、450K平台的BRCA项目,champ.load阶段的内存峰值大约在8到10GB,这是个不小的消耗。如果是EPIC平台、样本数500个以上,16GB内存的机器基本跑不动。

如果要处理多个项目,我建议的策略是:每个项目单独跑champ.load,把beta矩阵保存为RData文件,后续分析再统一加载。

save(myLoad, file = "BRCA_methylation_load.RData")

这样分开保存的好处是:每个项目的Sample Sheet可以单独维护,互不干扰;泛癌分析时只需要逐个加载myLoad的beta矩阵做合并,内存压力小得多;如果某个项目数据需要重新质控,只需重跑那一个项目,不用全量重来。

这个流程我实际跑下来觉得风险可控、效率也不差。如果你要一次性分析多个癌种,建议先确认这些项目的芯片平台是否一致,混平台的话后续合并会有很大麻烦(探针集不重叠,合并后可用探针数量骤减)。

7. 个人经验总结

这个TCGA甲基化数据导入流程,我前前后后跑了近十个项目,想清楚之后,整个流程其实很机械,难点全在Sample Sheet构建这一步。很多人卡在这一步反复折腾,并不是因为代码写不出来,而是没搞明白Sample Sheet在ChAMP流程中的位置——它不是一份可有可无的注释表,而是衔接原始数据与后续分析的桥梁。

我的体会是:构建Sample Sheet时宁可多花时间把每个字段核对清楚,也不要指望后面用代码“救回来”。因为后面所有步骤(质控、归一化、差异分析、可视化)都是基于这份Sample Sheet来运行的,源头出错,后面再精致的分析都会跟着错。

另外,如果你要在自己的服务器上跑一遍这个流程,建议提前检查一下R版本和Bioconductor依赖包的兼容性。ChAMP是一个依赖很多的包,在某些R版本上安装时会出现依赖冲突。我的建议是:有条件的话单独建一个conda环境或者R环境来跑ChAMP,别把系统全局的R环境搞乱了。

最后再分享一个小技巧:champ.load运行时会打印每个section的处理信息和耗时,你可以顺手把这些日志保存下来。如果后续论文的Methods部分想准确描述数据预处理流程,这份日志就是最好的参考材料,项目复盘、方法学复现都很有价值。

TCGA甲基化数据导入是整个甲基化分析流程中最繁琐、但又最不能跳过的一步。只要把Sample Sheet构建这一步做扎实,后面的分析基本就是一气呵成,不会再有太多幺蛾子。希望这篇文章能帮大家避开那些我曾经踩过的坑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询