☰
TCGA数据下载与整理全攻略:从表达矩阵到生存分析
2026/10/21 19:00:01 网站建设 项目流程

简介:这是一份癌症基因组图谱数据库(TCGA)使用教程的PDF电子书,面向生物医学研究者、生信入门学生以及需要借助公共癌症数据开展课题的分析人员,解决从数据获取、筛选到结果解析的全流程问题。资源仅包含1个PDF文件,压缩包只有12.75兆,下载后方便在任意设备上阅读。教程系统梳理了TCGA的分层数据结构,包括病例、样本、样本类型与分子数据,帮助读者理解不同样本之间的关系;重点演示如何查询特定基因的突变信息,比如单核苷酸变异和插入缺失,还能比较肿瘤组织与正常组织的基因表达差异,快速锁定潜在的关键驱动基因。同时,教程还涉及拷贝数变异、甲基化、蛋白质表达与磷酸化等多层次组学数据的下载与整合思路,指导学习者在数据平台中按癌症类型、样本类型、突变类型等条件进行高级搜索,并安全下载经脱敏处理的科研数据,为构建多维癌症模型奠定基础。该教程至今已有1150人学习,既是初学者的系统入门指南,也可供有经验的研究者随时查阅操作要点。

1. TCGA数据库到底在解决什么问题:从“没有自己的测序数据”说起

如果你做肿瘤相关研究,手头没有自己的测序样本,却想验证某个基因在癌组织中高不高表达、跟患者预后有没有关系,TCGA数据库几乎是绕不开的第一站。它把上万例癌症患者的转录组、突变、拷贝数、甲基化数据和临床随访信息集中在同一个公开平台上,让“用公开数据发文章”这件事从想法变成了常见操作。不少人下载教程后卡在同一个位置:数据是拿到了,但不知道哪些文件该用、怎么整理成能分析的表。这篇笔记就把 TCGA 从数据模型、下载方式到整理成表达矩阵和生存分析数据的完整路径讲一遍,新手能照着做,熟手可以跳着看边界和坑。

2. 从零看懂TCGA的数据模型:数据类型与下载选型

2.1 先分清四类常用数据:表达谱、突变、拷贝数与临床

打开 TCGA 的官方 GDC 门户,第一眼看到的是按“项目(Project)—样本(Case)—文件(File)”组织的三层结构。一个项目对应一个癌种,比如我们常说的某癌种项目;每个项目下有几百到上千个样本;每个样本又挂着一批数据文件。很多人第一次进去被文件列表吓到,其实常用的就四类。

数据类型常见文件内容典型用途
转录组表达谱STAR-Counts 的基因计数、FPKM、TPM 矩阵差异表达、预后基因筛选、表达与临床关联
体细胞突变突变注释文件(MAF 格式)突变图谱、高频突变基因、肿瘤突变负荷
拷贝数变异基因水平的拷贝数估计文件扩增/缺失事件、CNA 与表达联动分析
临床数据临床表格,含生存时间、分期、年龄等生存分析、分组比较、多因素 Cox 回归

以转录组表达谱为例,同一个样本在 GDC 里可能出现“STAR - Counts”“STAR - FPKM”“STAR - TPM”等不同文件。它们的区别在于定量口径:Counts 是原始计数,适合做差异表达(DESeq2、edgeR);FPKM/TPM 是归一化后的表达量,适合做基因间比较和展示。我一般建议把 Counts 作为分析主文件,FPKM/TPM 留到画热图和展示时再用。

如果是刚接触 TCGA,我通常会先明确一个问题:你到底要做什么分析?只验证一个基因的表达就下表达谱;要做突变与预后的关系才需要 MAF 文件;只做生存分析的话,临床表格加表达谱就够了。下载之前把分析目标定清楚,能省掉一大半无用功。

2.2 网页版下载:适合小样本快速取数的完整路径

当需要某个癌种全部样本的表达谱时,网页版下载其实是足够高效的。具体路径是这样走的:

第一步,进入 GDC 门户后切到 Files 页面,左侧过滤器找到“Data Category”,勾选“Transcriptome Profiling”;再在“Workflow Type”里选“STAR - Counts”。这一步的作用是把文件清单缩小到我们真正需要的基因计数文件。

