导语
GUIDE ╲
在对单细胞数据的处理中,常常遇到需要对两个或者多个数据集进行整合分析的情况,其中就涉及到数据集的矫正问题,今天我们基于Seurat来为大家介绍几种数据整合的方法,供大家在实践操作中参考选择。
正文
在实际操作中,我们经常会遇到需要对两个或多个单细胞RNA数据进行整合的情况,例如同一批实验中的多个样本/生物学重复/技术重复,来自不同研究项目、不同建库策略、不同测序平台的数据集合并等。如何对数据集合并并从中识别出其中存在的共有的细胞群体就成为了我们单细胞数据分析中的一个挑战。这个挑战主要来自于批次效应。
我们做数据分析的目的就是找到样本之间真实的生物学差异,而当我们希望通过合并同一组织数据挖掘出更有意义的信息时,常常发现明明是同个组织的数据,表达量就是存在明显的差异。那么在数据整合时合适的进行批次矫正操作就能帮助我们降低技术差异引入的影响。
下面我们给大家主要介绍一下Seurat v4中用于数据整合的三种方法。以下代码示例均来自于Seurat v4.0.1教程【1,2】。
01
简单数据整合
简单的数据整合,即没有对数据集做任何校正处理。使用函数seurat::merge(),适用于整合两个或多个数据集。可用于合并原始数据或者标准化后的数据。
代码语言:javascript复制# Seurat-merge示例
# 示例1:合并两个10X PBMC数据集
# 首先读入并创建两个seurat objects: pbmc4k 和pbmc8k
library(Seurat)
pbmc4k.data <- Read10X(data.dir = "../pbmc4k/filtered_gene_bc_matrices/GRCh38/")
pbmc4k <- CreateSeuratObject(counts = pbmc4k.data, project = "PBMC4K")
pbmc4k
pbmc8k.data <- Read10X(data.dir = "../pbmc8k/filtered_gene_bc_matrices/GRCh38/")
pbmc8k <- CreateSeuratObject(counts = pbmc8k.data, project = "PBMC8K")
pbmc8k
# 合并
# merge()函数会合并两个对象的原始表达数据;两个数据集的细胞barcode可能会重复,
# 为了区分细胞来源,通过`add.cell.ids`给不同样本的细胞barcode添加一个id
pbmc.combined <- merge(pbmc4k, y = pbmc8k, add.cell.ids = c("4K", "8K"), project = "PBMC12K")
pbmc.combined
head(colnames(pbmc.combined))
table(pbmc.combined$orig.ident)
# 示例2:合并多个数据集:pbmc3k pbmc4k pbmc8k
InstallData("pbmc3k")
pbmc3k <- LoadData("pbmc3k", type = "pbmc3k.final")
pbmc3k
pbmc.big <- merge(pbmc3k, y = c(pbmc4k, pbmc8k), add.cell.ids = c("3K", "4K", "8K"), project = "PBMC15K")
pbmc.big
table(pbmc.big$orig.ident)
#end.
02
CCA MNN
对数据做批次校正的整合方法:CCA MNN(Multi canonical correlation analysis Mutual nearest neighbor。该方法发表于2019年(如下图 )【3】, 是通过CCA方法最大化不同批次数据间的协方差,将数据映射到低维空间中,计算并找出两个数据集之间的“距离”最相近的细胞,即最相似的细胞, Seurat将这些细胞称为“锚点细胞”(anchor)。匹配上的“锚点细胞”被认为是相同类型和状态的细胞,它们之间的基因表达差异是由技术差异导致的,因此可以利用它们之间的差异来对两个数据集进行校正。校正后的表达值被人为消除了技术噪音,从而实现了两个单细胞数集的整合。
代码语言:javascript复制# CCA MNN 整合
# 示例:
library(Seurat)
library(SeuratData)
library(patchwork)
# 加载数据
InstallData("ifnb")
LoadData("ifnb")
# 将数据分为两个seurat 对象 :stim and CTRL
ifnb.list <- SplitObject(ifnb, split.by = "stim")
# 分别对两个数据集进行标准化并找出高变基因
ifnb.list <- lapply(X = ifnb.list, FUN = function(x) {
x <- NormalizeData(x)
x <- FindVariableFeatures(x, selection.method = "vst", nfeatures = 2000)
})
# 选择在数据集中重复的高变基因用于整合
features <- SelectIntegrationFeatures(object.list = ifnb.list)
#整合:基于高变基因找出两两数据集间的“锚点细胞”
immune.anchors <- FindIntegrationAnchors(object.list = ifnb.list, anchor.features = features)
# 生成一个新的 'integrated' assay
immune.combined <- IntegrateData(anchorset = immune.anchors)
# 通过 'integrated' assay的整合数据进行下游的细胞类型分类等分析;原始的表达数据仍保存在 'RNA' assay
DefaultAssay(immune.combined) <- "integrated"
immune.combined <- ScaleData(immune.combined, verbose = FALSE)
immune.combined <- RunPCA(immune.combined, npcs = 30, verbose = FALSE)
immune.combined <- RunUMAP(immune.combined, reduction = "pca", dims = 1:30)
immune.combined <- FindNeighbors(immune.combined, reduction = "pca", dims = 1:30)
immune.combined <- FindClusters(immune.combined, resolution = 0.5)
# 可视化:查看两个数据集之间细胞分类情况
DimPlot(immune.combined, reduction = "umap", split.by = "stim")
#end.
03
Reciprocal PCA and Reference-based integration
对于大型的数据来说,CCA寻找锚点细胞的方法有时会耗时较长,比如说如果我们要整合5个数据集,那么CCA需要进行5 choose 2=10次的操作寻找两两间的锚点细胞。当数据量较大并且数据集个数继续增长时,这个计算量还是非常大的。因此Seurat开发了另外两个可用于提高运行效率和实践的方法:Reciprocal PCA (RPCA)和Reference-based integration。主要的改进集中在寻找锚点细胞的函数`FindIntegrationAnchors`中。
该改进方法基本的实现思路是首先通过RPCA而非CCA来识别找到锚点细胞的低维有效空间,在确认任意两个数据集间的锚点细胞时, 将每个数据集映射到其他PCA空间,并通过相同的mutual neighborhood来选择。另外,在常规的流程中都是对所有数据集寻找两两间的锚点细胞,当合并的数据集数目非常大时,可以考虑Reference-based integration作为替代方案,即选取一个或多个数据集作为“参考”数据集,只寻找其他数据集合和参考数据集之间的锚点,而不关注其他数据集之间锚点,从而减少计算量, 比如合并5个数据集时,设置其中一个为参考,那么只需要进行4次比较操作了。
代码语言:javascript复制# 示例
library(Seurat)
# 分别对每个数据集进行进行标准化并找出高变基因
bm280k.data <- Read10X_h5("../data/ica_bone_marrow_h5.h5")
bm280k <- CreateSeuratObject(counts = bm280k.data, min.cells = 100, min.features = 500)
bm280k.list <- SplitObject(bm280k, split.by = "orig.ident")
bm280k.list <- lapply(X = bm280k.list, FUN = function(x) {
x <- NormalizeData(x, verbose = FALSE)
x <- FindVariableFeatures(x, verbose = FALSE)
})
# 选择在数据集中重复的高变基因用于整合
features <- SelectIntegrationFeatures(object.list = bm280k.list)
# 分别对每个数据集进行PCA降维,用于下面的rpca方法
bm280k.list <- lapply(X = bm280k.list, FUN = function(x) {
x <- ScaleData(x, features = features, verbose = FALSE)
x <- RunPCA(x, features = features, verbose = FALSE)
})
# 利用reference 和rpca寻找锚点细胞,进行整合
anchors <- FindIntegrationAnchors(object.list = bm280k.list, reference = c(1, 2), reduction = "rpca", dims = 1:50)
bm280k.integrated <- IntegrateData(anchorset = anchors, dims = 1:50)
# 整合后,查看数据集的分布状况
bm280k.integrated <- ScaleData(bm280k.integrated, verbose = FALSE)
bm280k.integrated <- RunPCA(bm280k.integrated, verbose = FALSE)
bm280k.integrated <- RunUMAP(bm280k.integrated, dims = 1:50)
DimPlot(bm280k.integrated, group.by = "orig.ident")
# end.
小编总结
CCA和RPCA方法的使用流程和语句都是非常相似的,但是它们可以适用于不同的情况。一般来说,CCA比较适用于当数据集之间细胞类型比较一致,但基因表达层面差异比较大的情况。然而Seurat团队指出CCA整合方法也可能导致过度矫正,尤其是当数据集之间大部分数据不重叠的情况下。另一方面,基于RPCA的方法运行速度变快,并且整合方法相对保守,即不同生物学状态的细胞不太可能会被整合到一起。因此,如果待整合的数据集存在很大的细胞类型差异的话,他们的建议是使用RPCA方法。大家在实践操作中可以根据自己的需求来选择。
Reference:
【1】 Hao, Yuhan, et al. "Integrated analysis of multimodal single-cell data." bioRxiv (2020).
【2】 https://satijalab.org/seurat/index.html
【3】 Stuart, Tim, et al. "Comprehensive integration of single-cell data." Cell 177.7 (2019): 1888-1902.