归一化和回归不必要的变异
现在我们有了高质量的细胞,我们首先需要探索我们的数据并识别任何不需要的变异来源。然后我们需要对数据进行归一化,执行方差稳定并回归对我们的数据有影响的任何协变量的影响。
目标:
- 准确标准化和缩放基因表达值,以解决测序深度和过度分散计数值的差异。
- 找出最有可能指示不同细胞类型的变异基因。
挑战:
- 检查并消除不必要的变异,避免下游人为原因导致的细胞聚集
建议:
- 在执行聚类之前,要很好地了解您对要呈现的细胞类型的期望。了解你所期望的是低复杂性的细胞类型还是高线粒体含量的细胞类型,以及这些细胞是否正在分化。
- 如果需要并且适合于实验,回归出UMIs的数量(默认使用 sctransform)、线粒体含量和细胞周期,因此不会用于下游聚类
开始
让我们首先创建一个新脚本进行规范化和集成步骤。创建一个新脚本(文件 -> 新文件 -> R 脚本),并将其保存为SCT_integration_analysis.R
.
对于工作流程的其余部分,我们将主要使用 Seurat 包中提供的函数。因此,除了 tidyverse 库和下面列出的其他一些库之外,我们还需要加载 Seurat 库。
# Single-cell RNA-seq - normalization
# Load libraries
library(Seurat)
library(tidyverse)
library(RCurl)
library(cowplot)
此分析的输入是一个seurat
对象。我们将使用我们在 QC 课程中创建的名为filtered_seurat
.
探索不必要的变异来源
对生物协变量的校正目的是为了挑选出感兴趣的特定生物信号,而技术协变量的校正对于揭示潜在的生物信号可能至关重要。最常见的生物学数据校正是去除细胞周期对转录组的影响。这种数据校正可以通过对细胞周期评分的简单线性回归来执行,我们将在下面演示。
第一步是查看数据,看看我们是否观察到数据中的是否有任何影响。细胞之间的原始计数不具有可比性,我们不能将它们用于我们的探索性分析。因此,我们将通过除以每个细胞的总计数并取自然对数来执行粗略的归一化。这种标准化仅用于探索我们数据中的变化来源。
注意:Seurat 最近引入了一种称为sctransform的新归一化方法 ,它同时执行方差稳定并回归出不必要的变化。这是我们在工作流程中使用的规范化方法。
# Normalize the counts
seurat_phase <- NormalizeData(filtered_seurat)
接下来,我们获取这些归一化数据并检查是否需要数据校正方法。
评估细胞周期的影响
为了根据每个细胞的 G2/M 和 S 期标记的表达为其分配一个分数,我们可以使用 Seuart 的CellCycleScoring()
函数。此函数需要输入规范标记计算细胞周期阶段分数。
我们在data
文件夹中为您提供了人类细胞周期标记的列表,作为一个名为cycle.rda
. 但是,如果您不使用人类数据,我们还有其他物种详细介绍了如何获取其他感兴趣生物的细胞周期标记。
# Load cell cycle markers
load("data/cycle.rda")
# Score cells for cell cycle
seurat_phase <- CellCycleScoring(seurat_phase,
g2m.features = g2m_genes,
s.features = s_genes)
# View cell cycle scores and phases assigned to cells
View(seurat_phase@meta.data)
在对细胞的细胞周期进行评分后,我们想使用 PCA 确定细胞周期是否是我们数据集中变异的主要来源。要执行 PCA,我们需要首先选择高度可变基因,然后对数据进行缩放。由于高表达的基因表现出最高的变异量,我们不希望我们的“高变异基因”只反映高表达,我们需要缩放数据反映出表达水平的变化。Seurat的ScaleData()
函数进行数据缩放:
- 调整每个基因的表达,使跨细胞的平均表达为 0
- 缩放每个基因的表达以使细胞间的方差为 1
# Identify the most variable genes
seurat_phase <- FindVariableFeatures(seurat_phase,
selection.method = "vst",
nfeatures = 2000,
verbose = FALSE)
# Scale the counts
seurat_phase <- ScaleData(seurat_phase)
注意:对于
selection.method
和nfeatures
参数,指定的值是默认设置。因此,代码中可以不包含这些。我们将其包含在此处以提高透明度并告知您正在使用的内容。
现在,我们可以执行 PCA 分析并将前两个主成分绘制出来。我们还按细胞周期阶段拆分图,以评估相似性或差异性。由于细胞周期阶段,我们没有看到大的差异。基于这个图,我们将不进行回归,未发现细胞周期引起的变化。
# Perform PCA
seurat_phase <- RunPCA(seurat_phase)
# Plot the PCA colored by cell cycle phase
DimPlot(seurat_phase,
reduction = "pca",
group.by= "Phase",
split.by = "Phase")
细胞周期阶段应该何时回归?
下面是从处理“细胞周期评分和回归”的 Seurat 案例中截取的两个 PCA 图。
第一个图类似于我们上面绘制的图,它是回归之前的 PCA,用于评估细胞周期是否在驱动 PC1 和 PC2 中发挥重要作用。
很明显,在这种情况下,细胞是按细胞类型分开的,所以该案例建议回归细胞周期产生的影响。
第二个 PCA 图是post-regression,显示了消除我们观察到的影响方面回归后的效果。
线粒体表达是另一个极大影响聚类的因素。通常,对线粒体表达引起的变化进行回归是很有用的。然而,如果线粒体基因表达的差异代表了一种可能有助于区分细胞簇的生物学现象,那么我们建议不要将其回归。在本练习中,我们可以执行类似于查看细胞周期的快速检查,并决定是否要对其进行回归。
- 首先,将线粒体比率变量转换为基于四分位数的新分类变量(使用以下代码):
# Check quartile values
summary(seurat_phase@meta.data$mitoRatio)
# Turn mitoRatio into categorical factor vector based on quartile values
seurat_phase@meta.data$mitoFr <- cut(seurat_phase@meta.data$mitoRatio,
breaks=c(-Inf, 0.0144, 0.0199, 0.0267, Inf),
labels=c("Low","Medium","Medium high", "High"))
接下来,绘制类似于我们如何处理细胞周期回归的 PCA。提示:使用新
mitoFr
变量拆分单元格并相应地为它们着色。评估 #2 中生成的 PCA 图。
1. 确定您是否观察到效果。
1\. Describe what you see.
1\. Would you regress out mitochndrial fraction as a source of unwanted variation?
使用 SCTransform 归一化和回归出不必要的变化源
现在我们可以使用 sctransform 方法作为更准确的归一化方法,估计原始过滤数据的方差,并识别最易变的基因。sctransform 方法使用正则化负二项式模型对UMI 计数进行建模,以消除由于测序深度(每个细胞的总 nUMI)引起的变化,同时根据具有相似丰度的基因之间的汇集信息进而调整方差(类似于一些bulk RNA-seq 方法)。
图片来源: Hafemeister C 和 Satija R。使用正则化负二项式回归对单细胞 RNA-seq 数据进行标准化和方差稳定化,bioRxiv 2019 (https://doi.org/10.1101/576827)
模型的输出(残差)是每个测试转录本的标准化表达水平。
Sctransform 通过回归测序深度 (nUMI) 自动考虑细胞测序深度。但是,如果在探索步骤期间在数据中发现了其他无用的变化来源,我们也可以包括这些。由于在细胞周期阶段,我们几乎没有观察到影响,因此我们选择不从我们的数据中回归。我们观察到线粒体表达的一些影响,因此我们选择从数据中回归。
为了运行 SCTransform,我们以下面的代码为例。不要运行此代码,因为我们更喜欢在下面的下一部分中为每个示例分别运行此代码。
## DO NOT RUN CODE ##
# SCTranform
seurat_phase <- SCTransform(seurat_phase, vars.to.regress = c("mitoRatio"))
迭代数据集中的样本
由于我们的数据集中有两个样本(来自两个条件),我们希望将它们保留为单独的对象并按照集成所需的方式转换它们。我们首先将seurat_phase
对象中的细胞拆分为“ctrl”和“stim”组:
# Split seurat object by condition to perform cell cycle scoring and SCT on all samples
split_seurat <- SplitObject(seurat_phase, split.by = "sample")
split_seurat <- split_seurat[c("ctrl", "stim")]
通过使用“for 循环”在每个样本上运行SCTransform()
,并在函数SCTransform()
的vars.to.regress
参数中指定来回归线粒体表达。
在我们运行for
循环之前,我们需要知道生成的R对象需要占用大量的内存。如果我们有一个大型数据集,那么我们需要使用以下代码调整 R 内允许的对象大小的限制(默认为 500 * 1024 ^ 2 = 500 Mb):
options(future.globals.maxSize = 4000 * 1024^2)
现在,我们运行以下循环对所有样本执行 sctransform。这可能需要一些时间(约 10 分钟):
for (i in 1:length(split_seurat)) {
split_seurat[[i]] <- SCTransform(split_seurat[[i]], vars.to.regress = c("mitoRatio"))
}
注意:默认情况下,在归一化、调整方差和回归不感兴趣的变异源后,SCTransform 将按残差对基因进行排序,并输出 3000 个变异最大的基因。如果数据集具有更大的细胞数,则使用该
variable.features.n
参数将该参数调整得更高效果将会更好。
请注意,输出的最后一行指定“将默认检测设置为 SCT”。我们可以查看存储在 seurat 对象中的不同分析。
# Check which assays are stored in objects
split_seurat$ctrl@assays
现在我们可以看到,除了原始 RNA 计数之外,我们现在在我们的assays
插槽中有一个 SCT 组件。最可变的特征将是存储在 SCT 分析中的唯一基因。当我们进行 scRNA-seq 分析时,我们将选择最合适的检测方法用于分析中的不同步骤。
训练
-
split_seurat
对象内的“stim”样本是否可以进行相同的分析?你用来运行的代码是什么? - 对于“ctrl”与“stim”的“前 10个feature:”和“最大的10 个variable feature:”中列出的基因或特征是否有任何观察?
保存对象!
在完成之前,让我们将此对象保存到data/
文件夹中。回到这个阶段可能需要一段时间,尤其是在处理大型数据集时,最佳做法是将对象另存为本地可轻松加载的文件。
# Save the split seurat object
saveRDS(split_seurat, "data/split_seurat.rds")
要将
.rds
文件加载回您的环境,您将使用以下代码:# Load the split seurat object into the environment split_seurat <- readRDS("data/split_seurat.rds")