话不多说先上官网:
- ScanPy官网:Preprocessing and clustering 3k PBMCs (legacy workflow)
- 官方数据集下载:pbmc3k_filtered_gene_bc_matrices.tar.gz
- 如果使用R语言的话,可以参考我写的另一篇:Seurat - Guided Clustering Tutorial官方文档学习及复现区别就是本文是Python代码复现(借鉴的Seurat),Seurat是R语言。
由于之前已经对Seurat中的10x Genomics
数据集的教程进行了复现,所以这篇文档只是参考官方教程来进行撰写的,会加入自己的理解以及教程中没有涉及到的扩展的内容,本文的代码会使用大模型来添加注释,每段代码都会加注释方便学习和理解。
1 ScanPy和Seurat的故事
看到ScanPy官网上第一句话是:In May 2017, this started out as a demonstration that Scanpy would allow to reproduce most of Seurat's guided clustering tutorial (Satija et al., 2015).We gratefully acknowledge Seurat's authors for the tutorial! In the meanwhile, we have added and removed a few pieces.
感觉还是挺有意思的,就去了解了一下,写个小前言。
Seurat先行:Seurat于2015年发布,是较早的单细胞RNA测序分析平台之一。
Scanpy借鉴:Scanpy在2017年开发,其设计受到Seurat的启发,官网提到Scanpy可复制Seurat的大部分引导式聚类教程,表明Scanpy在功能和流程设计上借鉴了Seurat的一些思路和方法 。
Seurat适用于R语言编程环境,能与R的其他生物信息学包集成。Scanpy适用于Python编程环境,能与Python的科学计算和机器学习库协同工作,适合更灵活的数据分析和可视化需求。
功能实现与算法上的对比
- SNN图生成:两软件在SNN图的生成上存在差异,Seurat在默认情况下比Scanpy给出更多的高连接SNN图。
- 聚类差异:使用默认设置时,两软件的Louvain聚类结果不同,但在Leiden算法实现上相同。
- 差异表达分析(DEA) :显著性差异基因 :Seurat的显著性marker基因比Scanpy多约50%,这主要是由于两软件在Wilcoxon功能的实现上有所不同,Seurat需要tie校正,而Scanpy默认省略;同时,两软件在调整p值的方法上也不同,Seurat采用Bonferroni multiple testing correction,而Scanpy采用Benjamini-Hochberg多重测试校正。过滤机制:Seurat在执行Wilcoxon秩和检验之前会进行过滤,而Scanpy在不调用其他函数的情况下不会进行这种过滤。
2 Preparation
2.1 import data and packages
首先准备工作就是引入数据集,安装对应的包。
官方数据集下载:pbmc3k_filtered_gene_bc_matrices.tar.gz
装包,官方文档:https://scanpy.readthedocs.io/en/stable/installation.html
bash
$ pip install scanpy
python
# 导库
import numpy as np # 数值计算
import pandas as pd # 数据处理
import scanpy as sc # Scanpy单细胞RNA测序数据分析工具包
# 设置日志的详细程度,0表示只显示错误,1显示警告,2显示信息,3显示提示
sc.settings.verbosity = 3
# 打印Scanpy包的头信息,包括版本号等信息
sc.logging.print_header()
# 设置绘图参数,设置图片的分辨率(dpi)为80,并将背景颜色设置为白色
sc.settings.set_figure_params(dpi=80, facecolor='white')
# 指定用于存储分析结果文件的路径,结果将写入到'write/pbmc3k.h5ad'文件中
results_file = 'write/pbmc3k.h5ad'
# 从指定的目录读取10x Genomics格式的数据文件
# 参数./filtered_gene_bc_matrices/hg19/是存放MTX文件的目录
# 参数var_names='gene_symbols'表示使用基因符号作为变量名
# 参数cache=True表示缓存文件,以便以后更快地读取
adata = sc.read_10x_mtx(
'./filtered_gene_bc_matrices/hg19/', # 数据文件所在目录
var_names='gene_symbols', # 变量名使用基因符号
cache=True) # 缓存文件,以便后续快速加载
2.2 pre - processing
python
# 绘制单细胞RNA测序数据中最高表达的基因的表达分布图。
sc.pl.highest_expr_genes(adata, n_top=20)

