4. 空间转录组数据预处理:质控、标准化与高变基因选择
预处理这个环节,我把它比作「地基中的地基」。你想想看,如果原始数据里掺了大量空点、死细胞或者批次噪音,后面再花哨的校正算法也救不回来。我个人习惯把预处理拆成三个递进阶段:质控过滤、标准化、高变基因选择。下面逐一拆开细讲。
一句话核心:预处理的目的不是「让数据变好看」,而是剔除技术噪音、保留真实的生物学信号,为后续批次校正和空间分析铺路。
4.1 质控过滤:先清理,再分析
说白了,质控就是三件事:切面对齐对不对、点质量够不够好、是不是空点。我在项目中见过不少人跳过组织对齐检查,直接跑标准化,结果一半「组织点」实际上是载玻片背景,后续差异分析全是假阳性。
4.1.1 组织切片与对齐检查
拿到空间数据,第一件事不是跑代码,而是看组织切片图像。10x Visium 会给你一张 H&E 或免疫荧光染色图,你得确认组织覆盖区域和捕获点阵是对齐的。我记得有一次,切片边缘有一块折叠组织,软件自动识别时把折叠区域也算进去了,那部分的基因表达完全失真。
- 组织掩膜:手动或自动勾勒组织边界,排除空白区域
- 对齐偏差:如果图像坐标与捕获点坐标偏移超过 1-2 个点直径,需要重新配准
- 组织碎片:直径小于 3 个点的组织碎片建议剔除
4.1.2 点级别 QC 指标
每个捕获点的质量,主要看三个指标。我习惯先画一组小提琴图,直观判断阈值。
| 指标 | 含义 | 常见阈值范围 | 异常信号 |
|---|---|---|---|
| nCount_Spatial | 每个点的总 UMI 数 | 500 – 15000 | 过低→空点;过高→双点或组织堆积 |
| nFeature_Spatial | 每个点检测到的基因数 | 200 – 5000 | 过低→RNA 降解或空点 |
| percent.mito | 线粒体基因 UMI 占比 | < 20% | 过高→细胞受损或凋亡 |
注意:阈值不是死的!不同组织类型、不同平台差异很大。比如 Slide-seq 数据 UMI 深度通常比 Visium 低一个数量级,硬套 Visium 的阈值会丢掉大量有效点。
这是我常用的一段 QC 过滤代码:
# R / Seurat — 点级QC
sp_data <- subset(sp_data,
subset = nCount_Spatial > 500 &
nFeature_Spatial > 200 &
percent.mito < 20)
# 可视化检查
VlnPlot(sp_data, features = c("nCount_Spatial",
"nFeature_Spatial", "percent.mito"),
pt.size = 0.1)
4.1.3 空点与背景点识别
空间转录组特有的一个坑:捕获点覆盖了组织,但也可能覆盖了载玻片上的背景区域。我曾经遇到一个项目,空点比例高达 30%,这些空点的基因表达谱其实是载玻片上的残留 RNA 或者环境菌群。怎么筛?
- UMI 绝对阈值:nCount_Spatial < 200 直接标记为空点
- 与组织图像交叉验证:点坐标是否落在组织掩膜内
- 空点评分模型:用 SpotClean 或 EmptyDrops 方法,基于背景 RNA 分布做概率判断
小技巧:筛选完空点后,建议保留原始计数矩阵中空点的数据作为「背景信号分布」,后续去卷积或反卷积分析时能用上。
4.2 标准化:让不同切片具有可比性
标准化要解决的核心问题——不同切片、不同捕获区域的测序深度不一样。你想想看,一张切片测了 15 万 UMI,另一张只测了 5 万,直接比较原始计数就是刻舟求剑。
我个人最常用的两种方法,对比在这里:
| 方法 | 数学本质 | 适用场景 | 注意事项 |
|---|---|---|---|
| LogNormalize | log(CPM + 1) | 快速、稳妥,适合大多数空间数据 | 对高表达基因有压缩,但丢失零膨胀结构 |
| SCTransform | 正则化负二项回归 | 数据稀疏性高、存在批次效应时 | 计算量大,但能保留更多生物学变异 |
| Pearson残差 | 基于预测值的残差 | 需要去除测序深度影响时 | 对异常值敏感,建议配合 HVG 使用 |
标准化的代码实现很简单,但参数选择有讲究:
# LogNormalize(默认scale.factor=10000)
sp_data <- NormalizeData(sp_data,
normalization.method = "LogNormalize",
scale.factor = 10000)
# SCTransform(推荐在QC后直接运行)
sp_data <- SCTransform(sp_data,
vars.to.regress = "percent.mito",
verbose = FALSE)
我的建议:如果后续要做批次校正(比如 Harmony、Seurat CCA),优先用 SCTransform。它内置了方差稳定化,高变基因筛选的准确率会比 LogNormalize 高出不少。我对比过多次,SCTransform 选出的基因在空间模式上更清晰。
4.3 高变基因选择:把精力花在刀刃上
空间转录组通常会检测 1-3 万个基因,但真正有空间表达模式的只有几百到两千个。高变基因选择的目的,就是找出这些「信息量最大」的基因,降维和聚类时才能看到结构。说白了,就是让你的计算资源用在正确的地方。
4.3.1 三种主流选择策略
- vst(方差稳定变换):Seurat 默认方法,速度快、普适性好,适合大多数空间数据
- dispersion(离散度):基于均值-方差关系,对低表达基因灵敏,但容易被高表达基因主导
- 空间特异性选择:用 Moran's I 或 SPARK-X 检测具有空间自相关的基因,计算量大但针对性最强
# vst 方法 —— 选2000个
sp_data <- FindVariableFeatures(sp_data,
selection.method = "vst",
nfeatures = 2000)
# 空间特异性方法(SPARK-X)
# sparkx_results <- sparkx(counts, location,
# numCores = 4)
# hvgs_spatial <- rownames(
# sparkx_results[sparkx_results$adjusted_pvalue < 0.05, ])
4.3.2 选多少个合适?
这个问题没有标准答案。我遇到过选 500 个聚类没结构,选 5000 个又跑不动的尴尬。一般来说:
- 10x Visium:1500 – 3000 个
- Slide-seq / Stereo-seq:2000 – 5000 个(数据更稀疏)
- 空间特异性基因:通常 200 – 800 个(严格筛选)
我曾经踩过的坑:为了追求「信息量」,我把高变基因数拉到 5000,结果后续 PCA 和 UMAP 不仅慢,还出现了明显的技术噪音聚类。后来发现是选入了大量核糖体基因和线粒体基因——这些基因在多数条件下都高表达,并不代表空间异质性。建议在筛选前先去除 RPS、RPL、MT- 等基因家族。
4.4 预处理流程在批次校正中的角色
到这里,你可能会问:「预处理和批次校正到底什么关系?」简单回答:预处理是批次校正的前置条件。如果每张切片单独做 QC、标准化、选 HVG,然后合并起来跑校正,效果远好于把原始计数直接合起来再处理。我试过两种路径,前者在校正后的 LISI 指标和生物分离度上都有明显优势。
具体操作时,我建议对每个样本独立完成以下步骤,再进入合并校正阶段:
- 独立 QC(阈值可以统一,但要检查每张切片的质量分布)
- 独立标准化(推荐 SCTransform)
- 独立高变基因选择(每张切片选 2000 个,然后取并集)
- 合并所有样本的标准化表达矩阵,开始批次校正
高效工作流:用 split() + lapply() 把三步骤写成函数,一行代码跑完所有样本的预处理,再 merge() 合并。千万别手动一张一张处理,既慢又容易出错。
预处理做扎实了,后续的批次校正才能放心。下一阶段我们会正式进入校正方法的实战对比,到时候你会看到,预处理质量直接决定了校正结果的上下限——这个关系,我希望你在自己的数据集上也验证一次。