scanpy官方教程2022||01-Preprocessing and clustering 3k PBMCs

学习资料来源:

  • scanpy主页:https://scanpy.readthedocs.io/en/stable/
  • 官网:https://scanpy-tutorials.readthedocs.io/en/latest/pbmc3k.html【注意教程有两个版本,这里是latest版本的学习笔记】

00 环境准备

安装教程:https://scanpy.readthedocs.io/en/stable/installation.html

我这里安装的版本为:scanpy 1.9.1 是最新版

# linux环境,使用conda安装软件
conda create -y -n scanpy python=3
conda activate scanpy
conda install seaborn scikit-learn statsmodels numba pytables -y
conda install -c conda-forge python-igraph leidenalg -y
pip install scanpy

scanpy可以进行:单细胞数据聚类,可视化,轨迹分析,数据整合,空间数据分析等

image-20220718104145202.png

本次学习使用scanpy进行单细胞数据基础分析:分群聚类注释

01 数据准备

数据来自10x官网:The data consist of 3k PBMCs from a Healthy Donor and are freely available from 10x Genomics

主要的分析结果过程与Seurat官网的教程:https://satijalab.org/seurat/articles/pbmc3k_tutorial.html 基本一致,两个软件的结果也可以进行一下对比

下载链接:https://support.10xgenomics.com/single-cell-gene-expression/datasets/1.1.0/pbmc3k

Note:注意数据下载链接,官网也有不同的数据版本,数据版本为datasets/1.1.0/pbmc3k

# 官网使用的wget下载数据,我们这里改用axel多线程命令下载数据
mkdir -p data/pbmc3k
cd data/pbmc3k
axel -n 100 http://cf.10xgenomics.com/samples/cell-exp/1.1.0/pbmc3k/pbmc3k_filtered_gene_bc_matrices.tar.gz

# 解压数据
tar -xzf pbmc3k_filtered_gene_bc_matrices.tar.gz

数据为10X上游cellranger的标准输出结果:

image-20220718105556786.png

02 数据读取

在python交互环境中运行:

import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import pandas as pd
import scanpy as sc
import seaborn as sns

# verbosity: errors (0), warnings (1), info (2), hints (3)
sc.settings.verbosity = 3
sc.logging.print_header()
#sc.settings.set_figure_params(dpi=80, facecolor='white')

adata = sc.read_10x_mtx('data/pbmc3k/filtered_gene_bc_matrices/hg19/', 
                        var_names='gene_symbols', 
                        cache=True) 

# this is unnecessary if using `var_names='gene_ids'` in `sc.read_10x_mtx`
adata.var_names_make_unique()
adata

到此,生成了一个anndata对象,包括2700个细胞,32738基因

AnnData object with n_obs × n_vars = 2700 × 32738
    var: 'gene_ids'

对象结构剖析可以参考官方说明:https://anndata.readthedocs.io/en/latest/

image-20220301095945349.png

03 数据预处理

显示那些在所有细胞中,每个单细胞中产生最高Counts的基因

sc.pl.highest_expr_genes(adata, n_top=20,)
plt.savefig("./01-highest_expr_genes.png")
image-20220718111442147.png

数据过滤:

  • 细胞:空的液滴过滤,每个细胞中至少有200个基因表达
  • 基因:低表达基因过滤,每个基因至少在三个细胞中表达
sc.pp.filter_cells(adata, min_genes=200)
sc.pp.filter_genes(adata, min_cells=3)

过滤后的结果:h还剩下2700个细胞 × 13714个基因

adata

AnnData object with n_obs × n_vars = 2700 × 13714
    obs: 'n_genes'
    var: 'gene_ids', 'n_cells'

关于线粒体基因:

线粒体基因含量高的问题(Lun, McCarthy & Marioni, 2017):

高比例表明细胞质量差(Islam et al. 2014; Ilicic et al. 2016) ,可能是因为穿孔细胞失去了细胞质 RNA,而线粒体比单个转录分子大,不太可能通过细胞膜上的裂口逃脱。

# 让我们收集一些关于线粒体基因的信息,这对质量控制很重要
# annotate the group of mitochondrial genes as 'mt'
adata.var['mt'] = adata.var_names.str.startswith('MT-')
sc.pp.calculate_qc_metrics(adata, qc_vars=['mt'], percent_top=None, log1p=False, inplace=True)

查看数据变化:

