37. 降维#
关键要点
用 UMAP 对 ADT 数据做可视化;对于包含大量表面蛋白的大型数据集,PCA 有助于降低维度。
环境设置
安装 conda:
在创建环境之前,请确保 conda 已安装在您的系统中。
保存 yml 内容:
将 yml 选项卡中的内容复制到名为
environment.yml的文件中。
创建环境:
打开终端或命令提示符。
运行以下命令:
conda env create -f environment.yml
激活环境:
创建好环境后,使用以下命令激活它:
conda activate <environment_name>
替换
<environment_name>,名称就是在environment.yml文件中指定的那个。在 yml 文件里,它看起来像这样:name: <environment_name>
验证安装:
通过运行以下命令,检查环境是否创建成功:
conda env list
name: surface-protein
channels:
- conda-forge
dependencies:
- python=3.13
- scanpy=1.12
- muon=0.1.7
- python-igraph=1.0.0
- ipykernel=7.2.0
- pip==26.0.1
- pip:
- lamindb==2.3.1
- harmonypy==0.0.9
获取数据和笔记本
本书使用 lamindb,并通过 theislab/sc-best-practices 实例 来存储、共享和加载数据集与笔记本。感谢 Lamin Labs 提供免费托管服务。
安装 lamindb
安装 lamindb Python 软件包:
pip install lamindb
可选择创建 lamin 账户
按照以下 说明 注册并登录。
验证你的设置
运行
lamin connect命令:
import lamindb as ln ln.Artifact.connect("theislab/sc-best-practices").df()
你现在应该看到最多 100 个存储的数据集。
访问数据集(Artifact)
在 Artifacts 页面 搜索该数据集。
加载一个 Artifact 及其对应的对象:
import lamindb as ln af = ln.Artifact.connect("theislab/sc-best-practices").get(key="key_of_dataset", is_latest=True) obj = af.load()
该对象现在已可在内存中访问,并可用于分析。请调整
ln.Artifact.connect("theislab/sc-best-practices").get("SOMEIDXXXX")后缀以获取相应的版本。访问笔记本(Transform)
在 Transforms 页面 搜索该笔记本。
加载笔记本:
lamin load <notebook url>
这会把笔记本下载到当前工作目录。与
Artifacts类似,你可以调整后缀 ID 来获取旧版本。
37.1. 动机#
表面蛋白标记的特征矩阵若以原始表格形式呈现,人很难直接看懂。因此,我们借助低维嵌入,把 ADT 通常可视化到二维空间中。我们对 ADT 数据所采用和推荐的方法,与转录组数据并无不同。前面提到的、通过 t-SNE 和 UMAP 等方法所得可视化的所有局限性,同样适用于 ADT 数据。
ADT 数据一般不需要任何复杂的特征选择,因为这些特征早在实验设计阶段就已先验地(a priori)选定。所有选定的 ADT 都应对应于生物学上相关的特征。不过,大型数据集可能会受益于 PCA,把数据集从几百个特征降到少数几个主成分。如果计算资源有限,这样做尤其值得推荐。
在本章及随后的两章中,我们决定聚焦于 ADT 数据,而不使用该研究的 RNA 数据。在 配对整合 一章中,我们将探索如何联合使用这两种模态,从而能够进行更详细的细胞类型注释。
37.2. 环境设置#
import warnings
import muon as mu
import scanpy as sc
warnings.filterwarnings("ignore")
mu.set_options(pull_on_update=False)
sc.settings.verbosity = 0
sc.set_figure_params(
dpi=80,
facecolor="white",
frameon=False,
)
import lamindb as ln
ln.track()
→ found notebook dimensionality_reduction.ipynb, making new version
→ created Transform('liGMVGre4G5H0004', key='dimensionality_reduction.ipynb'), started new Run('2jUW2z0ijgULitLv') at 2026-04-10 17:28:52 UTC
→ notebook imports: lamindb-core==2.3.1 muon==0.1.7 scanpy==1.12
• recommendation: to identify the notebook across renames, pass the uid: ln.track("liGMVGre4G5H")
37.3. 加载数据#
我们载入上一章 双细胞检测 末尾保存的 MuData 对象:
af = ln.Artifact.connect("theislab/sc-best-practices").get(
key="surface-protein/cite_doublet_detection.h5mu", is_latest=True
)
mdata = af.load()
mdata
MuData object with n_obs × n_vars = 117951 × 36741
var: 'gene_ids', 'feature_types'
2 modalities
rna: 117951 x 36601
obs: 'donor', 'batch'
var: 'gene_ids', 'feature_types'
prot: 117951 x 140
obs: 'donor', 'batch', 'n_genes_by_counts', 'log1p_n_genes_by_counts', 'total_counts', 'log1p_total_counts', 'n_counts', 'outliers', 'doublets_markers'
var: 'gene_ids', 'feature_types', 'n_cells_by_counts', 'mean_counts', 'log1p_mean_counts', 'pct_dropout_by_counts', 'total_counts', 'log1p_total_counts'
uns: 'doublets_markers_colors'
layers: 'counts'我们删除包含原始数据的计数层,因为我们不再需要了。
del mdata["prot"].layers["counts"]
同型对照不包含任何生物学信息,因为它们唯一的用途就是用于 dsb 归一化,参见 归一化 节。因此,我们可以把它们从我们的数据中删除。
mdata["prot"].var.index[:50]
Index(['CD86-1', 'CD274-1', 'CD270', 'CD155', 'CD112', 'CD47-1', 'CD48-1',
'CD40-1', 'CD154', 'CD52-1', 'CD3', 'CD8', 'CD56', 'CD19-1', 'CD33-1',
'CD11c', 'HLA-A-B-C', 'CD45RA', 'CD123', 'CD7-1', 'CD105', 'CD49f',
'CD194', 'CD4-1', 'CD44-1', 'CD14-1', 'CD16', 'CD25', 'CD45RO', 'CD279',
'TIGIT-1', 'Mouse-IgG1', 'Mouse-IgG2a', 'Mouse-IgG2b', 'Rat-IgG2b',
'CD20', 'CD335', 'CD31', 'Podoplanin', 'CD146', 'IgM', 'CD5-1', 'CD195',
'CD32', 'CD196', 'CD185', 'CD103', 'CD69-1', 'CD62L', 'CD161'],
dtype='object')
isotype_controls = ["Mouse-IgG1", "Mouse-IgG2a", "Mouse-IgG2b", "Rat-IgG2b"]
temp = (
mdata["prot"].var.loc[~mdata["prot"].var.index.isin(isotype_controls), :].index
) # Select all proteins except isotype controls.
现在我们实际上从数据中删除了同型对照。
mu.pp.filter_var(data=mdata["prot"], var=temp.tolist())
数据中不再包含同型对照。
mdata["prot"].var.index[:50]
Index(['CD86-1', 'CD274-1', 'CD270', 'CD155', 'CD112', 'CD47-1', 'CD48-1',
'CD40-1', 'CD154', 'CD52-1', 'CD3', 'CD8', 'CD56', 'CD19-1', 'CD33-1',
'CD11c', 'HLA-A-B-C', 'CD45RA', 'CD123', 'CD7-1', 'CD105', 'CD49f',
'CD194', 'CD4-1', 'CD44-1', 'CD14-1', 'CD16', 'CD25', 'CD45RO', 'CD279',
'TIGIT-1', 'CD20', 'CD335', 'CD31', 'Podoplanin', 'CD146', 'IgM',
'CD5-1', 'CD195', 'CD32', 'CD196', 'CD185', 'CD103', 'CD69-1', 'CD62L',
'CD161', 'CD152', 'CD223', 'KLRG1-1', 'CD27-1'],
dtype='object')
mdata["prot"]
AnnData object with n_obs × n_vars = 117951 × 136
obs: 'donor', 'batch', 'n_genes_by_counts', 'log1p_n_genes_by_counts', 'total_counts', 'log1p_total_counts', 'n_counts', 'outliers', 'doublets_markers'
var: 'gene_ids', 'feature_types', 'n_cells_by_counts', 'mean_counts', 'log1p_mean_counts', 'pct_dropout_by_counts', 'total_counts', 'log1p_total_counts'
uns: 'doublets_markers_colors'
37.4. 主成分分析(PCA)和 UMAP#
由于我们的数据集相当大(136 种表面蛋白),现在可以用 PCA 来降低数据的维度。
sc.pp.pca(mdata["prot"], svd_solver="arpack", random_state=0)
我们绘制一张肘部图(elbow plot),以决定使用多少个主成分(PC):
我们使用 20 个 PC,因为第 1–20 个 PC 捕获了数据中的大部分方差,而第 20–50 个 PC 捕获的方差很小,因此可以舍弃。现在,我们计算一个邻域图和一个 UMAP 嵌入,以可视化该研究的各个变量。
sc.pp.neighbors(mdata["prot"], n_pcs=20, random_state=0)
sc.tl.umap(mdata["prot"], random_state=0)
现在,我们已经把数据压缩到二维,可以用它来做可视化。我们先来可视化并评估是否存在批次效应,也就是不同供体、不同批次是否形成各自独立的聚类。
我们确实看到,一些供体形成了独立的聚类,批次也形成了独立的聚类。因此,看来有必要进行批次校正。为确认这一点,我们绘制 CD4 和 CD8 T 细胞的标记:
CD4 T 细胞碎裂成一个个供体特异的小聚类,也就是说,这些细胞是按供体身份、而不是按细胞类型聚在一起的。理想情况下,来自所有供体的 CD4 T 细胞,无论源自哪位供体,都应聚在一起。这种由供体驱动的分离是一种批次效应,必须在下游分析之前加以校正。
af_dimensionality_reduction = ln.Artifact.from_mudata(
mdata,
key="surface-protein/cite_dimensionality_reduction.h5mu",
description="CITE-seq data after dimensionality reduction",
)
af_dimensionality_reduction.save()
ln.finish()
37.5. 参考文献#
37.6. 贡献者#
我们衷心感谢以下人员的贡献:
37.6.2. 审阅者#
Lukas Heumos
Anna Schaar