1.基于python的单细胞数据预处理-质量控制

news2024/12/24 22:16:22

目录

  • 质量控制
  • 过滤低质量细胞的指南
  • 双细胞过滤
  • 手动过滤低质量读数细胞
  • 自动过滤低质量读数细胞
  • 环境RNA校正

参考
[1] https://github.com/Starlitnightly/single_cell_tutorial
[2] https://github.com/theislab/single-cell-best-practices

质量控制

原始的单细胞测序数据具有以下特点:

  • 由于测序深度不够,测序数据中会存在很多0值,这被称为drop-out事件;这是具有迷惑性的,因为对于一个细胞的具体基因表达量为0,我们不能判断到底是测序深度不够导致的,还是本身这个基因就不表达。
  • 由于细胞状态不同,我们必然会测量到一些即将死亡的细胞,这些衰老细胞的基因表达情况相对正常细胞的数据也是一个误差。
  • 测序技术本身不是百分百精确,比如液滴技术有时候会一个液滴中包含两个细胞,这样的基因表达量会非常高。一般正常细胞的基因表达量在3000-4000左右。

质量控制方法被用于初步过滤以上异常情况。随着大量的工程积累,下面演示为目前大家认可的最佳质量控制步骤。

使用的数据:这是一个基于10x-Multiome技术的数据集。该数据集测量了来自12名健康人类受试者在4个不同site(骨髓抽取的位置:手臂,胸骨等)的骨髓单核细胞的单细胞多组学数据(包含了嵌套的批次效应)。这里使用的数据是受试者8的样本4。

下载地址为:https://figshare.com/ndownloader/files/39546196

读取数据:

import omicverse as ov
import scanpy as sc

ov.utils.ov_plot_set()

adata = sc.read_10x_h5("./data/filtered_feature_bc_matrix.h5")
print(adata)

"""
AnnData object with n_obs × n_vars = 16934 × 36601
    var: 'gene_ids', 'feature_types', 'genome'
"""

由于原始数据中有的obs_names或者var_names会重名,我们执行unique,在重名names字符串后自动添加1,2等字符使变量名唯一:

adata.var_names_make_unique()
adata.obs_names_make_unique()

adata.X形状为16934 × 36601,分别对应着barcodesnumber of transcripts,var里有三个元素,gene_ids为来自Ensembl的基因id,genome为基因组的名字:

  • Ensembl ID是生物学领域中用于唯一标识基因和其他生物学序列的一种标识符
  • 如果已知genome(基因组的名字),我们可以通过额外的注释数据获得基因组所在的坐标,然后就能为RNA特征和ATAC特征建立关联。
print(adata.var.head())
"""
                    gene_ids    feature_types  genome
MIR1302-2HG  ENSG00000243485  Gene Expression  GRCh38
FAM138A      ENSG00000237613  Gene Expression  GRCh38
OR4F5        ENSG00000186092  Gene Expression  GRCh38
AL627309.1   ENSG00000238009  Gene Expression  GRCh38
AL627309.3   ENSG00000239945  Gene Expression  GRCh38
"""

过滤低质量细胞的指南

这是质量控制的第一步,主要针对三个质控协变量:

  • 1.每个barcode的计数数量(计数深度),barcode即一个细胞样本;
  • 2.每个barcode的基因数量;
  • 3.每个barcode的线粒体基因计数比例;

当检测到基因数量较少,计数深度较低,线粒体计数较高时,细胞膜可能会破裂,这说明细胞正在死亡,这种样本一般都不是我们分析的主要目标,从而误导下游分析,应该去除。

说明:如果一个细胞正在死亡,那么其mRNA被释放到内环境,导致线粒体基因的比例较高,所以可以通过线粒体基因的比例来过滤掉低质量的单细胞测序数据。但是如果仅考虑一个变量可能会造成生物学误差,共同考虑三个 QC 协变量至关重要。例如,线粒体计数相对较高的细胞可能参与呼吸过程,不应被过滤掉。然而,计数低或高的细胞可能对应于静止细胞群或尺寸较大的细胞。故在过滤低质量细胞的时候,要同时考虑不同的QC协变量之间的关系。

对于简单的数据,可以观察数据分布来确定协变量过滤的阈值。随着数据规模的增长,手动观察阈值不可行,我们可以通过计算MAD(median absolute deviations)设置阈值,如果计数大于5倍的MAD,我们可以认为这是一个异常值。

