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

学习资料来源:

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

推荐阅读更多精彩内容