跳到正文
百沐一下百沐一下
本节目录

TCGA 数据获取与整理

跟完这篇,您能从 GDC 或 UCSC Xena 任选一个入口,把某个癌种的表达矩阵、临床信息和生存随访三份数据取下来,看懂 TCGA 的样本条码,并把三者按病人对齐成一套「行是样本、能直接接分析」的配套数据。

TCGA 里有什么

TCGA(The Cancer Genome Atlas)是目前最常用的公共肿瘤多组学数据库,把上万例肿瘤样本按癌种整理成 33 个项目,每个项目一个癌种,用四个字母缩写标识(如 LIHC 肝细胞癌、BRCA 乳腺癌、LUAD 肺腺癌)。每个癌种下面,同一批病人往往同时有好几种组学数据,您真正常取的是下面这几类:

数据类型内容常用于
基因表达RNA-seq 的 counts / TPM / FPKM差异表达、生存、免疫浸润
临床信息年龄、性别、分期、分级等分组、协变量
生存随访生存状态与随访时长KM 曲线、Cox 模型
体细胞突变突变清单(MAF 文件)突变分析、TMB
拷贝数变异基因/片段的扩增与缺失拷贝数分析
DNA 甲基化各位点甲基化水平表观分析

这篇只聚焦最常配套使用的前三样:表达、临床、生存。它们分开存放,取下来后要靠病人条码拼到一起——后面几节的核心就是这个「取 + 对齐」。

先看懂 TCGA 条码

TCGA 给每个样本一串条码(barcode),对齐数据全靠它,务必先看懂结构。以 TCGA-DD-AAVP-01A-11R-A41C-07 为例,用短横线分段:

片段含义
ProjectTCGA固定前缀
TSSDD组织来源机构
ParticipantAAVP病人编号
Sample + Vial01A样本类型码(01) + 份次
其余11R-A41C-07提取份、板、中心等

两条最实用的规则记牢:

  • 前 12 位 TCGA-DD-AAVP 是病人条码——临床和生存表都是按病人(每人一行)组织的,对齐时以它为准。
  • 第 14~15 位这两位数字是样本类型码,决定这管样本是肿瘤还是正常:
类型码含义
01原发实体瘤(Primary Tumor)
02复发实体瘤
06转移灶(Metastatic)
11癌旁正常组织(Solid Tissue Normal)

做「肿瘤 vs 正常」时靠这两位分组;只想留原发肿瘤,就筛 01

两个入口:GDC 还是 UCSC Xena

取 TCGA 数据主流就两个门户,各有取舍,先按下表选,再往下看对应小节。