这里使用的数据集是人类骨髓,因此线粒体计数是以“ MT-”前缀注释的。对于鼠数据集,前缀通常是小写“ mt-”。

除了统计线粒体基因比例,scanpy还能统计指定基因的计数比例,比如核糖体,血红蛋白基因:

# 线粒体基因
adata.var["mt"] = adata.var_names.str.startswith("MT-")
# 核糖体基因
adata.var["ribo"] = adata.var_names.str.startswith(("RPS", "RPL"))
# 血红蛋白基因
adata.var["hb"] = adata.var_names.str.contains(("^HB[^(P)]"))

sc.pp.calculate_qc_metrics(
    adata, qc_vars=["mt", "ribo", "hb"], inplace=True, percent_top=[20], log1p=True
)

print(adata)
"""
AnnData object with n_obs × n_vars = 16934 × 36601
    obs: 'n_genes_by_counts', 'log1p_n_genes_by_counts', 'total_counts', 'log1p_total_counts', 'pct_counts_in_top_20_genes', 'total_counts_mt', 'log1p_total_counts_mt', 'pct_counts_mt', 'total_counts_ribo', 'log1p_total_counts_ribo', 'pct_counts_ribo', 'total_counts_hb', 'log1p_total_counts_hb', 'pct_counts_hb'
    var: 'gene_ids', 'feature_types', 'genome', 'mt', 'ribo', 'hb', 'n_cells_by_counts', 'mean_counts', 'log1p_mean_counts', 'pct_dropout_by_counts', 'total_counts', 'log1p_total_counts'
"""

