Seurat v5 数据整合分析教程¶
基于 Seurat v5.5.1 官方教程,系统学习多批次单细胞数据的整合分析。
使用 PBMC 3k 数据模拟批次效应,完整演示 CCA / RPCA 整合、保守 Marker、跨批次差异表达等核心流程。
目录¶
- 1. 背景与原理
- 2. 模拟批次效应
- 3. 未整合分析(展示批次效应)
- 4. CCA 整合
- 5. 整合前后对比
- 6. 细胞类型注释
- 7. 保守 Marker 基因(FindConservedMarkers)
- 8. 跨批次差异表达(FindMarkers)
- 9. RPCA 整合与 CCA 对比
- 10. 总结与核心知识点
- 附录: 完整脚本
1. 背景与原理¶
1.1 为什么需要数据整合?¶
在单细胞实验中,不同批次的样本由于技术差异(捕获效率、测序深度、试剂批次等)会产生批次效应。如果不进行整合,批次效应会导致:
- 相同细胞类型因批次不同而被分到不同聚类
- 批次特异的技术噪声干扰生物学信号
- 跨批次比较不可靠
1.2 Seurat v5 整合核心特性¶
Seurat v5 引入了 layers 机制,可以在一个 Seurat 对象中管理多个批次的数据,无需创建多个对象:
| 操作 | 函数 | 说明 |
|---|---|---|
| 按批次分割 | split(pbmc[["RNA"]], f = pbmc$batch) |
将 counts 分为多个 layer |
| 整合 | IntegrateLayers(method = CCAIntegration) |
一行代码完成整合 |
| 合并 | JoinLayers(pbmc[["RNA"]]) |
整合后合并回单 layer |
1.3 两种整合方法对比¶
| 方法 | 函数 | 特点 | 适用场景 |
|---|---|---|---|
| CCA | CCAIntegration |
经典方法,整合力度大 | 批次差异大、需要彻底去除批次效应 |
| RPCA | RPCAIntegration |
更快更保守 | 批次差异小、希望保留更多生物学变异 |
2. 模拟批次效应¶
由于官方 ifnb 数据集(394MB)下载过慢,本教程使用已有的 PBMC 3k 数据,通过人为分割模拟两个「批次」。
2.1 数据准备¶
# 读取原始 10X 数据
pbmc_data <- Read10X(data.dir = data_dir)
pbmc <- CreateSeuratObject(counts = pbmc_data, project = "pbmc3k",
min.cells = 3, min.features = 200)
# QC 过滤
pbmc <- PercentageFeatureSet(pbmc, pattern = "^MT-", col.name = "percent.mt")
pbmc <- subset(pbmc, subset = nFeature_RNA > 200 & nFeature_RNA < 2500 & percent.mt < 5)
# 过滤后细胞数: 2638
2.2 随机分批 + 添加技术偏差¶
# 随机分为两个批次
set.seed(42)
pbmc$batch <- sample(c("batch1", "batch2"), size = ncol(pbmc), replace = TRUE)
# batch1: 1348 个细胞 | batch2: 1290 个细胞
# 为 batch2 添加技术偏差:
# 1) 乘法噪声(0.7-1.3 的基因特异噪声因子,模拟不同捕获效率)
# 2) Dropout 500 个基因的 30% 细胞(模拟检测率差异)
2.3 分割 Layers(Seurat v5 核心)¶
# 按 batch 分割 RNA assay 的 counts layer
pbmc[["RNA"]] <- split(pbmc[["RNA"]], f = pbmc$batch)
# 分割后 pbmc 对象包含 counts.batch1 和 counts.batch2 两个 layer
3. 未整合分析(展示批次效应)¶
对每个 layer 独立进行标准流程(归一化、找高变基因、PCA),展示未整合时的批次效应。
pbmc <- NormalizeData(pbmc)
pbmc <- FindVariableFeatures(pbmc)
pbmc <- ScaleData(pbmc)
pbmc <- RunPCA(pbmc)
pbmc <- FindNeighbors(pbmc, dims = 1:30, reduction = "pca")
pbmc <- FindClusters(pbmc, resolution = 0.8, cluster.name = "unintegrated_clusters")
pbmc <- RunUMAP(pbmc, dims = 1:30, reduction = "pca", reduction.name = "umap.unintegrated")
3.1 未整合 UMAP - 按批次着色¶
可以清楚看到,两个批次在 UMAP 空间中明显分离,这就是批次效应。
3.2 未整合 UMAP - 按聚类着色¶
聚类结果受批次效应影响,相同细胞类型可能被分到不同聚类。
3.3 未整合 - 按批次分割¶
用 split.by 参数分面展示,更直观地看到两个批次的分布差异。
4. CCA 整合¶
4.1 一行代码完成整合¶
Seurat v5 的 IntegrateLayers 函数封装了整个整合流程:
pbmc <- IntegrateLayers(
object = pbmc,
method = CCAIntegration,
orig.reduction = "pca",
new.reduction = "integrated.cca",
verbose = FALSE
)
CCA 整合原理:
1. 在两个批次之间寻找典型相关分析(CCA)的「锚点」对
2. 基于锚点对计算批次校正向量
3. 将校正后的数据投影到新的降维空间(integrated.cca)
4.2 合并 Layers 并重新聚类¶
# 整合后必须合并 layers
pbmc[["RNA"]] <- JoinLayers(pbmc[["RNA"]])
# 基于整合后的降维结果聚类
pbmc <- FindNeighbors(pbmc, reduction = "integrated.cca", dims = 1:30)
pbmc <- FindClusters(pbmc, resolution = 0.5, cluster.name = "cca_clusters")
pbmc <- RunUMAP(pbmc, dims = 1:30, reduction = "integrated.cca", reduction.name = "umap.cca")
4.3 整合后 UMAP - 按批次着色¶
整合后,两个批次在 UMAP 空间中充分混合,批次效应已消除。
4.4 整合后 UMAP - 按聚类着色¶
聚类结果不再受批次影响,相同细胞类型被正确归入同一聚类。
4.5 整合后 - 按批次分割¶
分面展示可以看到两个批次的细胞类型分布高度一致。
5. 整合前后对比¶
5.1 按批次着色对比¶
左:未整合(批次明显分离)| 右:CCA 整合后(批次充分混合)
5.2 按聚类着色对比¶
左:未整合聚类(受批次影响)| 右:整合后聚类(反映真实细胞类型)
6. 细胞类型注释¶
6.1 寻找各聚类 Marker 基因¶
pbmc.markers <- FindAllMarkers(pbmc, only.pos = TRUE, min.pct = 0.25, logfc.threshold = 0.25)
top_markers <- pbmc.markers %>%
group_by(cluster) %>%
slice_max(n = 5, order_by = avg_log2FC)
各聚类 top 5 marker(示例):
| 聚类 | Top Markers | 细胞类型 |
|---|---|---|
| 0 | CD3D, CCR7, CD3E, LDHB, CD7 | Naive CD4 T |
| 1 | IL32, CD3D, CD3E, IL7R, CD2 | Memory CD4 T / T 细胞 |
| 2 | LYZ, S100A9, S100A8 | CD14+ Mono |
| 3 | MS4A1, CD79A, CD79B | B 细胞 |
| 4 | CD8A, GZMK, CCL5 | CD8 T |
| 5 | FCGR3A, MS4A7 | FCGR3A+ Mono |
| 6 | GNLY, NKG7, KLRD1 | NK |
| 7 | FCER1A, CST3, LST1 | DC |
| 8 | PPBP, PF4 | Platelet |
6.2 注释后 UMAP¶
new.cluster.ids <- c("Naive CD4 T", "CD14+ Mono", "Memory CD4 T", "B",
"CD8 T", "FCGR3A+ Mono", "NK", "DC", "Platelet")
names(new.cluster.ids) <- levels(pbmc)
pbmc <- RenameIdents(pbmc, new.cluster.ids)
pbmc$cell_type <- Idents(pbmc)
6.3 Marker FeaturePlot¶
经典 marker 基因在 UMAP 空间的表达分布:
FeaturePlot(pbmc, features = c("IL7R", "CD14", "MS4A1", "CD8A", "GNLY", "FCGR3A"),
reduction = "umap.cca", ncol = 3)
- IL7R: CD4 T 细胞
- CD14: 单核细胞
- MS4A1: B 细胞
- CD8A: CD8 T 细胞
- GNLY: NK 细胞
- FCGR3A: FCGR3A+ 单核细胞
7. 保守 Marker 基因(FindConservedMarkers)¶
7.1 原理¶
FindConservedMarkers 在两个批次中分别寻找某聚类的 marker 基因,然后用 meta-analysis 合并 p 值,找到不受批次效应影响的稳定 marker。
7.2 核心代码¶
# 注意:FindConservedMarkers 需要 layers 处于合并状态
pbmc[["RNA"]] <- JoinLayers(pbmc[["RNA"]])
Idents(pbmc) <- "cca_clusters"
# 选择最大的聚类进行分析
conserved_markers <- FindConservedMarkers(
pbmc,
ident.1 = target_cluster, # 聚类1
grouping.var = "batch", # 按批次分组
verbose = FALSE
)
7.3 结果解读¶
聚类1(T 细胞)的保守 marker 基因(前 15 个):
| 基因 | batch2 avg_log2FC | batch1 avg_log2FC | 说明 |
|---|---|---|---|
| IL32 | 1.457 | 1.153 | T 细胞活化标志 |
| CD3D | 1.056 | 1.067 | T 细胞受体组件 |
| CD3E | 1.052 | 1.052 | T 细胞受体组件 |
| IL7R | 1.260 | 1.711 | CD4 T 细胞标志 |
| CD2 | 1.848 | 1.389 | T 细胞粘附分子 |
| LDHB | 0.970 | 1.038 | 代谢酶(泛表达) |
| LTB | 1.235 | 1.438 | 淋巴毒素 |
| LCK | 0.957 | 0.682 | T 细胞信号转导 |
| AQP3 | 1.826 | 2.623 | 水通道蛋白(T 细胞活化) |
| PRDX2 | 1.185 | 0.871 | 抗氧化蛋白 |
这些基因在两个批次中都显著高表达,说明它们是稳定的生物学 marker,不受批次效应影响。
7.4 保守 Marker 可视化¶
小提琴图(按批次分割):展示 top 6 保守 marker 在两个批次中的表达一致性。
VlnPlot(pbmc, features = top_conserved, split.by = "batch", pt.size = 0, ncol = 3)
DotPlot(按批次分割):展示 top 12 保守 marker 的表达比例和水平。
DotPlot(pbmc, features = markers_to_plot, split.by = "batch") + RotatedAxis()
8. 跨批次差异表达(FindMarkers)¶
8.1 目的¶
比较同一细胞类型在两个批次中的差异表达基因,用于识别:
- 技术偏差导致的假阳性差异
- 真实的生物学差异(如果有处理条件不同)
8.2 核心代码¶
# 创建 celltype.batch 组合变量
pbmc$celltype.batch <- paste(pbmc$cell_type, pbmc$batch, sep = "_")
Idents(pbmc) <- "celltype.batch"
# 比较第一个共有细胞类型的两个批次
de_genes <- FindMarkers(pbmc, ident.1 = "Cluster0_batch2", ident.2 = "Cluster0_batch1")
8.3 结果解读¶
跨批次差异基因(top 10):
| 基因 | avg_log2FC | pct.1 | pct.2 | 说明 |
|---|---|---|---|---|
| B2M | -0.722 | 1.0 | 1.0 | MHC-I 组件(技术偏差) |
| RPL15 | -0.634 | 1.0 | 1.0 | 核糖体蛋白(技术偏差) |
| RPL13 | -0.558 | 1.0 | 1.0 | 核糖体蛋白(技术偏差) |
| TMSB4X | -0.419 | 1.0 | 1.0 | 肌动蛋白结合(技术偏差) |
| RPL19 | -0.487 | 1.0 | 1.0 | 核糖体蛋白(技术偏差) |
| RPL3 | -0.468 | 1.0 | 1.0 | 核糖体蛋白(技术偏差) |
| RPS15A | -0.510 | 0.993 | 1.0 | 核糖体蛋白(技术偏差) |
| RPS19 | -0.597 | 1.0 | 1.0 | 核糖体蛋白(技术偏差) |
关键发现:差异基因主要是核糖体蛋白和 MHC-I 分子,这些是典型的技术偏差而非生物学差异。这说明我们模拟的批次效应主要体现在检测效率上,符合预期。
8.4 差异基因可视化¶
VlnPlot(pbmc, features = top_de, split.by = "batch", pt.size = 0, ncol = 3)
9. RPCA 整合与 CCA 对比¶
9.1 RPCA 整合¶
RPCA(Reciprocal PCA)是一种更快速、更保守的整合方法:
# RPCA 需要 layers 处于分割状态
pbmc[["RNA"]] <- split(pbmc[["RNA"]], f = pbmc$batch)
pbmc <- IntegrateLayers(
object = pbmc,
method = RPCAIntegration,
orig.reduction = "pca",
new.reduction = "integrated.rpca",
verbose = FALSE
)
# 合并 layers
pbmc[["RNA"]] <- JoinLayers(pbmc[["RNA"]])
9.2 RPCA 整合后 UMAP¶
9.3 CCA vs RPCA 对比¶
左:CCA 整合 | 右:RPCA 整合
9.4 CCA vs RPCA 选择建议¶
| 指标 | CCA | RPCA |
|---|---|---|
| 整合力度 | 强(可能过度校正) | 适中(保留更多变异) |
| 计算速度 | 较慢 | 较快 |
| 适用场景 | 批次差异大 | 批次差异小 |
| 生物学信号保留 | 可能丢失部分 | 保留更好 |
| 推荐 | 常规首选 | 大数据集/小批次差异 |
10. 总结与核心知识点¶
10.1 核心流程图¶
原始数据 → QC 过滤 → 模拟/识别批次
↓
split(pbmc[["RNA"]], f = pbmc$batch)
↓
┌─────────────┴──────────────┐
↓ ↓
未整合分析 CCA/RPCA 整合
(展示批次效应) IntegrateLayers()
↓ ↓
UMAP(批次分离) JoinLayers() + 聚类
↓
UMAP(批次混合)
↓
┌─────────────────┴──────────────────┐
↓ ↓
FindConservedMarkers FindMarkers
(跨批次保守 marker) (跨批次差异基因)
10.2 关键注意事项¶
-
split vs JoinLayers 切换:
-IntegrateLayers需要 layers 分割状态
-FindConservedMarkers需要 layers 合并状态
- 脚本中需要反复切换 -
依赖包:
-FindConservedMarkers需要metap包
-metap依赖multtest(Bioconductor 包)
- 安装:BiocManager::install("multtest")→install.packages("metap") -
整合方法选择:
- 默认使用 CCA(整合力度大)
- 大数据集或小批次差异时优先使用 RPCA
10.3 输出文件清单¶
| 编号 | 文件名 | 内容 |
|---|---|---|
| 01 | 01_unintegrated_batch.png | 未整合 UMAP - 按批次 |
| 02 | 02_unintegrated_cluster.png | 未整合 UMAP - 按聚类 |
| 03 | 03_unintegrated_split.png | 未整合 - 按批次分割 |
| 04 | 04_integrated_batch.png | CCA 整合后 - 按批次 |
| 05 | 05_integrated_cluster.png | CCA 整合后 - 按聚类 |
| 06 | 06_integrated_split.png | CCA 整合后 - 按批次分割 |
| 07 | 07_compare_batch.png | 整合前后对比 - 按批次 |
| 08 | 08_compare_cluster.png | 整合前后对比 - 按聚类 |
| 09 | 09_annotated_umap.png | 注释后 UMAP |
| 10 | 10_marker_featureplot.png | Marker FeaturePlot |
| 11 | 11_conserved_markers_violin.png | 保守 Marker 小提琴图 |
| 12 | 12_conserved_markers_dot.png | 保守 Marker DotPlot |
| 13 | 13_batch_de_violin.png | 跨批次差异基因小提琴图 |
| 14 | 14_rpca_batch.png | RPCA 整合后 - 按批次 |
| 15 | 15_cca_vs_rpca.png | CCA vs RPCA 对比 |
附录: 完整脚本¶
integration_vignette.R¶
###############################################################################
# Seurat v5 阶段3:数据整合分析(Integration)
# 基于官方教程:
# - https://satijalab.org/seurat/articles/integration_introduction
# - https://satijalab.org/seurat/articles/seurat5_integration
#
# 由于 ifnb 数据集(394MB)从 Seurat 官方服务器下载过慢,
# 本脚本使用已有的 PBMC 3k 数据,通过人为分割模拟两个"批次",
# 完整演示 Seurat v5 整合流程的所有核心步骤:
# 1. 模拟批次效应
# 2. 未整合分析(展示批次效应)
# 3. CCA 整合
# 4. 整合前后对比
# 5. 保守 Marker 基因(FindConservedMarkers)
# 6. 跨条件差异表达(FindMarkers)
# 7. 整合方法对比(CCA vs RPCA)
###############################################################################
library(Seurat)
library(ggplot2)
library(patchwork)
library(dplyr)
# === 路径配置 ===
base_dir <- "E:/BaiduNetdiskDownload/生物信息学/pbmc3k_tutorial"
data_dir <- file.path(base_dir, "data/filtered_gene_bc_matrices/hg19")
output_dir <- file.path(base_dir, "output")
integ_dir <- file.path(output_dir, "integration")
dir.create(integ_dir, showWarnings = FALSE, recursive = TRUE)
# ============================================================================
# 1. 加载数据 & 模拟批次效应
# ============================================================================
cat("\n========== 1. 加载数据 & 模拟批次 ==========\n")
# 读取原始 10X 数据
pbmc_data <- Read10X(data.dir = data_dir)
# 创建 Seurat 对象
pbmc <- CreateSeuratObject(counts = pbmc_data, project = "pbmc3k",
min.cells = 3, min.features = 200)
# 计算线粒体百分比
pbmc <- PercentageFeatureSet(pbmc, pattern = "^MT-", col.name = "percent.mt")
# QC 过滤
pbmc <- subset(pbmc, subset = nFeature_RNA > 200 & nFeature_RNA < 2500 & percent.mt < 5)
cat("过滤后细胞数:", ncol(pbmc), "\n")
# --- 模拟批次效应 ---
# 将细胞随机分为两个"批次"
set.seed(42)
cell_ids <- colnames(pbmc)
batch_labels <- sample(c("batch1", "batch2"), size = length(cell_ids), replace = TRUE)
names(batch_labels) <- cell_ids
pbmc$batch <- batch_labels
# 为 batch2 人为添加技术偏差:
# 1) 对 batch2 的部分基因表达量添加随机噪声(模拟批次效应)
# 2) 降低 batch2 中某些基因的检测率
cat("正在模拟批次效应...\n")
# 获取 counts 矩阵
counts_mat <- GetAssayData(pbmc, layer = "counts")
# 找到 batch2 的细胞
batch2_cells <- which(pbmc$batch == "batch2")
batch1_cells <- which(pbmc$batch == "batch1")
cat("batch1:", length(batch1_cells), "个细胞\n")
cat("batch2:", length(batch2_cells), "个细胞\n")
# 对 batch2 添加乘法噪声(模拟不同的捕获效率)
set.seed(123)
noise_factor <- 0.7 + 0.6 * runif(nrow(counts_mat)) # 0.7-1.3 的基因特异噪声
noise_matrix <- matrix(noise_factor, nrow = nrow(counts_mat), ncol = length(batch2_cells))
# 对 batch2 的 counts 乘以噪声因子(向下取整)
counts_batch2 <- ceiling(as.matrix(counts_mat[, batch2_cells]) * noise_matrix)
counts_mat[, batch2_cells] <- as(counts_batch2, "dgCMatrix")
# 为 batch2 随机 dropout 部分基因(模拟检测率差异)
set.seed(456)
dropout_genes <- sample(rownames(pbmc), size = 500) # 随机选 500 个基因
for (gene in dropout_genes) {
dropout_cells <- sample(batch2_cells, size = floor(length(batch2_cells) * 0.3))
counts_mat[gene, dropout_cells] <- 0
}
# 写回修改后的 counts
pbmc[["RNA"]]$counts <- counts_mat
cat("批次效应模拟完成\n")
# ============================================================================
# 2. 按批次分割 Layers(Seurat v5 核心特性)
# ============================================================================
cat("\n========== 2. 分割 Layers ==========\n")
# Seurat v5 核心特性:在一个对象中通过 layers 管理多个批次
pbmc[["RNA"]] <- split(pbmc[["RNA"]], f = pbmc$batch)
cat("分割后 layers:\n")
print(pbmc)
# ============================================================================
# 3. 未整合分析(展示批次效应)
# ============================================================================
cat("\n========== 3. 未整合分析 ==========\n")
# 标准流程(对每个 layer 独立归一化和找高变基因)
pbmc <- NormalizeData(pbmc)
pbmc <- FindVariableFeatures(pbmc)
pbmc <- ScaleData(pbmc)
pbmc <- RunPCA(pbmc)
# 聚类
pbmc <- FindNeighbors(pbmc, dims = 1:30, reduction = "pca")
pbmc <- FindClusters(pbmc, resolution = 0.8, cluster.name = "unintegrated_clusters")
# UMAP(未整合)
pbmc <- RunUMAP(pbmc, dims = 1:30, reduction = "pca", reduction.name = "umap.unintegrated")
# 3.1 未整合 UMAP - 按批次着色
p_unintegrated_batch <- DimPlot(pbmc, reduction = "umap.unintegrated", group.by = "batch") +
ggtitle("未整合 - 按批次着色")
ggsave(file.path(integ_dir, "01_unintegrated_batch.png"), plot = p_unintegrated_batch, width = 8, height = 7, dpi = 150)
cat("已保存: 01_unintegrated_batch.png\n")
# 3.2 未整合 UMAP - 按聚类着色
p_unintegrated_cluster <- DimPlot(pbmc, reduction = "umap.unintegrated", group.by = "unintegrated_clusters") +
ggtitle("未整合 - 按聚类着色")
ggsave(file.path(integ_dir, "02_unintegrated_cluster.png"), plot = p_unintegrated_cluster, width = 8, height = 7, dpi = 150)
cat("已保存: 02_unintegrated_cluster.png\n")
# 3.3 未整合 - split.by 批次
p_unintegrated_split <- DimPlot(pbmc, reduction = "umap.unintegrated", split.by = "batch") +
ggtitle("未整合 - 按批次分割")
ggsave(file.path(integ_dir, "03_unintegrated_split.png"), plot = p_unintegrated_split, width = 14, height = 6, dpi = 150)
cat("已保存: 03_unintegrated_split.png\n")
# ============================================================================
# 4. CCA 整合
# ============================================================================
cat("\n========== 4. CCA 整合 ==========\n")
cat("正在运行 CCA 整合(可能需要几分钟)...\n")
# IntegrateLayers 一行代码完成整合
pbmc <- IntegrateLayers(
object = pbmc,
method = CCAIntegration,
orig.reduction = "pca",
new.reduction = "integrated.cca",
verbose = FALSE
)
cat("CCA 整合完成\n")
# 重新合并 layers(整合后必须执行)
pbmc[["RNA"]] <- JoinLayers(pbmc[["RNA"]])
cat("Layers 已重新合并\n")
# 基于整合后的降维结果聚类
pbmc <- FindNeighbors(pbmc, reduction = "integrated.cca", dims = 1:30)
pbmc <- FindClusters(pbmc, resolution = 0.5, cluster.name = "cca_clusters")
# 整合后 UMAP
pbmc <- RunUMAP(pbmc, dims = 1:30, reduction = "integrated.cca", reduction.name = "umap.cca")
# 4.1 整合后 UMAP - 按批次着色
p_integrated_batch <- DimPlot(pbmc, reduction = "umap.cca", group.by = "batch") +
ggtitle("CCA 整合后 - 按批次着色")
ggsave(file.path(integ_dir, "04_integrated_batch.png"), plot = p_integrated_batch, width = 8, height = 7, dpi = 150)
cat("已保存: 04_integrated_batch.png\n")
# 4.2 整合后 UMAP - 按聚类着色
p_integrated_cluster <- DimPlot(pbmc, reduction = "umap.cca", group.by = "cca_clusters", label = TRUE) +
ggtitle("CCA 整合后 - 按聚类着色")
ggsave(file.path(integ_dir, "05_integrated_cluster.png"), plot = p_integrated_cluster, width = 8, height = 7, dpi = 150)
cat("已保存: 05_integrated_cluster.png\n")
# 4.3 整合后 - split.by 批次
p_integrated_split <- DimPlot(pbmc, reduction = "umap.cca", split.by = "batch") +
ggtitle("CCA 整合后 - 按批次分割")
ggsave(file.path(integ_dir, "06_integrated_split.png"), plot = p_integrated_split, width = 14, height = 6, dpi = 150)
cat("已保存: 06_integrated_split.png\n")
# ============================================================================
# 5. 整合前后对比图
# ============================================================================
cat("\n========== 5. 整合前后对比 ==========\n")
# 5.1 并排对比 - 按批次着色
p_compare_batch <- DimPlot(pbmc, reduction = "umap.unintegrated", group.by = "batch") +
ggtitle("未整合") +
DimPlot(pbmc, reduction = "umap.cca", group.by = "batch") +
ggtitle("CCA 整合后")
ggsave(file.path(integ_dir, "07_compare_batch.png"), plot = p_compare_batch, width = 16, height = 6, dpi = 150)
cat("已保存: 07_compare_batch.png\n")
# 5.2 并排对比 - 按聚类着色
p_compare_cluster <- DimPlot(pbmc, reduction = "umap.unintegrated", group.by = "unintegrated_clusters") +
ggtitle("未整合聚类") +
DimPlot(pbmc, reduction = "umap.cca", group.by = "cca_clusters", label = TRUE) +
ggtitle("整合后聚类")
ggsave(file.path(integ_dir, "08_compare_cluster.png"), plot = p_compare_cluster, width = 16, height = 6, dpi = 150)
cat("已保存: 08_compare_cluster.png\n")
# ============================================================================
# 6. 细胞类型注释
# ============================================================================
cat("\n========== 6. 细胞类型注释 ==========\n")
# 使用经典 marker 进行注释(与阶段1一致)
# 先寻找每个聚类的 marker 基因
pbmc.markers <- FindAllMarkers(pbmc, only.pos = TRUE, min.pct = 0.25, logfc.threshold = 0.25)
top_markers <- pbmc.markers %>%
group_by(cluster) %>%
slice_max(n = 5, order_by = avg_log2FC)
cat("各聚类 top 5 marker:\n")
print(top_markers)
# 保存 marker 表
write.csv(pbmc.markers, file.path(integ_dir, "integration_markers.csv"), row.names = FALSE)
cat("已保存: integration_markers.csv\n")
# 基于阶段1的知识进行注释
# 查看各聚类的 marker 来确定细胞类型
new.cluster.ids <- c("Naive CD4 T", "CD14+ Mono", "Memory CD4 T", "B",
"CD8 T", "FCGR3A+ Mono", "NK", "DC", "Platelet")
# 根据实际聚类数调整
n_clusters <- length(unique(pbmc$cca_clusters))
cat("聚类数量:", n_clusters, "\n")
# 如果聚类数与注释数不匹配,使用通用注释
if (n_clusters == length(new.cluster.ids)) {
names(new.cluster.ids) <- levels(pbmc)
pbmc <- RenameIdents(pbmc, new.cluster.ids)
} else {
cat("聚类数与预设注释数不一致,使用通用注释\n")
# 使用数字标签
new.cluster.ids <- paste0("Cluster", 0:(n_clusters - 1))
names(new.cluster.ids) <- levels(pbmc)
pbmc <- RenameIdents(pbmc, new.cluster.ids)
}
pbmc$cell_type <- Idents(pbmc)
# 6.1 注释后 UMAP
p_annotated <- DimPlot(pbmc, reduction = "umap.cca", label = TRUE, pt.size = 0.5) + NoLegend() +
ggtitle("整合后 - 细胞类型注释")
ggsave(file.path(integ_dir, "09_annotated_umap.png"), plot = p_annotated, width = 8, height = 7, dpi = 150)
cat("已保存: 09_annotated_umap.png\n")
# 6.2 Marker FeaturePlot
p_markers_fp <- FeaturePlot(pbmc, features = c("IL7R", "CD14", "MS4A1", "CD8A", "GNLY", "FCGR3A"),
reduction = "umap.cca", ncol = 3)
ggsave(file.path(integ_dir, "10_marker_featureplot.png"), plot = p_markers_fp, width = 14, height = 10, dpi = 150)
cat("已保存: 10_marker_featureplot.png\n")
# ============================================================================
# 7. 保守 Marker 基因(FindConservedMarkers)
# ============================================================================
cat("\n========== 7. 保守 Marker 基因 ==========\n")
# FindConservedMarkers:在两个批次中分别寻找 marker,然后用 meta-analysis 合并 p 值
# 这可以找到不受批次效应影响的稳定 marker 基因
# 注意:FindConservedMarkers 需要 layers 处于合并状态
# (它在内部按 grouping.var 分组分析,不需要预先 split)
# 确保 layers 已合并
pbmc[["RNA"]] <- JoinLayers(pbmc[["RNA"]])
# 以某个聚类为例(选择最大的聚类)
Idents(pbmc) <- "cca_clusters"
target_cluster <- as.character(which.max(table(pbmc$cca_clusters)))
cat("分析聚类", target_cluster, "的保守 marker\n")
conserved_markers <- FindConservedMarkers(
pbmc,
ident.1 = target_cluster,
grouping.var = "batch",
verbose = FALSE
)
cat("保守 marker 前 15 个:\n")
print(head(conserved_markers, 15))
# 保存保守 marker
write.csv(conserved_markers, file.path(integ_dir, "conserved_markers.csv"), row.names = TRUE)
cat("已保存: conserved_markers.csv\n")
# 7.1 保守 marker 小提琴图(按批次分割)
top_conserved <- rownames(head(conserved_markers, 6))
p_conserved_vln <- VlnPlot(pbmc, features = top_conserved, split.by = "batch", pt.size = 0, ncol = 3) +
ggtitle("保守 Marker - 按批次分割")
ggsave(file.path(integ_dir, "11_conserved_markers_violin.png"), plot = p_conserved_vln, width = 14, height = 10, dpi = 150)
cat("已保存: 11_conserved_markers_violin.png\n")
# 7.2 保守 marker DotPlot(按批次分割)
# layers 已合并,直接使用
markers_to_plot <- rownames(head(conserved_markers, 12))
p_conserved_dot <- DotPlot(pbmc, features = markers_to_plot, split.by = "batch") + RotatedAxis() +
ggtitle("保守 Marker DotPlot - 按批次对比")
ggsave(file.path(integ_dir, "12_conserved_markers_dot.png"), plot = p_conserved_dot, width = 12, height = 6, dpi = 150)
cat("已保存: 12_conserved_markers_dot.png\n")
# ============================================================================
# 8. 跨批次差异表达分析
# ============================================================================
cat("\n========== 8. 跨批次差异表达 ==========\n")
# 创建 celltype.batch 组合变量
pbmc$celltype.batch <- paste(pbmc$cell_type, pbmc$batch, sep = "_")
Idents(pbmc) <- "celltype.batch"
# 选择一个细胞类型,比较两个批次的差异
# 尝试找到 CD14+ Mono 或第一个细胞类型
unique_idents <- unique(pbmc$celltype.batch)
cat("可用的 celltype.batch 组合:\n")
print(table(pbmc$celltype.batch))
# 选择第一个细胞类型进行跨批次比较
# 找到同时存在于两个批次的细胞类型
batch1_types <- unique(pbmc$cell_type[pbmc$batch == "batch1"])
batch2_types <- unique(pbmc$cell_type[pbmc$batch == "batch2"])
common_types <- intersect(batch1_types, batch2_types)
cat("两个批次共有的细胞类型:\n")
print(common_types)
if (length(common_types) > 0) {
target_type <- common_types[1]
ident1 <- paste0(target_type, "_batch2")
ident2 <- paste0(target_type, "_batch1")
if (ident1 %in% unique_idents && ident2 %in% unique_idents) {
de_genes <- FindMarkers(pbmc, ident.1 = ident1, ident.2 = ident2, verbose = FALSE)
cat("\n", target_type, "的跨批次差异基因(前 15 个):\n")
print(head(de_genes, 15))
write.csv(de_genes, file.path(integ_dir, "batch_de_genes.csv"), row.names = TRUE)
cat("已保存: batch_de_genes.csv\n")
# 8.1 差异基因小提琴图
top_de <- rownames(head(de_genes, 6))
if (length(top_de) > 0) {
p_de_vln <- VlnPlot(pbmc, features = top_de, split.by = "batch", pt.size = 0, ncol = 3) +
ggtitle(paste0("跨批次差异基因 - ", target_type))
ggsave(file.path(integ_dir, "13_batch_de_violin.png"), plot = p_de_vln, width = 14, height = 10, dpi = 150)
cat("已保存: 13_batch_de_violin.png\n")
}
}
}
# ============================================================================
# 9. RPCA 整合(更快速、更保守的整合方法)
# ============================================================================
cat("\n========== 9. RPCA 整合 ==========\n")
# RPCA 整合需要按批次分割 layers
pbmc[["RNA"]] <- split(pbmc[["RNA"]], f = pbmc$batch)
# RPCA 整合(比 CCA 更快、更保守)
cat("正在运行 RPCA 整合...\n")
pbmc <- IntegrateLayers(
object = pbmc,
method = RPCAIntegration,
orig.reduction = "pca",
new.reduction = "integrated.rpca",
verbose = FALSE
)
cat("RPCA 整合完成\n")
# 合并 layers
pbmc[["RNA"]] <- JoinLayers(pbmc[["RNA"]])
# RPCA 聚类和 UMAP
pbmc <- FindNeighbors(pbmc, reduction = "integrated.rpca", dims = 1:30)
pbmc <- FindClusters(pbmc, resolution = 0.5, cluster.name = "rpca_clusters")
pbmc <- RunUMAP(pbmc, dims = 1:30, reduction = "integrated.rpca", reduction.name = "umap.rpca")
# 9.1 RPCA 整合后 UMAP - 按批次着色
p_rpca_batch <- DimPlot(pbmc, reduction = "umap.rpca", group.by = "batch") +
ggtitle("RPCA 整合后 - 按批次着色")
ggsave(file.path(integ_dir, "14_rpca_batch.png"), plot = p_rpca_batch, width = 8, height = 7, dpi = 150)
cat("已保存: 14_rpca_batch.png\n")
# 9.2 CCA vs RPCA 对比
p_cca_rpca <- DimPlot(pbmc, reduction = "umap.cca", group.by = "batch") +
ggtitle("CCA 整合") +
DimPlot(pbmc, reduction = "umap.rpca", group.by = "batch") +
ggtitle("RPCA 整合")
ggsave(file.path(integ_dir, "15_cca_vs_rpca.png"), plot = p_cca_rpca, width = 16, height = 6, dpi = 150)
cat("已保存: 15_cca_vs_rpca.png\n")
# ============================================================================
# 10. 保存结果
# ============================================================================
cat("\n========== 10. 保存结果 ==========\n")
saveRDS(pbmc, file.path(output_dir, "pbmc3k_integrated.rds"))
cat("已保存整合后对象: pbmc3k_integrated.rds\n")
# ============================================================================
# 总结
# ============================================================================
cat("\n")
cat("=======================================================\n")
cat(" 阶段3 数据整合教程完成!\n")
cat("=======================================================\n")
cat(" 输出目录:", integ_dir, "\n")
cat(" 图片数量: 15 张\n")
cat(" 覆盖内容:\n")
cat(" 01-03: 未整合分析(展示批次效应)\n")
cat(" 04-06: CCA 整合结果\n")
cat(" 07-08: 整合前后对比\n")
cat(" 09-10: 细胞类型注释\n")
cat(" 11-12: 保守 Marker 基因\n")
cat(" 13: 跨批次差异表达\n")
cat(" 14-15: RPCA 整合与 CCA 对比\n")
cat(" 核心知识点:\n")
cat(" - Seurat v5 layers 机制(split / Join)\n")
cat(" - IntegrateLayers 一行代码整合\n")
cat(" - CCA vs RPCA 两种整合方法\n")
cat(" - FindConservedMarkers 跨批次保守 marker\n")
cat(" - FindMarkers 跨批次差异表达\n")
cat(" - 整合前后对比可视化\n")
cat("=======================================================\n")
本教程基于 Seurat v5.5.1 官方文档整理
R 4.6.1 + Seurat 5.5.1 + Windows 环境
阶段3: 数据整合分析(CCA / RPCA / 保守 Marker / 跨批次差异表达)