单细胞多组学(scATAC-seq / CITE-seq / Multiome)¶
1. 一句话说明¶
单细胞多组学就是在同一个细胞里同时测量多种信息(基因表达 + 染色质开放性、基因表达 + 表面蛋白等),然后把这些信息联合分析——好比你之前只给每个学生考了"语文"一科(scRNA-seq),现在同时考了"语文 + 数学 + 英语",看到的是更完整的学生画像。
2. 单细胞多组学是什么¶
2.1 从单模态到多模态¶
前置知识回顾(第 12 篇讲过 scRNA-seq 基础,这里不再重复):
- scRNA-seq 只测了 转录组(哪些基因在表达)
- 但一个细胞的身份不只由 mRNA 决定,还取决于:
- 染色质可及性(哪些基因的开关是打开的)→ scATAC-seq
- 表面蛋白(细胞外面"穿"了什么标签)→ CITE-seq
- 两者同时测 → 10x Multiome (RNA + ATAC)
白话类比:
scRNA-seq = 只看你的"购物清单"(mRNA),猜你要做什么菜
scATAC-seq = 看你厨房里"哪些柜子是打开的"(染色质开放区域),推测你可能要用哪些食材
CITE-seq = 看你身上"穿了什么工作服"(表面蛋白),判断你是厨师还是服务员
Multiome = 同时看你的购物清单 + 哪些柜子开着(RNA + ATAC 联合测)
2.2 为什么需要多组学¶
| 单模态的局限 | 多模态怎么解决 |
|---|---|
| scRNA-seq 无法区分 CD4/CD8 T 细胞亚型(mRNA 差异小) | CITE-seq 直接测 CD4/CD8 蛋白,一目了然 |
| scRNA-seq 不知道基因调控的上游机制 | scATAC-seq 看到转录因子结合位点是否开放 |
| 分开做 scRNA-seq 和 scATAC-seq,无法确认信号来自同一个细胞 | Multiome 从同一个细胞核同时获取 RNA 和 ATAC 数据 |
| 单一维度聚类容易混淆相似细胞 | 多模态联合聚类(WNN)更精准 |
2.3 主流单细胞多组学技术一览¶
| 技术 | 测什么 | 平台 | 配对/非配对 | 发表年份 |
|---|---|---|---|---|
| CITE-seq | RNA + 表面蛋白 | 10x / Drop-seq | 配对(同一细胞) | 2017 |
| scATAC-seq | 染色质可及性 | 10x / Fluidigm | 单独测(非配对) | 2015 |
| 10x Multiome | RNA + ATAC | 10x Chromium | 配对(同一细胞核) | 2020 |
| SHARE-seq | RNA + ATAC | 定制平台 | 配对 | 2020 |
| ASAP-seq | ATAC + 表面蛋白 | 定制平台 | 配对 | 2021 |
| TEA-seq | RNA + ATAC + 蛋白 | 定制平台 | 配对(三模态) | 2021 |
3. scATAC-seq:染色质可及性分析¶
3.1 原理白话版¶
DNA 在细胞核里不是散乱的,而是缠绕在"组蛋白"上形成"染色质"。
- 染色质"松开"的区域 → 基因可以被转录 → 叫做"开放区域"(open chromatin)
- 染色质"紧缩"的区域 → 基因被锁住了 → 叫做"关闭区域"
scATAC-seq 的原理:
用一种叫 Tn5 的酶(转座酶),它只能切割"松开"的 DNA 区域。
切完之后测序,看哪些位置被切了 → 就知道哪些区域是开放的。
白话:想象一栋大楼有 1000 扇门(基因),scATAC-seq 就是派一个人去
试着推每扇门,能推开的就记录下来 → 你就知道哪些门是"开着的"。
3.2 scATAC-seq 数据特点¶
| 特点 | 说明 | 对分析的影响 |
|---|---|---|
| 极度稀疏 | 每个细胞只有 ~1-10 万个 fragments,基因组有 30 亿 bp | 比 scRNA-seq 更稀疏,需要特殊降维方法 |
| 二值化 | 每个位点要么"开"要么"关" | 不像 RNA 有连续的表达量 |
| 特征空间大 | peaks 数量通常 10-50 万个 | 需要 LSI(隐语义索引)而不是 PCA |
| 片段大小有规律 | 核小体占位约 147bp,出现周期性 | 可用于质控(TSS enrichment、nucleosome signal) |
3.3 分析流程:ArchR(R 语言)¶
ArchR (v1.0.3) 是目前最主流的 scATAC-seq 分析框架。以下是核心流程:
# ====== 安装 ArchR ======
# 需要 R >= 4.0
if (!requireNamespace("devtools", quietly = TRUE)) install.packages("devtools")
devtools::install_github("GreenleafLab/ArchR", ref="master", repos = BiocManager::repositories())
library(ArchR) # 加载 ArchR 包
set.seed(1) # 设置随机种子,保证可重复
addArchRThreads(threads = 8) # 设置并行线程数(根据你的电脑 CPU 核心数调整)
addArchRGenome("hg38") # 设置参考基因组(人类用 hg38,小鼠用 mm10)
# ====== Step 1: 创建 Arrow 文件(ArchR 的核心数据格式)======
# fragments.tsv.gz 是 10x CellRanger-ATAC 的输出文件
ArrowFiles <- createArrowFiles(
inputFiles = "fragments.tsv.gz", # 输入:片段文件
sampleNames = "PBMC", # 样本名
filterTSS = 4, # 质控:TSS 富集分数 ≥ 4(太低说明质量差)
filterFrags = 1000, # 质控:至少 1000 个 unique fragments
addTileMat = TRUE, # 创建 500bp bin 的 Tile 矩阵
addGeneScoreMat = TRUE # 创建基因活性评分矩阵(用来推断基因表达)
)
# ====== Step 2: 推断 doublet 并创建 ArchRProject ======
doubScores <- addDoubletScores(input = ArrowFiles, k = 10, knnMethod = "UMAP")
proj <- ArchRProject(ArrowFiles = ArrowFiles, outputDirectory = "output")
proj <- filterDoublets(ArchRProj = proj) # 过滤掉 doublets(一个液滴里包了两个细胞)
# ====== Step 3: 降维(Iterative LSI,而不是 PCA)======
# LSI = Latent Semantic Indexing,借鉴自文本检索领域
# scATAC 数据太稀疏,PCA 效果不好,LSI 更适合
proj <- addIterativeLSI(ArchRProj = proj, useMatrix = "TileMatrix", name = "IterativeLSI")
# ====== Step 4: 聚类和 UMAP 可视化 ======
proj <- addClusters(input = proj, reducedDims = "IterativeLSI")
proj <- addUMAP(ArchRProj = proj, reducedDims = "IterativeLSI")
# ====== Step 5: 用 Gene Score 推断细胞类型 ======
# Gene Score = 根据基因附近的 ATAC peaks 信号推断该基因的"活性"
proj <- addImputeWeights(proj) # 用 MAGIC 平滑 dropout 噪声
plotEmbedding(proj, colorBy = "GeneScoreMatrix", name = "CD14",
embedding = "UMAP", imputeWeights = getImputeWeights(proj))
# ====== Step 6: Peak Calling(识别开放区域)======
proj <- addGroupCoverages(ArchRProj = proj, groupBy = "Clusters")
proj <- addReproduciblePeakSet(ArchRProj = proj, groupBy = "Clusters")
proj <- addPeakMatrix(proj) # 创建 Peak × Cell 矩阵
# ====== Step 7: Motif 分析(找转录因子结合位点)======
proj <- addMotifAnnotations(ArchRProj = proj, motifSet = "cisbp", name = "Motif")
markerMotifs <- getMarkerFeatures(
ArchRProj = proj, useMatrix = "MotifMatrix",
groupBy = "Clusters", testMethod = "wilcoxon"
)
3.4 分析流程:Signac(R 语言,Seurat 生态)¶
Signac (v1.17.0) 是 Seurat 生态中的 scATAC-seq 分析包,和 Seurat 无缝衔接:
library(Signac) # 加载 Signac
library(Seurat) # 加载 Seurat(Signac 依赖 Seurat)
library(EnsDb.Hsapiens.v86) # 基因注释(hg38 用这个)
# ====== Step 1: 创建 ChromatinAssay ======
counts <- Read10X_h5("filtered_peak_bc_matrix.h5") # 读取 10x 输出
fragpath <- "fragments.tsv.gz" # 片段文件路径
# 获取基因注释信息
annotations <- GetGRangesFromEnsDb(ensdb = EnsDb.Hsapiens.v86)
seqlevelsStyle(annotations) <- "UCSC" # 统一染色体命名格式
# 创建 ChromatinAssay(Signac 特有的 assay 类型)
chrom_assay <- CreateChromatinAssay(
counts = counts, sep = c(":", "-"),
fragments = fragpath, annotation = annotations
)
pbmc <- CreateSeuratObject(counts = chrom_assay, assay = "peaks")
# ====== Step 2: 质控 ======
pbmc <- NucleosomeSignal(pbmc) # 计算核小体信号(应 < 4)
pbmc <- TSSEnrichment(pbmc) # 计算 TSS 富集分数(应 > 2)
pbmc <- subset(pbmc, nCount_peaks > 3000 & nCount_peaks < 30000 &
nucleosome_signal < 4 & TSS.enrichment > 2)
# ====== Step 3: 降维(TF-IDF + SVD = LSI)======
pbmc <- RunTFIDF(pbmc) # TF-IDF 归一化(替代 scRNA 的 NormalizeData)
pbmc <- FindTopFeatures(pbmc, min.cutoff = "q0") # 选择特征
pbmc <- RunSVD(pbmc) # SVD 降维(替代 PCA)
# ====== Step 4: 聚类和可视化 ======
pbmc <- RunUMAP(pbmc, reduction = "lsi", dims = 2:30) # 注意跳过第 1 维(通常与测序深度相关)
pbmc <- FindNeighbors(pbmc, reduction = "lsi", dims = 2:30)
pbmc <- FindClusters(pbmc, algorithm = 3, resolution = 0.5)
3.5 scATAC-seq 与 scRNA-seq 整合¶
当 scATAC-seq 和 scRNA-seq 来自不同的实验(非配对),需要跨模态整合:
# 用 Signac/Seurat 做跨模态整合
# 核心思想:用 Gene Activity Score(scATAC 的基因活性推断值)
# 与 scRNA-seq 的基因表达进行锚点匹配(anchor-based integration)
gene.activities <- GeneActivity(atac_obj) # 从 ATAC peaks 推断基因活性
atac_obj[["RNA"]] <- CreateAssayObject(counts = gene.activities)
atac_obj <- NormalizeData(atac_obj, assay = "RNA")
# 找到两个数据集之间的锚点
transfer.anchors <- FindTransferAnchors(
reference = rna_obj, # scRNA-seq 作为参考
query = atac_obj, # scATAC-seq 作为查询
reduction = "cca" # 用 CCA 做跨模态匹配
)
# 把 scRNA-seq 的细胞类型标签转移到 scATAC-seq 上
predicted.labels <- TransferData(
anchorset = transfer.anchors,
refdata = rna_obj$celltype, # 参考数据的细胞类型
weight.reduction = atac_obj[["lsi"]]
)
atac_obj$predicted.celltype <- predicted.labels$predicted.id
4. CITE-seq:RNA + 表面蛋白联合分析¶
4.1 原理白话版¶
CITE-seq (Cellular Indexing of Transcriptomes and Epitopes by Sequencing)
核心思想:
在做 scRNA-seq 的同时,给细胞表面的蛋白贴上"DNA 条形码抗体"。
测序时同时读到 mRNA 和这些"蛋白标签"的条形码。
白话类比:
传统 scRNA-seq = 给每个学生考语文
CITE-seq = 语文考试的同时,还用扫码枪扫了他们身上的"学生证"
(学生证上写着班级、年级等信息 = 表面蛋白类型)
具体流程:
1. 准备带 DNA 标签的抗体(antibody-derived tag, ADT)
每种抗体识别一种表面蛋白(如 CD4, CD8, CD19 等)
2. 把抗体和细胞孵育 → 抗体结合到细胞表面对应蛋白上
3. 做常规 10x scRNA-seq → 液滴里同时包含 mRNA 和抗体的 DNA 标签
4. 测序 → 同时得到基因表达矩阵 (RNA) 和蛋白丰度矩阵 (ADT)
4.2 ADT 数据处理¶
ADT(Antibody-Derived Tag)数据和 RNA 数据的处理方式不同:
library(Seurat)
# ====== 加载 CITE-seq 数据(以 Seurat bmcite 数据集为例)======
# bmcite 数据包含 30672 个骨髓细胞,25 种表面蛋白
library(SeuratData)
InstallData("bmcite") # 安装示例数据
bm <- LoadData(ds = "bmcite") # 加载数据
# 数据结构:一个 Seurat 对象里有两个 assay
# bm[["RNA"]] → 基因表达矩阵(~2 万基因)
# bm[["ADT"]] → 蛋白丰度矩阵(25 种蛋白)
# ====== RNA 的标准处理 ======
DefaultAssay(bm) <- "RNA"
bm <- NormalizeData(bm) %>% FindVariableFeatures() %>% ScaleData() %>% RunPCA()
# ====== ADT 的特殊处理 ======
DefaultAssay(bm) <- "ADT"
VariableFeatures(bm) <- rownames(bm[["ADT"]]) # ADT 通道蛋白数少,全部用作特征
bm <- NormalizeData(bm, normalization.method = "CLR", margin = 2) %>%
# CLR = Centered Log-Ratio 归一化(适合成分数据,和 RNA 不同!)
# margin = 2 表示按特征(蛋白)方向归一化
ScaleData() %>%
RunPCA(reduction.name = "apca") # 单独做 PCA,结果命名为 "apca"
关键区别:RNA vs ADT 归一化
| 对比项 | RNA 归一化 | ADT 归一化 |
|---|---|---|
| 方法 | LogNormalize (默认) | CLR (Centered Log-Ratio) |
| 原因 | RNA 是"计数"数据,log 变换稳定方差 | ADT 只有几十种蛋白,是"成分"数据 |
| 特征数 | 选 2000-3000 个高变基因 | 全部蛋白都用(通常 < 200 种) |
| 降维 | PCA | 单独 PCA(命名区别于 RNA 的 PCA) |
4.3 WNN 加权最近邻分析¶
WNN (Weighted Nearest Neighbor) 是 Seurat v4/v5 (Hao, Hao et al, Cell 2021) 提出的多模态整合核心算法。
WNN 的核心思想:
对于每个细胞,根据 RNA 和蛋白(或 ATAC)的信息含量,
自动学习每种模态的"权重",然后用加权组合构建细胞间的邻居图。
白话类比:
假设你要给学生分班:
- 有些学生的"语文成绩"更能区分他们(比如文科生),那语文权重高
- 有些学生的"数学成绩"更能区分他们(比如理科生),那数学权重高
- WNN 就是根据每个学生的具体情况,动态调整两科的权重
实际效果:
- 祖细胞(progenitor cells):RNA 权重高(因为抗体面板没有好的祖细胞标记)
- T 细胞亚群:ADT 权重高(因为 CD4/CD8 蛋白标记比 mRNA 更准确)
# ====== WNN 分析(Seurat v5 实现)======
# FindMultiModalNeighbors 是核心函数
bm <- FindMultiModalNeighbors(
bm,
reduction.list = list("pca", "apca"), # RNA 用 "pca",ADT 用 "apca"
dims.list = list(1:30, 1:18), # RNA 用前 30 个 PC,ADT 用前 18 个
modality.weight.name = "RNA.weight" # 权重存储在这个 metadata 列
)
# 该函数会生成:
# bm[["weighted.nn"]] → 加权最近邻图
# bm[["wknn"]] → WNN 的 KNN 图
# bm[["wsnn"]] → WNN 的 SNN 图(用于聚类)
# bm$RNA.weight → 每个细胞的 RNA 权重(0~1,越高说明 RNA 信息越重要)
# ====== 基于 WNN 图做 UMAP 和聚类 ======
bm <- RunUMAP(bm, nn.name = "weighted.nn", reduction.name = "wnn.umap",
reduction.key = "wnnUMAP_") # WNN UMAP
bm <- FindClusters(bm, graph.name = "wsnn", algorithm = 3, resolution = 2)
# ====== 对比三种 UMAP ======
# 1) 只用 RNA 的 UMAP
bm <- RunUMAP(bm, reduction = "pca", dims = 1:30,
reduction.name = "rna.umap", reduction.key = "rnaUMAP_")
# 2) 只用 ADT 的 UMAP
bm <- RunUMAP(bm, reduction = "apca", dims = 1:18,
reduction.name = "adt.umap", reduction.key = "adtUMAP_")
# 3) WNN UMAP(已在上面生成)
# 对比结果:WNN UMAP 通常能更清晰地分开不同细胞亚群
# RNA UMAP 在区分祖细胞方面更好
# ADT UMAP 在区分 T 细胞亚群方面更好
# WNN UMAP 结合了两者的优势
5. 10x Multiome(scRNA-seq + scATAC-seq 联合分析)¶
5.1 什么是 Multiome¶
10x Genomics Multiome ATAC + Gene Expression:
从同一个细胞核中同时获取 RNA 表达和 ATAC 信号。
关键区别:
- 分别做 scRNA-seq 和 scATAC-seq → 来自不同细胞,需要"计算整合"
- Multiome → 来自同一个细胞核,天然配对,不需要计算锚点匹配
白话:
分别做 = 两个班各考一科(语文班考语文,数学班考数学),
事后按"相似"配对 → 可能配错
Multiome = 同一个班同时考语文和数学 → 每个学生两科成绩天然对应
5.2 Multiome 分析流程(Seurat + Signac)¶
library(Seurat)
library(Signac)
library(EnsDb.Hsapiens.v86)
# ====== Step 1: 读取 10x Multiome 数据 ======
# 10x Multiome 的 filtered_feature_bc_matrix.h5 里同时包含 RNA 和 ATAC 数据
inputdata.10x <- Read10X_h5("filtered_feature_bc_matrix.h5")
rna_counts <- inputdata.10x$`Gene Expression` # 提取 RNA 计数矩阵
atac_counts <- inputdata.10x$Peaks # 提取 ATAC peaks 矩阵
# ====== Step 2: 创建多模态 Seurat 对象 ======
pbmc <- CreateSeuratObject(counts = rna_counts)
pbmc[["percent.mt"]] <- PercentageFeatureSet(pbmc, pattern = "^MT-")
# 添加 ATAC assay
annotations <- GetGRangesFromEnsDb(ensdb = EnsDb.Hsapiens.v86)
seqlevelsStyle(annotations) <- "UCSC"
chrom_assay <- CreateChromatinAssay(
counts = atac_counts, sep = c(":", "-"),
genome = "hg38", fragments = "atac_fragments.tsv.gz",
min.cells = 10, annotation = annotations
)
pbmc[["ATAC"]] <- chrom_assay # 一个对象里同时有 RNA 和 ATAC
# ====== Step 3: 质控 ======
pbmc <- subset(pbmc,
nCount_ATAC < 7e4 & nCount_ATAC > 5e3 &
nCount_RNA < 25000 & nCount_RNA > 1000 &
percent.mt < 20
)
# ====== Step 4: 分别预处理两个模态 ======
# RNA
DefaultAssay(pbmc) <- "RNA"
pbmc <- SCTransform(pbmc) %>% RunPCA() %>%
RunUMAP(dims = 1:50, reduction.name = "umap.rna")
# ATAC
DefaultAssay(pbmc) <- "ATAC"
pbmc <- RunTFIDF(pbmc) %>% FindTopFeatures(min.cutoff = "q0") %>%
RunSVD() %>% RunUMAP(reduction = "lsi", dims = 2:50,
reduction.name = "umap.atac")
# ====== Step 5: WNN 联合分析 ======
pbmc <- FindMultiModalNeighbors(pbmc,
reduction.list = list("pca", "lsi"), # RNA 用 PCA,ATAC 用 LSI
dims.list = list(1:50, 2:50) # ATAC 跳过第 1 维
)
pbmc <- RunUMAP(pbmc, nn.name = "weighted.nn",
reduction.name = "wnn.umap")
pbmc <- FindClusters(pbmc, graph.name = "wsnn", algorithm = 3)
# ====== Step 6: 联合找转录因子调控子 ======
# 关键应用:同时看 TF 的 mRNA 表达 + motif 可及性
# 如果两者都在某个细胞类型中富集 → 该 TF 很可能是该细胞类型的关键调控因子
6. 多模态整合方法¶
6.1 方法对比¶
| 方法 | 全称 | 语言 | 适用场景 | 核心思想 |
|---|---|---|---|---|
| WNN | Weighted Nearest Neighbor | R (Seurat) | CITE-seq / Multiome | 学习每个细胞每种模态的权重 |
| MOFA+ | Multi-Omics Factor Analysis v2 | R/Python | 任意多组学 | 矩阵分解,找跨模态的潜在因子 |
| MultiVI | Multi-modal Variational Inference | Python (scvi-tools) | RNA + ATAC(配对/非配对混合) | VAE 深度生成模型 |
| totalVI | Total Variational Inference | Python (scvi-tools) | CITE-seq (RNA + ADT) | VAE 联合建模 RNA 和蛋白 |
| Cobolt | - | Python | Multiome (RNA + ATAC) | 多模态 VAE |
| GLUE | Graph-Linked Unified Embedding | Python | 任意配对/非配对多模态 | 图神经网络 |
6.2 WNN(已在第 4 节详述)¶
核心优势:简单、直觉,Seurat 内置,学习曲线低。
6.3 MOFA+ (Multi-Omics Factor Analysis v2)¶
MOFA+ 做了什么:
把多种组学数据(可以是 RNA + ATAC + 蛋白 + 甲基化...任意组合)
分解成少数几个"潜在因子"(latent factors)。
白话:
假设你有一群学生,考了语文、数学、英语、物理四科。
MOFA+ 会找到几个"隐藏因子":
- 因子 1 = "理科能力"(和数学、物理成绩高度相关)
- 因子 2 = "文科能力"(和语文、英语成绩高度相关)
- 因子 3 = "整体学习态度"(和所有科目都弱相关)
每个因子同时解释多种组学的变异 → 找到跨模态的共同信号。
# ====== MOFA+ 的 Python 接口(使用 mofapy2)======
# 安装:pip install mofapy2
from mofapy2.run.entry_point import entry_point
import numpy as np
# 准备数据:list of numpy arrays,每个元素是一个组学的矩阵
# 行 = 样本/细胞,列 = 特征
data = [
[rna_matrix], # 视图 1: RNA 数据 (cells × genes)
[atac_matrix] # 视图 2: ATAC 数据 (cells × peaks)
]
# 初始化 MOFA 模型
ent = entry_point()
ent.set_data_options(scale_groups=False, scale_views=True) # 按视图标准化
ent.set_data_matrix(data, groups_names=["group1"], views_names=["RNA", "ATAC"])
ent.set_model_options(factors=10) # 设置因子数为 10
ent.set_training_options(iter=1000, seed=42)
ent.build()
ent.run()
ent.save("mofa_model.hdf5") # 保存模型
6.4 MultiVI(scvi-tools)¶
MultiVI 专门处理 scRNA-seq + scATAC-seq 的混合数据(配对和非配对都行):
# ====== MultiVI 分析流程 ======
# 安装:pip install scvi-tools
import scvi
import anndata as ad
# 输入数据:
# - adata_multi: 配对的 Multiome 数据(同一细胞有 RNA + ATAC)
# - adata_rna: 只有 RNA 的数据
# - adata_atac: 只有 ATAC 的数据
# 合并所有数据
adata = ad.concat([adata_multi, adata_rna, adata_atac])
# 设置 MultiVI 模型
scvi.model.MULTIVI.setup_anndata(adata, batch_key="modality")
model = scvi.model.MULTIVI(adata, n_genes=2000, n_regions=2000)
model.train(max_epochs=500) # 训练 VAE 模型
# 获取联合潜在空间
latent = model.get_latent_representation() # 所有细胞的联合 embedding
adata.obsm["X_multivi"] = latent
# 在联合空间中做下游分析
import scanpy as sc
sc.pp.neighbors(adata, use_rep="X_multivi") # 基于联合 embedding 找邻居
sc.tl.umap(adata) # UMAP 可视化
sc.tl.leiden(adata) # 聚类
7. 常用工具速查¶
7.1 R 生态¶
| 工具 | 用途 | 版本 | 依赖 |
|---|---|---|---|
| ArchR | scATAC-seq 全流程分析 | 1.0.3 | R ≥ 4.0 |
| Signac | scATAC-seq 分析(Seurat 生态) | 1.17.0 | Seurat v5 |
| Seurat v5 | 多模态单细胞分析框架(WNN) | 5.4.0 | R ≥ 4.0 |
| chromVAR | 转录因子 motif 可及性评分 | Bioconductor | GenomicRanges |
7.2 Python 生态¶
| 工具 | 用途 | 安装 |
|---|---|---|
| muon | 多模态单细胞分析框架(MuData 数据结构) | pip install muon |
| scvi-tools | MultiVI/totalVI 等深度学习模型 | pip install scvi-tools |
| mofapy2 | MOFA+ 的 Python 接口 | pip install mofapy2 |
| episcanpy | scATAC/甲基化的 Scanpy 扩展 | pip install episcanpy |
| SnapATAC2 | 大规模 scATAC-seq 分析 | pip install snapatac2 |
7.3 muon 简介¶
muon 是 Python 生态中处理多模态单细胞数据的框架,核心数据结构是 MuData:
import muon as mu
# MuData = 多模态 AnnData 的容器
# 每个模态是一个 AnnData,共享同一批细胞
mdata = mu.read_10x_h5("filtered_feature_bc_matrix.h5") # 读取 10x Multiome 数据
# mdata.mod["rna"] → RNA 的 AnnData
# mdata.mod["atac"] → ATAC 的 AnnData
# RNA 预处理
mu.pp.intersect_obs(mdata) # 保留两个模态都有的细胞
sc.pp.normalize_total(mdata.mod["rna"])
sc.pp.log1p(mdata.mod["rna"])
# ATAC 预处理
mu.atac.pp.tfidf(mdata.mod["atac"])
mu.atac.tl.lsi(mdata.mod["atac"])
# WNN 分析(muon 也实现了 WNN)
mu.pp.neighbors(mdata, key_added="wnn")
mu.tl.umap(mdata, neighbors_key="wnn")
8. 面试怎么答¶
Q1:scATAC-seq 和 scRNA-seq 有什么区别?¶
scRNA-seq 测的是基因的 表达量(mRNA),告诉你"哪些基因正在被读取"。scATAC-seq 测的是染色质的 开放性(chromatin accessibility),告诉你"哪些基因的'开关'是打开的"。
打个比方,RNA-seq 看的是"工厂正在生产什么产品",ATAC-seq 看的是"工厂的哪些生产线是开着的"——一个基因的开关打开了,不代表它一定在生产(还需要转录因子来启动),但开关关着的基因一定不会生产。
分析上的核心区别:scATAC-seq 数据极度稀疏(每个细胞只有数万个 fragments),所以用 LSI 降维而不是 PCA,用 TF-IDF 归一化而不是 LogNormalize。
Q2:CITE-seq 的 ADT 数据和 RNA 数据为什么要用不同的归一化方法?¶
RNA 数据有 ~2 万个基因,服从近似的负二项分布,LogNormalize 或 SCTransform 都适合。但 ADT 数据通常只有几十到几百种蛋白,属于"成分数据"(compositional data),不同蛋白的表达量范围差异极大,所以要用 CLR (Centered Log-Ratio) 归一化,它能处理成分数据的"总量效应"问题。
另外,RNA 通常选 2000-3000 个高变基因做下游分析,而 ADT 因为蛋白数量本身就少(通常全部使用),不需要做特征选择。
Q3:什么是 WNN?它比单模态分析好在哪里?¶
WNN (Weighted Nearest Neighbor) 是 Seurat v4 提出的多模态整合框架。它的核心思想是为每个细胞、每种数据模态学习一个权重值,然后用加权组合构建邻居图。
比单模态好在:不同细胞在不同模态中的信息含量不同。比如分析 CITE-seq 时,T 细胞的 ADT 数据更有区分度(CD4/CD8 蛋白标记明确),而祖细胞的 RNA 数据更有区分度(抗体面板缺少祖细胞标记)。WNN 能根据每个细胞的具体情况,动态地给 RNA 和蛋白分配不同的权重,从而达到"哪个模态在当前细胞更有用,就更信任哪个"的效果。
Q4:10x Multiome 和分别做 scRNA-seq + scATAC-seq 有什么优缺点?¶
Multiome 的优势: - 数据天然配对——RNA 和 ATAC 来自同一个细胞核,不需要计算整合,避免了配对误差 - 可以直接关联一个基因的"表达量"和它的"启动子开放性" - 可以找到"表达升高 + motif 开放"的转录因子 → 更可靠地推断关键调控因子
Multiome 的劣势: - 成本更高(试剂贵,一次只能做一种方案) - 从细胞核而非完整细胞提取 → 会丢失一些胞质 mRNA - RNA 数据质量通常比纯 scRNA-seq 稍低(基因检测数较少)
分别做的优势:灵活,已有数据可以直接复用,各自优化实验条件。 分别做的劣势:需要计算整合,存在配对误差,无法确认信号来自同一个细胞。
Q5:如果让你分析一个 CITE-seq 数据集,你的流程是什么?¶
- 数据加载:用 Seurat 的
Read10X或Read10X_h5读取,确认有 RNA 和 ADT 两个 assay- 质控:RNA 看 nFeature_RNA、nCount_RNA、percent.mt;ADT 看 nCount_ADT 和 isotype control
- RNA 预处理:NormalizeData → FindVariableFeatures → ScaleData → RunPCA
- ADT 预处理:CLR 归一化(
NormalizeData(method='CLR', margin=2))→ 全部蛋白作为特征 → ScaleData → 单独 RunPCA(命名为 apca)- WNN 整合:
FindMultiModalNeighbors学习每个细胞的模态权重- 下游分析:基于 WNN 图做 UMAP、聚类、差异表达
- 结果验证:对比 RNA-only UMAP、ADT-only UMAP 和 WNN UMAP;检查权重分布是否合理(T 细胞 ADT 权重高,祖细胞 RNA 权重高)
9. 速查表¶
9.1 技术选择决策树¶
你想测什么?
├── 只测染色质开放性 → scATAC-seq(ArchR 或 Signac)
├── 基因表达 + 表面蛋白 → CITE-seq(Seurat WNN)
├── 基因表达 + 染色质开放性(同一细胞)→ 10x Multiome(Seurat+Signac WNN)
├── 基因表达 + 染色质开放性(不同细胞)→ 计算整合(Signac transfer / MultiVI)
└── 三模态或更多 → TEA-seq / MOFA+ / GLUE
9.2 分析方法选择¶
你的数据类型?
├── CITE-seq (RNA + ADT)
│ ├── Seurat WNN(R,首选)
│ ├── totalVI(Python, scvi-tools)
│ └── muon WNN(Python)
├── 10x Multiome (RNA + ATAC,配对)
│ ├── Seurat + Signac WNN(R,首选)
│ ├── ArchR + scRNA 整合(R)
│ ├── MultiVI(Python)
│ └── muon(Python)
├── 非配对 scRNA + scATAC
│ ├── Signac 的 TransferData(R)
│ ├── MultiVI(Python, 推荐)
│ └── GLUE(Python)
└── 多个组学(≥3 种)
├── MOFA+(R/Python)
└── GLUE(Python)
9.3 降维方法对应关系¶
| 数据类型 | 归一化 | 降维 | 第一维是否去掉 |
|---|---|---|---|
| scRNA-seq | LogNormalize / SCTransform | PCA | 不去 |
| scATAC-seq | TF-IDF | LSI (SVD) | 去掉第 1 维(和深度相关) |
| ADT (CITE-seq) | CLR | PCA | 不去 |
9.4 关键函数速查¶
| 任务 | Seurat/Signac (R) | Scanpy/muon (Python) |
|---|---|---|
| 读取 Multiome 数据 | Read10X_h5() | mu.read_10x_h5() |
| ATAC 归一化 | RunTFIDF() | mu.atac.pp.tfidf() |
| ATAC 降维 | RunSVD() | mu.atac.tl.lsi() |
| ADT 归一化 | NormalizeData(method='CLR') | mu.prot.pp.clr() |
| WNN 整合 | FindMultiModalNeighbors() | mu.pp.neighbors() |
| WNN UMAP | RunUMAP(nn.name="weighted.nn") | mu.tl.umap() |
| Peak Calling | CallPeaks() / ArchR | macs2 (外部工具) |
| Motif 分析 | RunChromVAR() | mu.atac.tl.rank_peaks_groups() |
10. 延伸资源¶
10.1 官方文档与教程¶
| 资源 | 链接 | 说明 |
|---|---|---|
| ArchR 完整手册 | archrproject.com | scATAC-seq 全流程(R) |
| Signac 教程 | stuartlab.org/signac | scATAC-seq + Seurat 生态(R) |
| Seurat WNN 教程 | satijalab.org/seurat | CITE-seq 和 Multiome 的 WNN 分析(R) |
| muon 教程 | muon-tutorials.readthedocs.io | Python 多模态分析 |
| scvi-tools MultiVI | docs.scvi-tools.org | 深度学习多模态整合(Python) |
| MOFA+ 文档 | biofam.github.io/MOFA2 | 多组学因子分析 |
10.2 关键论文¶
| 论文 | 期刊/年份 | 内容 |
|---|---|---|
| Stoeckius et al. (CITE-seq) | Nat Methods 2017 | CITE-seq 技术原始论文 |
| Buenrostro et al. (scATAC-seq) | Nature 2015 | scATAC-seq 技术原始论文 |
| Hao, Hao et al. (WNN) | Cell 2021 | WNN 方法 + Seurat v4 |
| Granja et al. (ArchR) | Nat Genet 2021 | ArchR 工具论文 |
| Stuart, Butler et al. | Cell 2019 | Seurat v3 多模态整合 |
| Argelaguet et al. (MOFA+) | Genome Biol 2020 | MOFA+ 方法论文 |
| Ashuach et al. (MultiVI) | Nat Methods 2023 | MultiVI 方法论文 |
10.3 与本知识库其他篇目的联系¶
| 篇目 | 关系 |
|---|---|
| 12_单细胞分析入门_Scanpy | 前置知识:scRNA-seq 基础(本篇不重复) |
| 18_多组学整合分析入门 | 讲 bulk 多组学整合,本篇聚焦单细胞多模态 |
| 33_表观基因组学入门_ChIP-seq_ATAC-seq | 讲 bulk ATAC-seq 原理,本篇讲单细胞 ATAC |
| 40_空间转录组分析 | 单细胞的空间维度扩展 |
本篇定位:在已掌握 scRNA-seq 基础(第 12 篇)的前提下,学习如何从单一模态跨越到多模态单细胞分析,掌握 scATAC-seq、CITE-seq、Multiome 的原理与分析流程,以及 WNN、MOFA+、MultiVI 等整合方法。面试中遇到"单细胞多组学"相关问题时,能从原理、流程、工具三个层面给出有条理的回答。