第二步,在左侧继续找“Experimental Strategy”,勾选“RNA-Seq”。如果你只想要某一个癌种,在“Projects”里勾选对应项目。注意有些项目会有多个批次的数据,文件列表里会出现同一个样本在不同批次下的多个记录,这时候按“最新数据版本”过滤。

第三步,把过滤后的文件全部加入购物车。GDC 提供两种下载方式:直接下载压缩包,或者生成 manifest 清单文件。文件数量在几十个以内时,直接下载压缩包没问题;文件数量达到几百个以上,建议选 manifest,配合 GDC 客户端下载。

需要注意一个细节:勾选“STAR - Counts”时,GDC 会同时列出基因水平的 counts 文件和转录本水平的 counts 文件。前端默认展示的是基因水平文件,文件名里通常带 gene 字样,别选成转录本版本,否则后面合并矩阵时行名会变成转录本 ID,处理起来很别扭。

2.3 GDC客户端批量下载:清单文件过滤与参数说明

当你要下载一个项目的全部表达谱文件(上千个文件)时,浏览器直接下载几乎必然中断。我的习惯是:网页上生成 manifest 文件,然后用 GDC 客户端在本地批量拉取。这个过程绕不开命令行,但需要的命令其实很短。

gdc-client download -m manifest.txt -d ./tcga_data

上面这条命令的意思是:按照 manifest.txt 中列出的文件 ID,把数据下载到当前目录下的 tcga_data 文件夹。client 会自动为每个文件建立以文件 UUID 命名的子目录,原始文件和解压后的文件都放在里面。

常用参数我一般这样设:

  • -m指定 manifest 文件路径,这个文件在网页购物车里导出;
  • -d指定下载根目录,建议单独建一个目录,不要跟脚本混在一起;
  • --retry-amount设置重试次数,网络波动大时我会设成 10;
  • --n-processes设置并行下载进程数,默认 4 到 8 之间比较稳妥,开太多容易触发服务端限流。

下载完成后不要急着删 manifest,它记录了文件 UUID 与文件名的对应关系,后续整理文件时可以用来反向查错。如果下载中断了,重新执行同一条命令,client 会跳过已经完整下载的文件,只补齐缺失的部分。

3. 把下载的原始文件整理成可分析矩阵:从命名规则到表达矩阵

3.1 读懂TCGA的文件与样本命名:条形码与样本类型

下载下来的文件目录是 UUID 命名的,看不出样本信息。真正的样本标识藏在两个地方:一个是从网页下载的 metadata JSON,另一个是每个文件内部的样本条形码(barcode)。TCGA 的样本条形码有固定格式,比如 TCGA-XX-YYYY-01A-11R-A33Z-07。

这里最关键的是第四段,也就是“01”“11”这些数字。01 表示原发肿瘤,10 表示正常组织(癌旁),06 表示转移灶。在做肿瘤与正常对照的差异分析时,必须靠这段数字来分组,而不能靠文件名判断。很多人拿到数据后直接把所有样本放一起跑差异分析,结果正常样本和肿瘤样本混在一起,分组全乱。

此外,条形码第五段的字母表示样本分析类型,比如 A 表示 DNA 分析、R 表示 RNA 分析。后续合并临床信息和表达矩阵时,要保证两边用的是同一个样本条形码的完整版本,不要只取前半截做匹配,否则同一患者可能因为多次测序记录而匹配出多个条目。

3.2 用Python合并STAR-Counts为表达矩阵

每个下载文件夹里都有一个后缀为.counts.tsv的文件,里面是多列制表符格式。分别是基因 ID、基因名、基因类型以及不同方向的计数列。合并表达矩阵的原理很简单:遍历所有样本文件夹,读取每个 counts 文件,取其中的 unstranded 列作为该样本的表达量,最后把各样本的列拼到一起,行名用基因 ID。

import pandas as pd import glob import os sample_files = glob.glob("./tcga_data/*/*.counts.tsv") expr_dict = {} for f in sample_files: # 从文件路径中解析出样本条形码 barcode = os.path.basename(f).split(".")[0] df = pd.read_csv(f, sep="\t", comment="#", low_memory=False) # 只保留基因水平记录:gene_type 列通常不为空 df = df[df["gene_type"].notna()] # 提取基因 ID 和 unstranded 表达量 expr_dict[barcode] = df.set_index("gene_id")["unstranded"] expr_matrix = pd.DataFrame(expr_dict) # 过滤掉全零基因,保留在至少 20% 样本中表达量大于 10 的基因 keep = (expr_matrix > 10).sum(axis=1) >= (expr_matrix.shape[1] * 0.2) expr_matrix = expr_matrix.loc[keep] print(expr_matrix.shape)

