单细胞RNA-seq生信分析全流程——第五篇:归一化

5. 归一化Normalization

5.1 前言

到目前为止,我们从数据集中删除了低质量细胞、环境RNA污染和双联体,并且数据以“细胞 x 基因”数字矩阵的形式呈现,作为计数矩阵。这些计数代表scRNA-seq实验中捕获、逆转录和测序的分子。每个步骤都会给相同细胞的测量计数深度增加一定程度的变异性,这意味着数据集以及计数矩阵仍然包含变化很大的方差项。分析数据集通常具有挑战性,因为许多统计方法假设数据具有统一的方差结构。
“归一化”的预处理步骤旨在通过将可观察方差缩放到指定范围来调整数据集中的原始计数以实现可变采样效果。实践中使用了多种复杂性各异的归一化技术。它们的设计方式大多是为了后续分析任务及其适用于基础统计方法。
本篇将介绍三种不同的归一化技术:移位对数变换shifted logarithm transformation、scran归一化和皮尔逊残差的解析逼近analytic approximation of Pearson residuals。移位对数变换有利于稳定方差,以利于后续降维和差异表达基因的识别。Scran经过广泛测试并用于批量校正任务,皮尔逊残差的解析逼近非常适合选择生物可变基因和鉴定稀有细胞类型。
我们首先导入所有必需的Python包并加载我们过滤低质量细胞、去除环境 RNA 和评分双联体的数据集。

import scanpy as sc
import numpy as np
import seaborn as sns
from matplotlib import pyplot as plt
import anndata2ri
import logging
from scipy.sparse import issparse

import rpy2.rinterface_lib.callbacks as rcb
import rpy2.robjects as ro

sc.settings.verbosity = 0
sc.settings.set_figure_params(
    dpi=80,
    facecolor="white",
    # color_map="YlGnBu",
    frameon=False,
)

rcb.logger.setLevel(logging.ERROR)
ro.pandas2ri.activate()
anndata2ri.activate()

%load_ext rpy2.ipython
adata = sc.read(
    filename="s4d8_quality_control.h5ad",
    backup_url="https://figshare.com/ndownloader/files/40014331",
)

我们现在可以检查我们在质量控制过程中已经计算出的原始计数的分布。在标准单细胞分析流程中可以忽略此步骤,但有助于理解不同的标准化概念。

p1 = sns.histplot(adata.obs["total_counts"], bins=100, kde=False)

5.2 移位对数变换

我们介绍的第一个归一化技术是基于delta方法的移位对数。Delta方法将非线性函数 f(Y) 应用于原始计数 Y,旨在使数据集中的方差更加相似。
移位对数变换是一种快速归一化技术,优于其他揭示数据集潜在结构的方法(特别是在进行主成分分析时),并且有利于稳定方差,以进行后续的降维和差异表达基因的识别。我们现在将检查如何将此标准化方法应用于我们的数据集。通过运行pp.normalized_total设置为target_sum=None,可以使用scanpy方便地调用移位对数。我们将inplace参数设置为False,因为我们想在本教程中探索三种不同的标准化技术。第二步,使用缩放后的计数,获得了第一个归一化计数矩阵。

scales_counts = sc.pp.normalize_total(adata, target_sum=None, inplace=False)
# log1p transform
adata.layers["log1p_norm"] = sc.pp.log1p(scales_counts["X"], copy=True)

现在,我们可以检查应用移位对数变换后计数分布如何变化,并将其与原始(但已过滤)数据集中的总计数进行比较。

fig, axes = plt.subplots(1, 2, figsize=(10, 5))
p1 = sns.histplot(adata.obs["total_counts"], bins=100, kde=False, ax=axes[0])
axes[0].set_title("Total counts")
p2 = sns.histplot(adata.layers["log1p_norm"].sum(1), bins=100, kde=False, ax=axes[1])
axes[1].set_title("Shifted logarithm")
plt.show()

