引言
本系列讲解 使用Scanpy
分析单细胞(scRNA-seq)数据教程,持续更新,欢迎关注,转发!
BBKNN
BBKNN 可以很好地解决批次效应。
%%time
sc.external.pp.bbknn(adata_all, batch_key="batch")
sc.tl.umap(adata_all)
sc.pl.umap(adata_all, color=["batch", "celltype"])
如果有人更倾向于从一个参考数据集开始迭代工作,可以使用 ingest。
使用 ingest 映射到参考批次
选择一个参考批次来训练模型并建立邻域图(这里使用 PCA),并分离出所有其他批次。
和之前一样,训练于参考批次的模型将解释其中观察到的生物学变异。
adata_ref = adata_all[adata_all.obs["batch"] == "0"].copy()
在参考数据上计算 PCA和 UMAP。
sc.pp.pca(adata_ref)
sc.pp.neighbors(adata_ref)
sc.tl.umap(adata_ref)
参考批次包含了所有批次中 19 种细胞类型中的 12 种。
sc.pl.umap(adata_ref, color="celltype")
迭代地将参考数据中的标签(如 “celltype”)和嵌入(如 “X_pca” 和 “X_umap”)映射到查询批次。
adatas = [adata_all[adata_all.obs["batch"] == i].copy() for i in ["1", "2", "3"]]
sc.settings.verbosity = 2 # a bit more logging
for iadata, adata in enumerate(adatas, 1):
print(f"... integrating batch {iadata}")
adata.obs["celltype_orig"] = adata.obs["celltype"] # save the original cell type
sc.tl.ingest(adata, adata_ref, obs="celltype")
现在每个查询批次都带有与 adata_ref 相关联的注释。通过合并,我们可以一起查看它们。
adata_concat = anndata.concat([adata_ref, *adatas], label="batch", join="outer")
adata_concat.obs["celltype"] = (
adata_concat.obs["celltype"]
.astype("category")
.cat.reorder_categories(adata_ref.obs["celltype"].cat.categories)
)
# fix category coloring
adata_concat.uns["celltype_colors"] = adata_ref.uns["celltype_colors"]
sc.pl.umap(adata_concat, color=["batch", "celltype"])
与 BBKNN 的结果相比,这种方法在保持聚类方面表现得更为明显。如果已经观察到期望的连续结构(例如在造血数据集中),ingest 可以轻松地保持这种结构。
评估一致性
我们先将数据限定在查询批次中。
adata_query = adata_concat[adata_concat.obs["batch"].isin(["1", "2", "3"])].copy()
接下来的图表有点难以阅读,因此我们转而查看下面的混淆矩阵。
sc.pl.umap(adata_query, color=["batch", "celltype", "celltype_orig"], wspace=0.4)
跨批次保留的细胞类型
我们首先关注与参考数据一致的细胞类型,以便简化混淆矩阵的阅读。
# intersected categories
conserved_categories = adata_query.obs["celltype"].cat.categories.intersection(
adata_query.obs["celltype_orig"].cat.categories
)
# intersect categories
obs_query_conserved = adata_query.obs.loc[
adata_query.obs["celltype"].isin(conserved_categories)
& adata_query.obs["celltype_orig"].isin(conserved_categories)
].copy()
# remove unused categories
obs_query_conserved["celltype"] = obs_query_conserved[
"celltype"
].cat.remove_unused_categories()
# remove unused categories and fix category ordering
obs_query_conserved["celltype_orig"] = (
obs_query_conserved["celltype_orig"]
.cat.remove_unused_categories()
.cat.reorder_categories(obs_query_conserved["celltype"].cat.categories)
)
pd.crosstab(obs_query_conserved["celltype"], obs_query_conserved["celltype_orig"])
总体而言,保留的细胞类型也如预期般被映射。主要的例外是一些在原始注释中表现为腺泡细胞的腺泡细胞。然而,参考数据本身就存在一个包含腺泡细胞和导管细胞的聚类,这解释了这种差异,并暗示了初始注释可能存在潜在的不一致性。
所有细胞类型
现在我们来看所有细胞类型。
pd.crosstab(adata_query.obs["celltype"], adata_query.obs["celltype_orig"])
我们发现,胰腺星状细胞(PSC)实际上只是被不一致地注释了,并且正确地映射到了 “activated_stellate” 细胞上。
此外,看到 “间充质” 和 “间充质的” 细胞都被映射到了同一个类别上,这是很有趣的。然而,那个类别又是 “activated_stellate”,可能并不正确。
跨批次的可视化
通常,批次对应于人们想要比较的实验。Scanpy 为此提供了两种便捷的可视化方式。
一种是密度图,另一种是在嵌入中对类别/组的一个子集的部分可视化。
密度图
sc.tl.embedding_density(adata_concat, groupby="batch")
sc.pl.embedding_density(adata_concat, groupby="batch")
在嵌入中对一个组的子集的部分可视化
import matplotlib.pyplot as plt
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
for batch, ax in zip(["1", "2", "3"], axes):
sc.pl.umap(adata_concat, color="batch", groups=[batch], ax=ax, show=False)