这段代码有几个值得注意的地方。读取时用了comment="#",因为 counts 文件头部有若干行以#开头的元数据,不用这个参数会把表头解析错。取列时只取unstranded,这是 STAR 比对后未区分链方向的计数,TCGA 官方推荐用于常规表达分析。过滤条件是经验值:全零基因和极低表达基因建议直接去掉,否则后续差异分析会产生大量无意义的低表达噪声。

合并完成后,行名是 ENSG 开头的基因 ID(比如 ENSG00000000003),不方便阅读。我习惯再映射一列基因名,用文件自带的gene_name列构建映射表。这里要注意:一个 ENSG ID 可能对应多个基因名版本,映射时建议保留第一次出现的对应关系,避免重复行。

3.3 临床信息合并:从clinical.tsv提取生存时间与分组

TCGA 的临床数据同样可以从网页按项目下载,通常是clinical.tsv格式。这个表格列非常多,但真正用于生存分析的核心变量就几个:vital_status、days_to_death、days_to_last_follow_up、age_at_index、ajcc_pathologic_stage等。

clin = pd.read_csv("clinical.tsv", sep="\t", dtype=str) # 计算总生存时间:死亡患者用 days_to_death,存活患者用最后随访时间 clin["OS_time"] = clin.apply( lambda r: float(r["days_to_death"]) if r["vital_status"] == "Dead" else float(r["days_to_last_follow_up"]), axis=1 ) clin["OS_event"] = (clin["vital_status"] == "Dead").astype(int)

这段逻辑是整个生存分析的基础。很多初学者直接把days_to_death当作生存时间,结果所有存活患者的生存时间变成缺失值,样本量骤减。正确做法是:死亡患者用死亡时间,存活患者用最后随访时间,再把事件列标成 0 和 1。OS_event等于 1 表示发生了终点事件(死亡),0 表示删失。删失的意思不是患者没死,而是我们不知道他后来什么时候死的,统计上按“到随访结束时仍然活着”处理。

临床表格里的样本 ID 通常是患者在 TCGA 中的案例 ID(case ID),格式跟样本条形码不同。合并时要先通过 GDC 提供的样本-案例对应关系做一次映射,或者直接用条形码的前十二位(TCGA-XX-YYYY)作为连接键,因为同一个患者的多个样本共享前十二位。

4. TCGA使用避坑指南:样本命名、版本差异与数据缺失的三个翻车现场

4.1 样本数对不上:把“癌”和“癌旁”混进同一组了

现象:明明下载了某癌种 500 多个样本的表达谱,整理后却发现样本量比预期多或者少,差异分析结果也跟文献对不上。

原因:TCGA 项目里除了肿瘤样本,还包含一部分癌旁正常样本和转移样本。过滤条件选了整个项目后,所有样本都会混进来。如果不按条形码第四段分组,肿瘤和正常的对比就完全失去意义。

解决:拿到表达矩阵后,第一时间用条形码第四段做分组标记。01 归为肿瘤组,11 归为正常组,06 单独剔除或标记为转移组。在后续分析中始终带着这个分组列,不要靠文件名猜。

4.2 同一基因在两个版本文件里表达量差十倍:工作流没选对

现象:某同学在一个项目里下载了部分样本的 FPKM 文件,又下载了另一部分样本的 Counts 文件,合并后同一个基因在样本间的表达量差异极大,画出来的热图一塌糊涂。

原因:Counts 是原始文库计数,受测序深度影响,数值通常从几十到几万;FPKM/TPM 做了长度和深度归一化,数值一般从 0 到几百。两者混合在一起,本质上就不是同一个度量。

解决:一个分析里只用同一种工作流的数据。做差异表达统一用 STAR - Counts,做展示统一用 TPM。如果确实需要跨平台合并,先对 Counts 做 TMM 或 DESeq2 的归一化处理,不要直接拿原始值比较。

4.3 临床信息丢掉一半样本:样本条形码没有对齐到正确层级

现象:临床表格里明明有 500 行记录,跟表达谱合并后只剩 200 多行,大量样本匹配不上。

原因:临床表格的样本标识是 case ID,而表达谱列名是 sample barcode。这两者不在同一个粒度上:一个患者可能有多个样本(肿瘤和正常各一个),直接按全条形码匹配自然对不上。

