预处理:10x 数据读取与质量控制(Cell Ranger)

这一节,我们聊聊 10x 数据最关键的预处理环节——Cell Ranger。不少朋友拿到原始 BCL 文件后,第一反应就是跑 cellranger count,但实际项目中我见过太多因为参数不对、参考基因组版本搞混、或者直接忽略质控报告导致后面分析全崩的情况。说白了,Cell Ranger 不只是跑个命令,更像是一个流水线质检员——你给它正确的输入,它给你可靠的表达矩阵;你给它脏数据,它只会产出误导性的结果。

Cell Ranger 的核心流程

先看整体结构。下面这张图概括了从 BCL 到基因表达矩阵的全过程:

Cell Ranger 预处理流程 BCL 原始数据 cellranger mkfastq → FASTQ cellranger count(比对 + 定量) STAR 比对(转录组) BC/UMI 校正(测序) gene × barcode 表达矩阵 web_summary.html / metrics_summary.csv

整个流水线其实就三步:BCL 转 FASTQ、比对定量、生成矩阵与报告。但每一步都有坑,我给大家拆开讲。

BCL 转换与 FASTQ 生成

如果你拿到的数据是 Illumina 原始的 BCL 格式,第一步需要用 cellranger mkfastq 拆分成 FASTQ。这步其实很简单,但要注意两个点:

  • 样本 index 的配置:必须提供正确的样本 index 序列,否则会拆错样本。我之前就见过有人把 i7 和 i5 搞反,结果所有 reads 都标成了 unknown。
  • barcode 长度:默认 10x 的 barcode 是 16bp,UMI 是 12bp。如果你用的是较新版本的 10x 试剂盒(如 3' v3),barcode 长度是 28bp,需要在 mkfastq 的参数里显式指定 --barcode-length=16,12(实际是 read1 的组成)。

命令示例:

cellranger mkfastq --id=Sample1 \
    --run=/path/to/BCL_dir \
    --samplesheet=samplesheet.csv \
    --barcode-length=16,12 \
    --localcores=8 --localmem=32
小提示:如果 BCL 数据已经由测序中心提供了 FASTQ,这一部可以跳过。但建议先看一眼 RunInfo.xml 确认 index 和 read 结构,不然直接 count 可能报错。

cellranger count 的主要参数

接下来是重头戏。我个人习惯把参数分成两类:必选参数和调优参数。

参数作用典型值
--id输出文件夹名sample_01
--transcriptome参考基因组路径(含 STAR 索引)refdata-cellranger-GRCh38-3.0.0
--fastqsFASTQ 所在目录./fastq_path
--sample样本名(匹配 FASTQ 前缀)Sample1
--expect-cells预期捕获细胞数5000
--localcoresCPU 核心数8
--localmem内存(GB)32

运行命令一般是:

cellranger count --id=MySample \
    --transcriptome=/ref/hg38/3.0.0 \
    --fastqs=/data/FASTQ \
    --sample=MY_SAMPLE \
    --expect-cells=5000 \
    --localcores=16 --localmem=64
注意:参考基因组版本必须与 Cell Ranger 版本匹配。比如 3.0 版本的 Cell Ranger 只能用 3.0 的参考包,混用会导致 STAR 索引报错。我曾经在项目里因为偷懒用了 2.0 的 ref,结果花了一天排查为什么比对率只有 40%。

核心质控指标解读

跑完后,outs/ 目录下会生成 web_summary.html(交互报告)和 metrics_summary.csv(数值表格)。我通常先看以下几个关键指标:

  1. Valid barcodes(有效 barcode 比例):正常 > 90%。如果低于 80%,可能是 barcode 长度设置错误,或者测序质量太差。
  2. Q30 bases in barcode & UMI:barcode 和 UMI 的碱基 Q30 比例,一般要求 > 90%。太低说明测序质量差,校正后有效 reads 会大量丢失。
  3. Fraction reads in cells:分配到细胞中的 reads 占比。我常看到新手只关注这个数字,其实它和期望细胞数有关,过高(> 95%)说明估计的细胞数偏少,可以适当调高 --expect-cells 重新跑。
  4. Median genes per cell:每个细胞的中位基因数。人 PBMC 样本一般在 1000-2000 之间。如果是组织样本(如肝脏、肾脏),可能在 500-1500。特别低(< 300)提示细胞活性差或测序深度不足。
  5. Sequencing saturation:测序饱和度。这个指标很实用——如果低于 40%,说明测序深度不够,可以增加 reads;如果高于 90%,说明已经饱和,再加测序也测不到更多新基因,纯属浪费钱。

下面是一个相对健康的指标示例:

Estimated Number of Cells:     5,216
Fraction Reads in Cells:       0.92
Mean Reads per Cell:           42,518
Median Genes per Cell:         1,804
Median UMI Counts per Cell:    7,231
Sequencing Saturation:         0.65
Q30 Bases in Barcode:          0.96
Q30 Bases in UMI:              0.94

过滤参数调整与避坑

Cell Ranger 自动跑的过滤已经挺成熟,但有些场景需要手动调整。比如多细胞样本或低质量样本,系统可能把真正的低质量细胞判为空液滴而剔除。我个人经验是:先看 barcode 秩图(barcode rank plot),在 web_summary.html 的“Cells”部分可以下载。

如果你发现曲线拐点不明显,说明细胞/空液滴区分模糊。这时可以尝试:

  • 调整 --expect-cells 为更合理的数值(常见错误是随便填个 3000,实际样本有 8000 个细胞)。
  • 运行完后再用 cellranger reanalyze 调整过滤参数,比如修改 min_umis 和 min_genes 阈值。

示例 reanalyze 命令:

cellranger reanalyze --id=Reanalyze1 \
    --matrix=../MySample/outs/filtered_feature_bc_matrix \
    --params=params.json

params.json 内容可手动指定:

{
  "min_umis": 500,
  "min_genes": 200,
  "min_confidence": 0.5
}
重点:不要过度过滤。我曾经在急性髓系白血病样本里把 min_genes 设成 300,结果把一大群真正的低表达白血病细胞给剔除了,导致下游肿瘤亚群分析完全失真。过滤参数需要结合领域知识来设。

多样本重复(Aggr)前的准备

如果你要对多个 10x 样本做批次校正,通常先单独跑每个样本的 cellranger count,然后用 cellranger aggr 合并。但要注意:各个样本的过滤参数不同,合并前需统一。

我习惯的做法:

  1. 对所有样本用相同的 --expect-cells(比如取所有样本中位数)。
  2. 用 cellranger count 跑完后,检查每个样本的 metrics_summary.csv 中的“Estimated Number of Cells”是否合理。
  3. 如果某个样本细胞数明显偏离预期(比如只有期望的一半),我会手动用 reanalyze 重新过滤,再导出整合矩阵。

这样到了下一讲做批次整合时,各个样本的细胞数和质量基线就比较一致了。

小技巧:所有样本的 metrics_summary.csv 可以合并到一个表格里快速对比。我通常写个 Python 脚本把指标拉平,一次扫过去就看到哪个样本需要重跑。

最后一句

预处理的质量直接决定下游整合的成败。如果你在跑完 Cell Ranger 后,发现某个样本的基因检测中位数只有 300,而其他样本都是 2000,别急着往下做——先确认是技术问题(测序深度、barcode 指定错误)还是生物问题(样本本身细胞脆弱)。这一点,值得多花一天排查。