在obs中有三个变量:

  • n_genes_by_counts:一个细胞中发现的有效基因数量(即表达量不为0)
  • total_counts:一个细胞中发现的分子数量(UMI),通常也可以被认为是这个细胞的文库大小(adata.obs['total_counts'] = adata.X.toarray().sum(axis=1)
  • pct_counts_mt:一个细胞中线粒体基因的表达计数占比(adata.obs['pct_counts_mt'] = adata[:, adata.var["mt"]].X.toarray().sum(axis=1) / adata.obs['total_counts'].values

绘制协变量分布图,可以直观看到三个协变量:

mito_filter = 15
n_counts_filter = 4300
fig, axs = plt.subplots(ncols = 2, figsize = (8,4))
sc.pl.scatter(adata, x='total_counts', y='pct_counts_mt',ax = axs[0], show=False)
sc.pl.scatter(adata, x='total_counts', y='n_genes_by_counts',ax = axs[1], show = False)
#draw horizontal red lines indicating thresholds.
axs[0].hlines(y = mito_filter, xmin = 0, xmax = max(adata.obs['total_counts']), color = 'red', ls = 'dashed')
axs[1].hlines(y = n_counts_filter, xmin = 0, xmax = max(adata.obs['total_counts']), color = 'red', ls = 'dashed')
fig.tight_layout()
plt.savefig("./result/2-1.png")

fig1
在这个案例中,首先对双细胞进行过滤(表达量过大),然后进行质控:过滤比如total_counts小于500的细胞,比如n_genes_by_counts小于250的细胞,线粒体基因的计数比例不超过15%。请不要忽视质量控制的每一步,这对后续分析尤为重要

双细胞过滤

双细胞是可能存在的,两个小尺寸细胞容易被同一个液滴捕获,每个液滴被barcode标记,这也是用barcode而不是cell的原因(没有完美单细胞测量,只能说分辨率几乎接近单细胞)。双细胞存在下面两种:

  • 同型:同型通常被认为是不影响下游分析的,因为其是由一类相同的细胞中的两个所构成,所以这部分细胞不是我们所需要过滤的对象
  • 异型:异型通常是由来自两类不同的细胞所构成的,异型的存在会使得我们后续的细胞分类出现错误

使用sc中的scrublet去除异型双细胞:

# Original QC
n0 = adata.shape[0]
print(f'Original cell number: {n0}')

print('Begin of post doublets removal and QC plot')
sc.external.pp.scrublet(adata, random_state=112)
adata = adata[adata.obs['predicted_doublet']==False, :].copy()
n1 = adata.shape[0]
print(f'Cells retained after scrublet: {n1}, {n0-n1} removed.')
print(f'End of post doublets removal and QC plots.')

"""
Cells retained after scrublet: 16931, 3 removed.
"""

在双细胞过滤后,按照指南,过滤低质量读数细胞,我们分别演示手动和自动过滤,所以,复制两份adata:

adata_manual=adata.copy()
adata_auto=adata.copy()

手动过滤低质量读数细胞

首先定义一个过滤字典,然后按照字典进行过滤:

import numpy as np
tresh={'mito_perc': 15, 'nUMIs': 500, 'detected_genes': 250}

adata_manual.obs['passing_mt'] = adata_manual.obs['pct_counts_mt'] < tresh['mito_perc']
adata_manual.obs['passing_nUMIs'] = adata_manual.obs['total_counts'] > tresh['nUMIs']
adata_manual.obs['passing_ngenes'] = adata_manual.obs['n_genes_by_counts'] > tresh['detected_genes']

print(f'Lower treshold, nUMIs: {tresh["nUMIs"]}; filtered-out-cells: {n1-np.sum(adata_manual.obs["passing_nUMIs"])}')
print(f'Lower treshold, n genes: {tresh["detected_genes"]}; filtered-out-cells: {n1-np.sum(adata_manual.obs["passing_ngenes"])}')
print(f'Lower treshold, mito %: {tresh["mito_perc"]}; filtered-out-cells: {n1-np.sum(adata_manual.obs["passing_mt"])}')

保留剩余的细胞的交集:

QC_test = (adata_manual.obs['passing_mt']) & (adata_manual.obs['passing_nUMIs']) & (adata_manual.obs['passing_ngenes'])
removed = QC_test.loc[lambda x : x == False]
print(f'Total cell filtered out with this last  QC (and its chosen options): {n1-np.sum(QC_test)}')
adata_manual = adata_manual[QC_test, :].copy()
n2 = adata_manual.shape[0]
   
print(f'Cells retained after scrublet and filtering: {n2}, {n0-n2} removed.')

最后,再添加一步,直接过滤掉一些从基因和细胞层面低计数的细胞/基因:

sc.pp.filter_cells(adata_manual, min_genes=200)
sc.pp.filter_genes(adata_manual, min_cells=3)
print(adata_manual)

自动过滤低质量读数细胞

自动过滤也需要设置基础最低阈值,MAD计算可以获得最高阈值:

tresh={'pct_counts_mt': 15, 'total_counts': 500, 'n_genes_by_counts': 250}
adata_auto.obs['passing_mt'] = adata_auto.obs['pct_counts_mt'] < tresh['pct_counts_mt']
adata_auto.obs['passing_nUMIs'] = ov.pp._qc.mads_test(adata_auto.obs, 'total_counts', nmads=5, lt=tresh)
adata_auto.obs['passing_ngenes'] = ov.pp._qc.mads_test(adata_auto.obs, 'n_genes_by_counts', nmads=5, lt=tresh)  

nUMIs_t = ov.pp._qc.mads(adata_auto.obs, 'total_counts', nmads=5, lt=tresh)
n_genes_t = ov.pp._qc.mads(adata_auto.obs, 'n_genes_by_counts', nmads=5, lt=tresh)

print(f'Tresholds used, nUMIs: ({nUMIs_t[0]}, {nUMIs_t[1]}); filtered-out-cells: {n1-np.sum(adata_auto.obs["passing_nUMIs"])}')
print(f'Tresholds used, n genes: ({n_genes_t[0]}, {n_genes_t[1]}); filtered-out-cells: {n1-np.sum(adata_auto.obs["passing_ngenes"])}')
print(f'Lower treshold, mito %: {tresh["pct_counts_mt"]}; filtered-out-cells: {n1-np.sum(adata_auto.obs["passing_mt"])}')

剩下步骤与手动注释一样:

QC_test = (adata_auto.obs['passing_mt']) & (adata_auto.obs['passing_nUMIs']) & (adata_auto.obs['passing_ngenes'])
removed = QC_test.loc[lambda x : x == False]
print(f'Total cell filtered out with this last  QC (and its chosen options): {n1-np.sum(QC_test)}')
adata_auto = adata_auto[QC_test, :].copy()
n2 = adata_auto.shape[0]

print(f'Cells retained after scrublet and filtering: {n2}, {n0-n2} removed.')

sc.pp.filter_cells(adata_auto, min_genes=200)
sc.pp.filter_genes(adata_auto, min_cells=3)
print(adata_auto)

环境RNA校正

对于基于液滴的单细胞RNA测序实验,在分配到含有细胞的液滴中存在一定量的背景mRNA,并且随着液滴一起被测序。这样做的结果是产生了一种背景污染,代表了不是来自液滴中包含的细胞,而是来自含有细胞的溶液中的RNA表达。

无细胞的 mRNA 分子,也被称为环境 RNA,混淆了观察到的计数的数量。对于无细胞 mRNA,纠正基于液滴的 scRNA-seq 数据集非常重要,因为它可能会扭曲我们下游分析中数据的解释。具体校正方法参考:soupX

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1658152.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[C++核心编程-05]----C++类和对象之对象的初始化和清理

目录 引言 正文 01-构造函数和析构函数 ​02-构造函数的分类及调用 03-拷贝构造函数调用时机 04-构造函数调用规则 05-深拷贝与浅拷贝 06-初始化列表 07-静态成员变量 08-静态成员函数 …

vue3 - 150

目录 vue优势使用方式编写vue代码指令响应式数据其他 vue优势 功能全面生态好&#xff0c;语法简洁效率高&#xff0c;免去 DOM 操作苦&#xff0c;开发重任一肩挑&#xff01; 使用方式 1.通过cdn引入来将 Vue 应用到整个页面 2.或通过官方脚手架 create-vue来创建完整的v…

Spring-依赖来源

依赖来源 1 Spring BeanDefinition&#xff08;xml,注解&#xff0c;BeanDefinitionBuilder, 还有API实现的单例对象&#xff09; 2 Spring 内建BeanDefinition 3 内建单例对象 依赖注入和依赖查找的区别 Context.refresh() 的时候会调用这个方法&#xff1a;prepareBeanF…

【Linux】-Linux用户和权限[3]

一、认知root用户 1、root用户&#xff08;超级管理员&#xff09; 无论是Windows、MacOS、Linux均采用多用户的管理模式进行权限管理。 在Linux系统中&#xff0c;拥有最大权限的账户为&#xff1a;root&#xff08;超级管理员&#xff09; root用户拥有最大的系统操作权限…

多线程三种实现

多线程 线程 线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中&#xff0c;是进程中的实际运作单位。 &#xff08;理解&#xff1a;应用软件中互相独立&#xff0c;可以同时运行的功能&#xff09; 进程 进程是程序的基本执行实体。&#xff08;理解&#…

部署JVS服务出现上传文件不可用,问题原因排查。

事情的起因是这样的&#xff0c;部门经理让我部署一下JVS资源共享框架&#xff0c;项目的地址是在这里 项目资源地址 各位小伙伴们做好了&#xff0c;我要开始发车了&#xff0c;全新的“裂开之旅” 简单展示一下如何部署JVS文档 直达链接 撕裂要开始了 本来服务启动的好好…

SpringBoot结合Canal 实现数据同步

1、Canal介绍 Canal 指的是阿里巴巴开源的数据同步工具&#xff0c;用于数据库的实时增量数据订阅和消费。它可以针对 MySQL、MariaDB、Percona、阿里云RDS、Gtid模式下的异构数据同步等情况进行实时增量数据同步。 当前的 canal 支持源端 MySQL 版本包括 5.1.x , 5.5.x , 5.6.…

使用tkinter开发的一款可扫描并删除本地文件敏感词的Windows软件

大致功能&#xff1a;可指定扫描Windows上的某个目录的所有文件&#xff0c;单个文件扫描&#xff0c;目前适配支持的文件后缀有&#xff1a;"pdf"、"txt、"doc"、"docx"&#xff0c;软件是开源的&#xff0c;大家可以在此基础上扩展更多类…

什么是HTTP?

什么是HTTP&#xff1f; HTTP基本概念HTTP 是什么&#xff1f;HTTP 常见的状态码有哪些&#xff1f;HTTP 常见字段有哪些&#xff1f; HTTP特性HTTP/1.1 的优点有哪些&#xff1f;HTTP/1.1 的缺点有哪些&#xff1f; HTTP基本概念 HTTP 是什么&#xff1f; HTTP 是超文本传输…

44.乐理基础-音符的组合方式-附点

内容参考于&#xff1a; 三分钟音乐社 首先如下图&#xff0c;是之前的音符&#xff0c;但是它不全&#xff0c;比如想要一个三拍的音符改怎样表示&#xff1f; 在简谱中三拍&#xff0c;在以四分音符为一拍的情况下&#xff0c;在后面加两根横线就可以了&#xff0c;称为附点…

C++:重载、重写与重定义

一、重载、重写与重定义的概念 C中&#xff0c;重载、重写和重定义是三个与函数和类成员相关的概念&#xff0c;但它们具有不同的含义和用途。 重载&#xff1a;是指在同一作用域内&#xff0c;可以有多个名称相同但参数列表&#xff08;参数类型、参数个数或参数顺序&#x…

Web3加密空投入门:空投类型有哪些?如何避免限制?

今天分享空投如何避免限制以提高效率&#xff0c;增加成功几率&#xff0c;首先我们来了解什么是空投加密&#xff0c;有哪些空投类型。 一、什么是空投加密&#xff1f; 加密货币空投是一种营销策略&#xff0c;包括向用户的钱包地址发送免费的硬币或代币。 加密货币项目使用…

【算法练级js+java】旋转字符串判断是否相等

每一天一道算法题训练&#xff0c;努力打开编程思维&#xff0c;才能进大厂光明正大的泡心仪的小姐姐&#xff01;&#xff01;(手动捂脸) 题目 /** * 给定字符创A和B * 旋转字符串A,就是把最左边的移动到最右边 * 比如A‘abcde’,在移动一次之后结果就是bcdea * 如果若干次之…

揭秘新时代的内容创作:一键生成的AI黑科技

在数字媒体的浪潮下&#xff0c;内容创作已成为连接人与信息的重要桥梁。然而&#xff0c;头条、公众号等平台上的爆文创作&#xff0c;对很多内容创作者来说却是一项挑战。“从选题到找素材&#xff0c;再到成文&#xff0c;”这个过程不仅耗时至少1到2个小时&#xff0c;而且…

word图片水印

一、word中旧水印如何删除 打开word模板&#xff0c;想要删除旧水印&#xff0c;如下图所示操作&#xff0c;但是旧水印删除不掉。 以为上传新水印图片会替换掉旧水印&#xff0c;结果显示了2个水印&#xff0c;要怎么删除呢&#xff1f; 如下截图所示&#xff0c;双击打开页…

如何在CentOS上解决Python版本冲突和路径问题

在使用CentOS等Linux系统时&#xff0c;安装多个Python版本可能会导致版本冲突和路径问题。当你运行python3命令时&#xff0c;系统可能不会调用你期望的Python版本&#xff0c;这可能会导致运行错误或者其他依赖问题。下面是一篇详细的博客&#xff0c;介绍如何解决这种Python…

微信小程序发布,推广等步骤

发布小程序 一.首先写好小程序后在微信开发者工具的右上角找到上传并点击 2.填写本次开发版本的版本号和备注信息&#xff0c;点击上传 3.登录微信小程序管理后台 微信公众平台 在管理处找到版本管理 4.在版本管理页面可以看到刚刚提交的小程序已经上传到这里&#xff0c;点击…

如何在两台电脑之间共享文件(超详细步骤)

所需物品&#xff1a; 两台以上电脑一个路由器 步骤1&#xff1a; 将两台电脑用网线或无线网连接至同一路由器下 只有在同一路由器下才能形成局域网&#xff0c;从而才能正常共享文件。例如通常打印机和电脑也需要保持在同一路由器下才能正常打印文件。 步骤2&#xff1a;设置…

【全开源】Java洗衣清洁服务同城清洗服务小程序源码

特色功能&#xff1a; 在线预约与支付&#xff1a;用户可以通过洗衣小程序在线预约洗衣服务&#xff0c;并选择支付方式进行支付&#xff0c;如微信支付、支付宝等。这种在线预约和支付的方式极大地方便了用户&#xff0c;提高了服务的便捷性。智能推荐与选择&#xff1a;根据…

Web 安全基础理论

Web 安全基础理论 培训、环境、资料、考证 公众号&#xff1a;Geek极安云科 网络安全群&#xff1a;624032112 网络系统管理群&#xff1a;223627079 网络建设与运维群&#xff1a;870959784 移动应用开发群&#xff1a;548238632 短视频制作群&#xff1a; 744125867极安云…