python
# 过滤低质量细胞样本
# filtered out 19024 genes that are detected in less than 3 cells
sc.pp.filter_cells(adata, min_genes=200)
sc.pp.filter_genes(adata, min_cells=3)
High proportions are indicative of poor-quality cells (Islam et al. 2014; Ilicic et al. 2016), possibly because of loss of cytoplasmic RNA from perforated cells. The reasoning is that mitochondria are larger than individual transcript molecules and less likely to escape through tears in the cell membrane.
高比例表明细胞质量差(Islam 等人,2014 年;Ilicic 等人,2016 年),可能是因为穿孔细胞的细胞质 RNA 丢失。原因是线粒体比单个转录物分子大,不太可能通过细胞膜中的撕裂逃逸。
使用 ,我们可以非常高效地计算许多指标。
pp.calculate_qc_metrics
其实就是说,线粒体基因表达比例过高可能是因为细胞受损,导致细胞质中的RNA丢失,而线粒体基因相对保留得更多。我们可以用 pp.calculate_qc_metrics 这个工具来计算相关指标,从而判断细胞的质量。
python
# 将线粒体基因标记为 'mt'
# 创建一个新的列 'mt',用于标记线粒体基因。
# 如果基因名以 "MT-" 开头,则认为它是线粒体基因,标记为 True;否则标记为 False。
adata.var["mt"] = adata.var_names.str.startswith("MT-")
# 计算质量控制(QC)指标
sc.pp.calculate_qc_metrics(
adata, # 输入的 AnnData 对象
qc_vars=["mt"], # 指定需要计算的 QC 指标变量,这里计算线粒体基因(mt)相关的指标
percent_top=None, # 不计算最高表达基因的百分比(默认值)
log1p=False, # 不对结果取 log1p 变换(默认值)
inplace=True # 将计算结果直接存储在 adata 对象中
)
python
sc.pl.violin(
adata,
["n_genes_by_counts", "total_counts", "pct_counts_mt"],
jitter=0.4,
multi_panel=True,
)
基因的数量,每个细胞包含的表达量,线粒体基因表达量的百分比绘图如下:

去除表达线粒体基因过多或总计数过多的细胞:
python
import matplotlib.pyplot as plt
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
# 在第一个子图中绘制总表达量与线粒体基因比例的关系
sc.pl.scatter(adata, x="total_counts", y="pct_counts_mt", ax=axes[0], show=False)
axes[0].set_title("Total Counts vs. Percent Mitochondrial Counts")
# 在第二个子图中绘制总表达量与检测到的基因数的关系
sc.pl.scatter(adata, x="total_counts", y="n_genes_by_counts", ax=axes[1], show=False)
axes[1].set_title("Total Counts vs. Number of Genes by Counts")
plt.tight_layout()
plt.show()

3 Slicing highly-variable genes
python
# 筛选检测到的基因数小于2500的细胞
# adata.obs.n_genes_by_counts 是一个包含每个细胞检测到的基因数的列
# 这里我们保留基因数小于2500的细胞,排除基因数过多的异常细胞
adata = adata[adata.obs.n_genes_by_counts < 2500, :]
# 筛选线粒体基因比例小于5%的细胞
# adata.obs.pct_counts_mt 是一个包含每个细胞线粒体基因表达比例的列
# 这里我们保留线粒体基因比例小于5%的细胞,排除可能受损的细胞
adata = adata[adata.obs.pct_counts_mt < 5, :].copy()
python
# 对数据进行总和归一化,使每个细胞的总表达量(UMI数)标准化为目标值
sc.pp.normalize_total(adata, target_sum=1e4)
normalizing counts per cell
finished (0:00:00)
python
# 做对数
sc.pp.log1p(adata)
python
# 寻找高变基因,指在不同细胞中表达水平差异较大的基因,这些基因通常在后续分析中更具生物学意义
sc.pp.highly_variable_genes(adata, min_mean=0.0125, max_mean=3, min_disp=0.5)
# 画图
sc.pl.highly_variable_genes(adata)
extracting highly variable genes
finished (0:00:00)
--> added
'highly_variable', boolean vector (adata.var)
'means', float vector (adata.var)
'dispersions', float vector (adata.var)
'dispersions_norm', float vector (adata.var)

4 Obtain datasets with only high-variable genes
python
# 仅保留高变基因
adata = adata[:, adata.var.highly_variable]
# adata.var.highly_variable 是一个布尔数组,表示每个基因是否为高变基因。
# 使用线性回归去除总表达量和线粒体基因比例的影响
sc.pp.regress_out(adata, ["total_counts", "pct_counts_mt"])
# 1. total_counts:每个细胞的总表达量(UMI数)。
# 2. pct_counts_mt:每个细胞的线粒体基因表达比例。
# 对数据进行标准化(Z-score标准化),并将值限制在 [-10, 10] 范围内
sc.pp.scale(adata, max_value=10)
# max_value=10 参数限制了标准化后的值范围,避免极端值对后续分析(如降维)产生过大影响。
# 标准化后的数据更适合用于主成分分析 PCA
5 Principal component analysis (PCA)
用PCA来降维,为什么?(思考一下)
python
# 对数据进行PCA降维
sc.tl.pca(adata, svd_solver="arpack")
在 PCA 坐标中制作散点图,但之后用不到
python
sc.pl.pca(adata, color="CST3")

