归一化:消除测序深度的差异
质控之后,细胞之间的 UMI 总数仍然可以相差好几倍,其中很大一部分来自液滴里的捕获效率和测序深度,而不是生物学。归一化的目的,是让不同细胞的表达可以放在一起比较。
为什么不能直接比较原始计数
设想两个同类型的细胞,基因 A 的真实表达一样。第一个细胞所在的液滴捕获效率高、分到的 reads 多,总共 6,000 个 UMI;第二个只有 3,000 个。第一个细胞里基因 A 的计数大约会是第二个的两倍。如果直接比较原始计数,这个差别会被误读成表达差异。
细胞的总 UMI 数(文库大小)混合了三种来源:液滴里的捕获和逆转录效率(第 3 章)、测序深度(第 4 章),以及细胞真实的 RNA 含量。前两种是技术噪音,第三种是生物学,但从数据里很难把它们分开。
Seurat 默认的 LogNormalize 分两步:
- 每个细胞的计数除以该细胞的总 UMI,再乘 10,000(即 CP10k):每个细胞被缩放到相同的总量。
- 取 log1p,即 log(1 + x):压缩动态范围,让高表达基因不至于主导后续分析;加 1 是为了处理 0。
obj <- NormalizeData(obj, normalization.method = "LogNormalize", scale.factor = 10000)
在 pbmc3k 上检查深度效应
组件横轴是 QC 后每个细胞的文库大小,纵轴是表达量最高的 500 个基因的平均值,左边是原始 UMI,右边是缩放到每 10,000 之后(取对数之前),并标出 Spearman 相关系数 ρ。归一化前,文库越大,表达值越高,两者几乎同步;缩放之后,这种依赖基本消失。
剩下的少量相关不一定是失败。PBMC 里单核细胞本来就比淋巴细胞大、RNA 多,文库大小有一部分是真实生物学。这也说明了归一化的代价:缩放到相同总量,同时抹掉了细胞之间真实的 RNA 含量差异。
还要注意取对数这一步。第三个面板对 log1p 之后的值画了同样的图,相关明显回升:测得浅的细胞零值更多、计数更离散,对数变换会把这种差别重新带进来。这也是 SCTransform 这类方法想要解决的问题之一。
另一种常用方法是 SCTransform:对每个基因,用正则化负二项回归把计数对测序深度建模,取 Pearson 残差作为归一化后的值。它对深度效应校正得更彻底,并且直接给出后续使用的高变基因。对主要细胞类型而言,两种方法的结果通常相近。
常见误区
- 以为归一化能去掉一切技术因素。 它处理的是总量差异,环境 RNA、批次效应和细胞组成差异都还在。
- 盲目回归 percent.mt 或 nCount_RNA。 在 ScaleData 里回归这些变量,可能连同真实的生物学一起去掉。
- 把 CP10k 当作绝对表达量。 10,000 只是一个方便的尺度,归一化值只在细胞之间相对可比。
- 用 z 分数做差异分析。 缩放后的值放大了低表达基因的噪音,不适合计算倍数变化。