单细胞数据分析前期的数据预处理涉及normalization、log1p、hvg、scale、pca等一系列步骤。这些预处理步骤消除了测序深度差异,稳定了方差并压缩极端值,筛选到能够聚焦于真正携带细胞间生物学变异的高变基因以降低噪声和数据维度,平衡每个基因在降维中权重而不被高表达基因主导,并且进一步线性降维并提取数据中方差最大的主要结构,这一系列操作下来为后续的细胞聚类、类型注释和差异分析提供一份干净、可比、低维且真实反映生物学差异的数据基础。除此之外,如果数据具有批次效应,在进行下游分析之前还需要在预处理时消除批次因素以获得真正的生物学效应。
这些预处理步骤在熟知的seurat、scanpy分析流程中基本上都是常规操作,做起来不费事效果也不错,看起来平静而美好。此外,随着工具的发展,这些事情也有了不一样的选择,如利用大模型的嵌入来处理这些问题。下面将两者做一个对比:
相同点
- 降维:把每个细胞从高维表达数据压缩成低维向量。
- 无监督:不需要标签,直接对数据做变换。
- 下游通用:输出向量可用于UMAP、Leiden 聚类、分类等。
不同点
| 维度 | 常规方法 | Geneformer嵌入 |
|---|---|---|
| 线性/非线性 | 线性变换 | 非线性(Transformer 多层注意力) |
| 是否上下文感知 | 否,同一基因在所有细胞中权重固定 | 是,同一基因在不同细胞中嵌入不同 |
| 是否利用基因网络 | 否,只看表达矩阵方差 | 是,预训练学到了基因调控关系 |
| 批次稳健性 | 较弱 | 较强,对平台/患者差异更稳健 |
| 依赖外部知识 | 无,完全从当前数据学 | 依赖预训练语料和微调任务 |
总结而言,都是为了数据降维,但它利用预训练模型的嵌入属于非线性、上下文感知、依赖预训练知识的降维,能捕捉更复杂的关系,效果好坏依赖模型,模型越好越匹配任务,嵌入就越能反映真实的细胞状态差异,而常规的预处理效果仅受数据本身影响而不依赖任何外部模型。
from geneformer import EmbExtractor
embex = EmbExtractor(model_type="CellClassifier",
num_classes=3,
emb_mode='cell',
filter_data={"cell_type": ["Cardiomyocyte1","Cardiomyocyte2","Cardiomyocyte3"]},
max_ncells=1000,
emb_layer=0,
emb_label=["disease","cell_type"],
labels_to_plot=["disease"],
forward_batch_size=200,
model_version="V1",
nproc=16)
# example dataset for V1 model series: https://huggingface.co/datasets/ctheodoris/Genecorpus-30M/tree/main/example_input_files/cell_classification/disease_classification/human_dcm_hcm_nf.dataset
embs = embex.extract_embs("Geneformer-V1-10M", "human_dcm_hcm_nf.dataset", "extract_embs", "my_embs")
用模型的嵌入来替代常规的预处理,分析过程很简单,在geneformer流程里面两步就可以提取到细胞的嵌入信息。然后,用UMAP图来看一看效果:
embex.plot_embs(embs=embs, plot_style="umap", output_directory="extract_embs", output_prefix="emb_plot")

前面也说到,嵌入的效果依赖模型。从上面的图可以看出这个模型的嵌入效果不好,三种状态的细胞全部混在一起完全无法区分关注的信息。这种情况应该先微调一下模型然后再分析数据。微调后三种状态的细胞区分明显,说明嵌入学习到了细胞的状态信息。