检查一下单个 PC 对数据总方差的贡献。这为我们提供了有关我们应该考虑多少台 PC 的信息,以便计算单元的邻域关系,例如用于聚类函数或 tSNE 。根据我们的经验,通常粗略估计 PC 的数量就可以了。
python
sc.pl.pca_variance_ratio(adata, log=True)
保存结果
python
adata.write(results_file)
adata
bash
AnnData object with n_obs × n_vars = 2638 × 1838
obs: 'n_genes', 'n_genes_by_counts', 'total_counts', 'total_counts_mt', 'pct_counts_mt'
var: 'gene_ids', 'n_cells', 'mt', 'n_cells_by_counts', 'mean_counts', 'pct_dropout_by_counts', 'total_counts', 'highly_variable', 'means', 'dispersions', 'dispersions_norm', 'mean', 'std'
uns: 'log1p', 'hvg', 'pca'
obsm: 'X_pca'
varm: 'PCs'
6 Computing the neighborhood graph
为了重现 Seurat 的结果,官网取以下值:
python
sc.pp.neighbors(adata, n_neighbors=10, n_pcs=40)
bash
computing neighbors
using 'X_pca' with n_pcs = 40
finished: added to `.uns['neighbors']`
`.obsp['distances']`, distances for each pair of neighbors
`.obsp['connectivities']`, weighted adjacency matrix (0:00:22)
7 Embedding the neighborhood graph
建议使用 UMAP 将图形嵌入两个维度,它可能比 tSNE 更忠实于流形的全局连接性,即它更好地保留了轨迹。
python
sc.tl.umap(adata)
sc.pl.umap(adata, color=["CST3", "NKG7", "PPBP"])

前面的图显示了 "原始" (归一化、对数化但未校正) 基因表达,还可以通过 use_raw = False
来绘制缩放和校正的基因表达。
python
sc.pl.umap(adata, color=["CST3", "NKG7", "PPBP"], use_raw=False)

8 Clustering the neighborhood graph
scanPy里面推荐使用leiden
来绘制,首先你要先安装igraph(pip3)
bash
pip3 install igraph
bash
conda install -c conda-forge python-igraph
python
sc.tl.leiden(
adata,
resolution=0.9,
random_state=0,
flavor="igraph",
n_iterations=2,
directed=False,
)
绘制聚类
python
sc.pl.umap(adata, color=["leiden", "CST3", "NKG7"])
保存结果
python
adata.write(results_file)
9 Finding marker genes
10 思考
10.1 什么是PCA降维?
PCA用于将高维数据转换为低维数据,同时尽可能保留原始数据中的主要变异信息。简单来说,PCA通过以下步骤实现降维:
- 寻找主成分:PCA通过计算数据的协方差矩阵,找到一组正交的"主成分"(即新的坐标轴)。这些主成分是数据中变异最大的方向。
- 投影数据:将原始数据投影到这些主成分上,得到新的低维表示。主成分的数量通常远小于原始数据的维度。
- 保留主要变异:通过选择前几个主成分(通常解释了大部分数据的变异),可以将数据从高维空间压缩到低维空间,同时保留最重要的信息。
数据集是几维的?
在单细胞RNA测序数据中,每个细胞的基因表达值构成了数据的一个维度。假设你的数据集中有 n
个细胞 和 m
个基因 ,那么数据集的维度可以理解为 m
维,其中每一维代表一个基因的表达值。
例如:如果数据集中有 10,000 个基因,那么数据集就是 10,000 维的。每个细胞是一个 10,000 维的向量,表示其在每个基因上的表达值。
10.2 为什么要降维?
单细胞RNA测序数据通常是高维的(基因数可能达到数千甚至数万),但实际的生物学信息可能集中在少数几个维度上。高维数据存在以下问题:
- 计算复杂度高:高维数据的分析(如聚类、分类等)计算成本很高。
- 噪声干扰:高维数据中可能包含大量噪声,掩盖了真正的生物学信号。
- "维度灾难":在高维空间中,数据点之间的距离变得不明显,难以进行有效的分析。
因此,降维的目的是:
- 降低计算成本:将数据从高维空间压缩到低维空间,减少计算复杂度。
- 去除噪声:通过保留主要变异信息,去除无关的噪声。
- 便于可视化:低维数据(如二维或三维)可以更容易地进行可视化和解释。
- 提高分析效率:低维数据更适合进行后续的聚类、分类、轨迹推断等分析。
python
# 对数据进行PCA降维
sc.tl.pca(adata, svd_solver="arpack")
svd_solver="arpack"
:指定用于计算奇异值分解(SVD)的求解器。arpack
是一种高效的稀疏矩阵求解器,适用于大规模数据。
运行该代码后,PCA 的结果会被存储在 adata.obsm['X_pca']
中,这是一个低维矩阵,每一行代表一个细胞在主成分空间中的坐标。通常,前几个主成分(如前 20 个)会被用于后续的分析。
- PCA降维:将高维数据转换为低维数据,保留主要变异信息。
- 数据集维度 :单细胞数据通常是基因数(
m
)维的。 - 降维原因:降低计算成本、去除噪声、便于可视化和提高分析效率。