维度GDC(配 TCGAbiolinksUCSC Xena
数据形态原始或接近原始,字段最全已归一化、整理好,开箱即用
拿原始 counts可以(STAR - Counts 即原始计数)部分数据集提供
补正常样本只有 TCGA 自带的(很少)有 TCGA + GTEx 合并队列可补
上手方式写 R 脚本下载、自己整理网页点选,直接下文本文件
适合谁要最全字段、做深入分析想快速出图、初步筛线索

一句话经验:想快点把数据取下来出图,用 Xena;要最原始、最完整的字段做深入分析,用 GDC。 两条路下面各走一遍。

GDC(Genomic Data Commons)是 TCGA 数据的官方门户,R 里用 TCGAbiolinks 按癌种、数据类型批量下载。分表达和临床两步。

第一步,取表达(原始 counts)。 走「查询 → 下载 → 整理」三个函数:

library(TCGAbiolinks)
library(SummarizedExperiment)

# 一、查询肝癌(LIHC)的 RNA-seq 表达,workflow 选 STAR - Counts 才是原始计数
query <- GDCquery(
  project       = "TCGA-LIHC",
  data.category = "Transcriptome Profiling",
  data.type     = "Gene Expression Quantification",
  workflow.type = "STAR - Counts"
)
GDCdownload(query)                    # 下载到本地
se <- GDCprepare(query)               # 整理成 SummarizedExperiment 对象

# 二、取原始计数矩阵:行 = 基因,列 = 样本条码
counts <- assay(se, "unstranded")

assay() 里除了 "unstranded"(原始 counts,做 DESeq2 用它),同一对象还带 "tpm_unstrand""fpkm_unstrand" 等归一化好的矩阵,按需要取。差异表达为什么要用原始 counts,见 表达量单位

第二步,取临床与生存字段。 GDC 的整理版临床表一个函数就够,它自带算生存所需的三个字段:

# 病人层级的临床信息,一人一行
clin <- GDCquery_clinic(project = "TCGA-LIHC", type = "clinical")

# 生存分析用的三个关键列:
#   vital_status            —— "Alive" / "Dead"
#   days_to_death           —— 死亡者:从诊断到死亡的天数
#   days_to_last_follow_up  —— 存活者:最后一次随访的天数

第三步,拼出生存表(time + event)。 生存分析要的是「随访时长 time + 结局 event(0/1)」两列,从上面字段推导:

library(dplyr)

surv <- clin %>%
  transmute(
    barcode = submitter_id,                          # 病人条码,如 TCGA-DD-AAVP
    event   = as.integer(vital_status == "Dead"),    # 1 = 死亡,0 = 删失
    time    = ifelse(vital_status == "Dead",
                     days_to_death,                  # 死亡者用到死亡的天数
                     days_to_last_follow_up)         # 存活者用到末次随访的天数
  )

这里 time 单位是,画图时想换成月常按惯例除以 30、换成年除以 365,只是换刻度、不改结论。生存分析怎么读、log-rank 和删失是怎么回事,见 生存分析入门

路线二:从 UCSC Xena 取(推荐上手)

UCSC Xena 把 TCGA 数据整理成了规整、已归一化的文本矩阵,省掉大量清洗。它的 GDC 数据中心里,每个癌种通常配好三个文件,正好对上我们要的三样:

文件(以 LIHC 为例)内容
TCGA-LIHC.htseq_counts.tsv.gz表达矩阵(多为 log2 归一化值)
TCGA-LIHC.GDC_phenotype.tsv.gz临床表型
TCGA-LIHC.survival.tsv生存表,已带 OS 与 OS.time

网页上选好数据集直接下载,本地读入即可:

# 表达矩阵:行 = 基因,列 = 样本条码;Xena 上多为已归一化的 log2 值
expr <- read.delim("TCGA-LIHC.htseq_counts.tsv.gz",
                   row.names = 1, check.names = FALSE)

# 生存表:Xena 直接给好 OS(结局 0/1)与 OS.time(天),省去自己推导
surv <- read.delim("TCGA-LIHC.survival.tsv", header = TRUE)
# 常见列:sample(样本条码)、OS、OS.time

Xena 的表达值具体是哪种归一化(log2(count+1)log2(tpm+0.001) 等),每个数据集页面的说明里都写着,用之前务必看一眼——归一化方式不同,能不能接差异表达、能不能直接比较,结论不一样。

Xena 还有一大长处:它提供把 TCGA 肿瘤与 GTEx 正常组织统一处理的合并队列,专门补 TCGA 正常样本太少的短板,是做「肿瘤 vs 正常」跨癌种图最常用的来源。用它时要记得这是两个来源拼在一起,批次差异要留个心眼,见 批次效应

三者对齐:表达、临床、生存怎么配套

不管走哪条路线,取下来的三份数据都还是各管各的,最后一步是把它们按病人对齐成一套。难点在条码位数不一致:表达矩阵的列是样本级条码(15~16 位),临床和生存表是病人级(12 位)。四步对齐:

# 1) 只留原发肿瘤:样本类型码 "01" 在条码第 14~15 位
sample_type <- substr(colnames(counts), 14, 15)
tumor <- counts[, sample_type == "01"]

# 2) 把样本级条码截成 12 位病人条码,才能跟临床/生存对上
colnames(tumor) <- substr(colnames(tumor), 1, 12)

# 3) 一个病人可能有多管样本,去重,避免同一人算两次
tumor <- tumor[, !duplicated(colnames(tumor))]

# 4) 取三者共有的病人,并把顺序对齐一致
common <- intersect(colnames(tumor), surv$barcode)
tumor  <- tumor[, common]                       # 表达按 common 排
surv   <- surv[match(common, surv$barcode), ]   # 生存表按同一顺序排

对齐后请一定做一次自查,这是最容易翻车、也最该核对的地方:

检查项期望不对时的隐患
表达列名与生存 barcode 完全一致all(colnames(tumor) == surv$barcode)TRUE顺序错位会把 A 的表达配到 B 的结局
有没有留下正常样本没剔只剩类型码 01正常样本混进「肿瘤」组,分组被污染
一人多样本是否去了重病人条码不重复同一人重复计数,样本量虚高
对齐后样本量与预期相差不大掉太多说明某份数据缺失严重

顺序对齐比「都在就行」更重要:很多下游函数(比如生存分析)默认第 i 列表达对应第 i 行生存,一旦错位,跑得出结果但全是错的。用 match()(如上)或以病人条码做键合并,别只靠「碰巧顺序一样」。对齐好的这套数据,怎么进一步整理成各分析要的规范形状,见 表达矩阵整理

常见坑与边界

TCGA 好用,但几个坑几乎人人都会踩,先知道能省很多返工:

  • 正常样本很少。 多数癌种的癌旁正常只有个位数,有的几乎没有。做「肿瘤 vs 正常」时,要么接受小样本、结论说保守些,要么用 Xena 的 TCGA + GTEx 合并队列补,但要认下批次效应这笔账。
  • 临床字段不齐、写法不一。 分期、分级等字段常有缺失,早年录入的措辞也不统一(如分期写法五花八门)。用作分组或协变量前,务必先清洗、统一取值。
  • time 有 0 或负数、缺失。 随访天数偶有异常值或缺失,进生存分析前先过滤掉 time 缺失或非正的记录。
  • 一人多样本。 同一病人可能有多管肿瘤样本(不同份、不同部位),不去重会重复计数,务必按上一节的第 3 步处理。
  • 生存终点不止一种。 上面用的是总生存(OS)。研究问题不同,可能要用无进展生存(PFI)、无病生存(DFI)等终点——社区有整理好的 TCGA 临床终点表把这些终点统一给出,做预后时按需选用,别只有 OS 一条路。
  • 别把 TCGA 结论当终点。 它是回顾性的公共队列,跨批次、跨机构,适合筛线索、提假设;真正的结论仍需独立数据集验证与实验支撑。

把这几条放在心上,取数和对齐这一关就基本稳了。

在平台上跑一遍

上面「取数据 → 看懂条码 → 三者对齐」这一整套,在百沐一下不用写代码也能做:告诉平台您要哪个癌种、要表达和生存,它会替您取数、按病人对齐、剔掉正常样本与重复,直接交给您一套能接着分析的配套数据,并附上可复现的 R 代码。您要做的,是核对癌种和分组对不对。

上手见 组学智能体使用指南,或直接开始:https://app.baimuyixia.com

相关