adata.var

                      gene_ids  n_cells     mt  n_cells_by_counts  mean_counts  pct_dropout_by_counts  total_counts
AL627309.1     ENSG00000237683        9  False                  9     0.003333              99.666667           9.0
AP006222.2     ENSG00000228463        3  False                  3     0.001111              99.888889           3.0
RP11-206L10.2  ENSG00000228327        5  False                  5     0.001852              99.814815           5.0
RP11-206L10.9  ENSG00000237491        3  False                  3     0.001111              99.888889           3.0
LINC00115      ENSG00000225880       18  False                 18     0.006667              99.333333          18.0
...                        ...      ...    ...                ...          ...                    ...           ...
AC145212.1     ENSG00000215750       16  False                 16     0.006667              99.407407          18.0
AL592183.1     ENSG00000220023      323  False                323     0.134815              88.037037         364.0
AL354822.1     ENSG00000215615        8  False                  8     0.002963              99.703704           8.0
PNRC2-1        ENSG00000215700      110  False                110     0.042963              95.925926         116.0
SRSF10-1       ENSG00000215699       69  False                 69     0.025926              97.444444          70.0

[13714 rows x 7 columns]

小提琴绘制三幅质控图:

  • 每个细胞中表达的基因个数
  • 每个细胞中的总counts数
  • 每个细胞中线粒体基因表达的比例
# 画图
outdir = "./"
sc.pl.violin(adata, ['n_genes_by_counts', 'total_counts', 'pct_counts_mt'],
             jitter=0.4, multi_panel=True)
plt.savefig(outdir + './02-violin_qc.jpg')

可以看到大多数细胞表达的基因个数在1000以下接近800个左右,线粒体百分比在5%以下:

image-20220718113512541.png

线粒体基因过滤:

# 去除那些线粒体基因表达过多或总数过多的细胞
sc.pl.scatter(adata, x='total_counts', y='pct_counts_mt')
plt.savefig(outdir + './03-pct_counts_mt.jpg')

sc.pl.scatter(adata, x='total_counts', y='n_genes_by_counts')
plt.savefig(outdir + './03-n_genes_by_counts.jpg')

## 过滤:线粒体百分比<5%,基因个数<2500
adata = adata[adata.obs.n_genes_by_counts < 2500, :]
adata = adata[adata.obs.pct_counts_mt < 5, :]

adata

View of AnnData object with n_obs × n_vars = 2638 × 13714
    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'
image-20220718114413836.png
image-20220718114426125.png

数据标准化:

# Total-count normalize (library-size correct) the data matrix X to 10,000 reads per cell
sc.pp.normalize_total(adata, target_sum=1e4)
sc.pp.log1p(adata)

高变基因鉴定:

# Identify highly-variable genes
sc.pp.highly_variable_genes(adata, min_mean=0.0125, max_mean=3, min_disp=0.5)
sc.pl.highly_variable_genes(adata)
plt.savefig(outdir + './04-highly_variable_genes.jpg')
image-20220718115018136.png

数据保存:

adata.raw = adata

# regress_out掉total_counts与mt的影响
sc.pp.regress_out(adata, ['total_counts', 'pct_counts_mt'])

数据归一化

通过主成分分析(PCA)对数据进行降维,揭示数据的主要变化轴,对数据进行降噪处理

# Scale each gene to unit variance. Clip values exceeding standard deviation 10
sc.pp.scale(adata, max_value=10)

04 PCA分析

通过运行主成分分析分析(PCA)来降低数据的维数,它揭示了变化的主轴,并去除了数据的噪音。

# Reduce the dimensionality of the data
sc.tl.pca(adata, svd_solver='arpack')
sc.pl.pca(adata, color='CST3')
plt.savefig(outdir + './05-PCA.jpg')

# PC可视化
sc.pl.pca_variance_ratio(adata, log=True)
plt.savefig(outdir + './05-pca_variance.jpg')

# 保存结果
adata.write(outdir + 'pbmc3k.h5ad')
image-20220718124235165.png

PC贡献度:

image-20220718124301260.png

05 聚类

构建neighborhood graph,在这里推荐使用UMAP进行聚类可视化:We suggest embedding the graph in two dimensions using UMAP (McInnes et al., 2018)。

  • 它可能比tSNE更忠实于流形的全局连通性,也就是说,它能更好地保存轨迹。
  • 在某些情况下,可能仍然会观察到断开连接的clusters和类似的连接冲突。