解决:构建两列映射表,一列是 case ID,一列是 sample barcode。合并时先把临床表按 case ID 去重(通常一个患者保留一条临床记录),再去关联表达矩阵的样本列。我一般会保留一份从 GDC 页面导出的样本-案例映射文件,这个文件在项目页面里可以直接生成。

4.4 生存分析事件全为0:把随访时间当成了生存时间

现象:跑 KM 曲线时发现所有患者的事件列都是 0,生存曲线变成一条水平线,分组比较没有意义。

原因:临床表格里days_to_last_follow_up和days_to_death是两列互斥字段。直接用days_to_last_follow_up填所有样本,死亡患者的生存时间就变成了最后一次随访时间,事件也错标成了删失。

解决:按前一章的方式,用vital_status做条件判断,死亡取死亡时间,存活取随访时间。写完这段逻辑后立刻检查:事件为 1 的样本比例一般在 30% 到 70% 之间,如果比例低于 10%,说明事件构造大概率出了问题。

4.5 下载中断后从头再来:manifest没有保留

现象:大规模下载时网络断了,重跑 gdc-client 命令后发现之前下载的文件被重新下载一遍,时间和流量都白费。

原因:GDC 客户端确实支持断点续传,但前提是 manifest 文件不变、下载目录不变。有人换了目录名或重新导出了 manifest,客户端就把所有文件当作新任务。

解决:manifest 文件固定放在下载根目录外面,重新执行命令时保持参数完全一致。客户端检测到已有完整文件会自动跳过。另外,不建议手动移动 uuid 命名的子目录,目录结构变了也会触发重新下载。

5. 用TCGA数据快速验证一个基因的预后价值:从表达分箱到KM曲线的完整脚本

拿到整理好的表达矩阵和临床表之后,最常见的落地场景是验证某个基因是否跟患者生存有关。这一节给出一个可以完整运行的套路:取基因表达量,按中位数把样本分成高低两组,然后做 KM 曲线和 log-rank 检验。这里用lifelines库实现。

import pandas as pd from lifelines import KaplanMeierFitter from lifelines.statistics import logrank_test # expr_matrix: 行为基因, 列为样本条形码 # clin: 包含 OS_time 与 OS_event, 索引为样本条形码 gene = "GENE_SYMBOL" df = pd.DataFrame({ "expr": expr_matrix.loc[gene].values, "sample": expr_matrix.columns }).merge(clin, left_on="sample", right_index=True) # 中位数组别 median_val = df["expr"].median() df["group"] = (df["expr"] > median_val).astype(int) kmf = KaplanMeierFitter() for g in [0, 1]: mask = df["group"] == g kmf.fit( durations=df.loc[mask, "OS_time"], event_observed=df.loc[mask, "OS_event"], label=f"Group{g}" ) kmf.plot_survival_function() result = logrank_test( df.loc[df["group"] == 0, "OS_time"], df.loc[df["group"] == 1, "OS_time"], df.loc[df["group"] == 0, "OS_event"], df.loc[df["group"] == 1, "OS_event"], ) print("p-value:", result.p_value)

这段脚本的核心是中位数分组策略。它不假设表达量和风险之间存在线性关系,只是把样本分成高表达和低表达两类,所以对样本量要求相对宽松。但中位数组别也有局限:如果表达量分布严重偏斜,中位数可能把很多低表达样本和中等表达样本混在一起,这时可以改用上下三分位数分组,只保留前 30% 和后 30% 的样本。

多基因联合分析时,我一般会给每个基因单独跑一遍这段流程,输出 p 值列表,再挑出 p 值较小的基因做多因素 Cox 回归。单基因 KM 曲线适合快速筛选,多因素模型才是最终发文章时拿得出手的证据。

另外建议在跑正式分析前先做一次数据体检:检查表达矩阵是否存在全零列,临床表是否有空值,两个表的样本交集数量是否正确。这三项检查花不了两分钟,却能避免大量返工。真实项目里,我最深的体会是:TCGA 的坑大多不在统计方法上,而在数据整理的第一步。样本标识没对齐、度量类型混用、生存时间构造错误,这三个问题占了失败案例的绝大部分。希望这些步骤能帮你少走一段弯路。

本文还有配套的精品资源,点击获取

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

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

立即咨询