第二种归一化方法也是基于delta方法,是scran归一化方法。它与移位对数变换唯一的区别是Scran 利用反卷积方法根据细胞池基因的线性回归来估计大小因子。这种方法旨在更好地解释数据集中所有细胞计数深度的差异。
细胞被分成多个池,Scran使用基因的线性回归来估计基于池的大小因子。Scran针对批量校正任务进行了广泛的测试,并且可以使用相应的R包轻松调用。

from scipy.sparse import csr_matrix, issparse
%%R
library(scran)
library(BiocParallel)

scran需要粗聚类输入来提高尺寸因子估计性能。在本教程中,我们使用简单的预处理方法并以低分辨率对数据进行聚类,以获得尺寸因子估计的输入。基本预处理包括假设所有大小因子相等(文库大小归一化为每百万计数 - CPM)以及对计数数据进行对数转换。

# Preliminary clustering for differentiated normalisation
adata_pp = adata.copy()
sc.pp.normalize_total(adata_pp)
sc.pp.log1p(adata_pp)
sc.pp.pca(adata_pp, n_comps=15)
sc.pp.neighbors(adata_pp)
sc.tl.leiden(adata_pp, key_added="groups")

现在,我们将data_mat和计算组添加到R环境中。

data_mat = adata_pp.X.T
# convert to CSC if possible. See https://github.com/MarioniLab/scran/issues/70
if issparse(data_mat):
    if data_mat.nnz > 2**31 - 1:
        data_mat = data_mat.tocoo()
    else:
        data_mat = data_mat.tocsc()
ro.globalenv["data_mat"] = data_mat
ro.globalenv["input_groups"] = adata_pp.obs["groups"]

我们现在还可以删除anndata对象的副本,因为我们获得了运行scran所需的所有对象。

del adata_pp

现在,我们根据之前计算的细胞组来计算尺寸因子。

%%R -o size_factors

size_factors = sizeFactors(
    computeSumFactors(
        SingleCellExperiment(
            list(counts=data_mat)), 
            clusters = input_groups,
            min.mean = 0.1,
            BPPARAM = MulticoreParam()
    )
)

我们将size_factors保存在.obs中,现在能够标准化数据并随后应用log1p转换。

adata.obs["size_factors"] = size_factors
scran = adata.X / adata.obs["size_factors"].values[:, None]
adata.layers["scran_normalization"] = csr_matrix(sc.pp.log1p(scran))
fig, axes = plt.subplots(1, 2, figsize=(10, 5))
p1 = sns.histplot(adata.obs["total_counts"], bins=100, kde=False, ax=axes[0])
axes[0].set_title("Total counts")
p2 = sns.histplot(
    adata.layers["scran_normalization"].sum(1), bins=100, kde=False, ax=axes[1]
)
axes[1].set_title("log1p with Scran estimated size factors")
plt.show()

5.3 皮尔逊残差的解析逼近

我们在本篇中介绍的第三种归一化技术是皮尔逊残差的解析逼近。这种标准化技术的原因是观察到scRNA-seq数据中的细胞间变异可能会因生物异质性与技术效应而混淆。该方法利用“正则化负二项式回归”中的皮尔逊残差来计算数据中的技术噪声模型。它明确地将计数深度添加为广义线性模型中的协变量。在对不同标准化技术的独立比较中表明,该方法消除了采样效应的影响,同时保留了数据集中的细胞异质性。解析Pearon残差在scanpy中实现,可以直接在原始计数矩阵上计算。

analytic_pearson = sc.experimental.pp.normalize_pearson_residuals(adata, inplace=False)
adata.layers["analytic_pearson_residuals"] = csr_matrix(analytic_pearson["X"])
fig, axes = plt.subplots(1, 2, figsize=(10, 5))
p1 = sns.histplot(adata.obs["total_counts"], bins=100, kde=False, ax=axes[0])
axes[0].set_title("Total counts")
p2 = sns.histplot(
    adata.layers["analytic_pearson_residuals"].sum(1), bins=100, kde=False, ax=axes[1]
)
axes[1].set_title("Analytic Pearson residuals")
plt.show()

我们对数据集应用了不同的标准化技术,并将它们作为单独的层保存到我们的anndata对象中。根据下游分析任务,可以使用不同的归一化层并评估结果。

adata.write("s4d8_normalization.h5ad")
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容