## 计算KNN Graph
sc.pp.neighbors(adata, n_neighbors=10, n_pcs=40)

# Embedding the neighborhood graph
sc.tl.umap(adata)
sc.pl.umap(adata, color=['CST3', 'NKG7', 'PPBP'])
plt.savefig(outdir + './06-umap1.jpg')

sc.pl.umap(adata, color=['CST3', 'NKG7', 'PPBP'], use_raw=False)
plt.savefig(outdir + './06-umap2.jpg')

降维聚类可视化:

image-20220718132232536.png

与Seurat和许多其他框架一样,我们推荐Traag et al. (2018)提出的Leiden graph-clustering method(基于优化模块化的社区检测)。注意Leiden直接聚类细胞的邻域图,我们已经在前一节计算过了:

## Clustering the neighborhood graph
# resolution默认为1,这里聚类数可能跟官网会有点不一样
sc.tl.leiden(adata,resolution=0.9)
sc.pl.umap(adata, color=['leiden', 'CST3', 'NKG7'])
plt.savefig(outdir + './06-umap3.jpg',dpi=800,bbox_inches = 'tight')

## save
adata.write(outdir + 'pbmc3k.h5ad')

聚类结果:这里聚成了9类,官网是8类:

image-20220718170437147.png

06 鉴定markers

让我们计算每个cluster中差异较大的基因的排名。为此,默认情况下,使用AnnData的.raw属性以防它之前被初始化。最简单、最快的方法是t检验:

# Finding marker genes
# t-test
sc.tl.rank_genes_groups(adata, 'leiden', method='t-test')
sc.pl.rank_genes_groups(adata, n_genes=25, sharey=False)
plt.savefig(outdir + './07-rank_genes1.jpg',dpi=800,bbox_inches = 'tight')

t检验:

image-20220718170934215.png

也可以使用秩和检验wilcoxon: Wilcoxon rank-sum (Mann-Whitney-U)

We recommend using the latter in publications, see e.g., Sonison & Robinson (2018)。

# wilcoxon
sc.tl.rank_genes_groups(adata, 'leiden', method='wilcoxon')
sc.pl.rank_genes_groups(adata, n_genes=25, sharey=False)
plt.savefig(outdir + './07-rank_genes2.jpg')

## save
adata.write(outdir + 'pbmc3k.h5ad')

wilcoxon:

image-20220718171844147.png

当然,还可以考虑更强大的差异测试包,比如 MAST, limma, DESeq2 and, 对于 python,还有最近的 affxpy

还有另一种选择,用逻辑回归对基因进行排序。例如,这是由Natranos et al. (2018)提出的。本质的区别是,这里,我们使用多变量评估,而传统的差分检验是单变量,Clark et al. (2014)提供更多的细节。

# using logistic regression
sc.tl.rank_genes_groups(adata, 'leiden', method='logreg')
sc.pl.rank_genes_groups(adata, n_genes=25, sharey=False)
plt.savefig(outdir + './07-rank_genes3.jpg')

logreg:

image-20220718171947302.png

除IL7R仅通过t检验和FCER1A仅通过另外两种鉴定方法发现外,所有方法均覆盖了所有的标记基因。

官网给的是8个群的marker,我们需要改成自己对应的9群的一个结果:

image-20220301115115174.png
# Let us also define a list of marker genes for later reference
marker_genes = ['IL7R', 'CD79A', 'MS4A1', 'CD8A', 'CD8B', 'LYZ', 'CD14',
                'LGALS3', 'S100A8', 'GNLY', 'NKG7', 'KLRB1',
                'FCGR3A', 'MS4A7', 'FCER1A', 'CST3', 'PPBP']

重新加载之前Wilcoxon Rank-Sum test保存的数据

adata = sc.read(outdir + 'pbmc3k.h5ad')

# Show the 10 top ranked genes per cluster 0, 1, …, 7,8 in a dataframe.
pd.DataFrame(adata.uns['rank_genes_groups']['names']).head(5)

       0       1         2     3     4       5       6         7      8
0   LDHB     LYZ      CD74  CCL5  NKG7    LST1  MALAT1  HLA-DPA1    PF4
1  RPS12  S100A9     CD79A  NKG7  GNLY  FCER1G   RPL32  HLA-DPB1   SDPR
2  RPS25  S100A8   HLA-DRA  CST7  GZMB  FCGR3A  RPL27A   HLA-DRA  GNG11
3   CD3D  TYROBP     CD79B   B2M  CTSW    AIF1   RPS27  HLA-DRB1   PPBP
4   RPS3     FTL  HLA-DPB1  GZMA  PRF1   COTL1   RPL13      CD74   NRGN

得到一个分数和组表:

# Get a table with the scores and groups.
result = adata.uns['rank_genes_groups']
groups = result['names'].dtype.names
pd.DataFrame(
    {group + '_' + key[:1]: result[key][group]
    for group in groups for key in ['names', 'pvals']}).head(5)
image-20220718173013421.png

与单个cluster进行比较:0 vs 1

# Compare to a single cluster:
sc.tl.rank_genes_groups(adata, 'leiden', groups=['0'], reference='1', method='wilcoxon')
sc.pl.rank_genes_groups(adata, groups=['0'], n_genes=20)
plt.savefig(outdir+'./08-marker1.jpg')

更详细的可视化:0 vs 1

sc.pl.rank_genes_groups_violin(adata, groups='0', n_genes=8)
plt.savefig(outdir+'./08-marker_violin.jpg')

加载之前的差异分析结果:看0 vs rest

adata = sc.read(outdir + 'pbmc3k.h5ad')
sc.pl.rank_genes_groups_violin(adata, groups='0', n_genes=8)
plt.savefig(outdir+'./09-marker_violin.jpg')
image-20220718173324532.png

如果你想在不同cluster之间比较某个基因,请使用以下方法:

# compare a certain gene across groups
sc.pl.violin(adata, ['CST3', 'NKG7', 'PPBP'], groupby='leiden')
plt.savefig(outdir+'./09-marker_violin1.jpg',dpi=800,bbox_inches = 'tight')

'CST3', 'NKG7', 'PPBP'的结果:

image-20220718173534828.png

定义细胞群:

# 首先看不同的marker在亚群中的表达情况:
# visualize the marker genes
sc.pl.dotplot(adata, marker_genes, groupby='leiden')
plt.savefig(outdir+'./09-marker_dotplot.jpg',dpi=800,bbox_inches = 'tight')
image-20220718173734492.png

手动注释亚群:这里有个点,不支持多个cluster是同一种细胞类型的格式,

后来找到了解决办法,参考:https://mp.weixin.qq.com/s/cevuK4znyWLND4t5X-xrfA

# mark the cell types
new_cluster_names = [
    'CD4 T', 
    'CD14 Monocytes',
    'B', 
    'CD8 T',
    'NK', 
    'FCGR3A Monocytes',
    'CD4 T',
    'Dendritic', 
    'Megakaryocytes']

adata.rename_categories('leiden', new_cluster_names)
#ValueError: Categorical categories must be unique
#不支持多个cluster是同一种细胞类型的格式,换一种方式添加细胞类型

# 换一种方式添加细胞类型
new_cluster_names_unique=list(set(new_cluster_names))
new_cluster_names_unique.sort(key=new_cluster_names.index)
celltype = [new_cluster_names[int(i)] for i in adata.obs.leiden.values.tolist()]
adata.obs.leiden = celltype
adata.obs.leiden = adata.obs.leiden.astype('category')
adata.obs.leiden.cat.set_categories(new_cluster_names_unique, inplace=True)

sc.pl.umap(adata, color='leiden', legend_loc='on data', title='', frameon=False)
plt.savefig(outdir+'./09-marker_annotation.jpg',dpi=1000,bbox_inches = 'tight')

注释之后的结果:

image-20220718181526742.png

marker基因可视化:

## 注释之后的marker可视化
sc.pl.dotplot(adata, marker_genes, groupby='leiden')
plt.savefig(outdir+'./09-marker_annotation-dotplot.jpg',dpi=1000,bbox_inches = 'tight')
# 小提琴图
sc.pl.stacked_violin(adata, marker_genes, groupby='leiden', rotation=90);
plt.savefig(outdir+'./09-marker_annotation-violin.jpg',dpi=1000,bbox_inches = 'tight')

气泡图:

image-20220718181707433.png

小提琴图:

image-20220718181941799.png

最后数据保存:

## 最终结果保存
# `compression='gzip'` saves disk space, but slows down writing and subsequent reading
adata.write(outdir + 'pbmc3k.h5ad', compression='gzip')

你可能感兴趣的:(scanpy官方教程2022||01-Preprocessing and clustering 3k PBMCs)