37. 降维#

   关键要点

用 UMAP 对 ADT 数据做可视化;对于包含大量表面蛋白的大型数据集,PCA 有助于降低维度。

动机
   环境设置
  1. 安装 conda:

    • 在创建环境之前,请确保 conda 已安装在您的系统中。

  2. 保存 yml 内容:

    • 将 yml 选项卡中的内容复制到名为 environment.yml 的文件中。

  3. 创建环境:

    • 打开终端或命令提示符。

    • 运行以下命令:

      conda env create -f environment.yml
      
  4. 激活环境:

    • 创建好环境后,使用以下命令激活它:

      conda activate <environment_name>
      
    • 替换 <environment_name> ,名称就是在 environment.yml 文件中指定的那个。在 yml 文件里,它看起来像这样:

      name: <environment_name>
      
  5. 验证安装:

    • 通过运行以下命令,检查环境是否创建成功:

      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 提供免费托管服务。

  1. 安装 lamindb

    • 安装 lamindb Python 软件包:

    pip install lamindb
    
  2. 可选择创建 lamin 账户

    • 按照以下 说明 注册并登录。

  3. 验证你的设置

    • 运行 lamin connect 命令:

    import lamindb as ln
    
    ln.Artifact.connect("theislab/sc-best-practices").df()
    

    你现在应该看到最多 100 个存储的数据集。

  4. 访问数据集(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") 后缀以获取相应的版本。

  5. 访问笔记本(Transform)

    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):

sc.pl.pca_variance_ratio(mdata["prot"], n_pcs=50)

我们使用 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)

现在,我们已经把数据压缩到二维,可以用它来做可视化。我们先来可视化并评估是否存在批次效应,也就是不同供体、不同批次是否形成各自独立的聚类。

sc.pl.umap(mdata["prot"], color=["donor", "batch"])

我们确实看到,一些供体形成了独立的聚类,批次也形成了独立的聚类。因此,看来有必要进行批次校正。为确认这一点,我们绘制 CD4 和 CD8 T 细胞的标记:

sc.pl.umap(mdata["prot"], color=["CD4-1", "CD8", "CD3"])

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()

隐藏代码单元输出

→ returning artifact with same hash: Artifact(uid='9DWigMKiH7zGL1jy0001', key='surface-protein/cite_dimensionality_reduction.h5mu', description='CITE-seq data after dimensionality reduction', suffix='.h5mu', kind='dataset', otype='MuData', size=1498728248, hash='OGdSkrdRzOgP_SJoVwIgpT', n_files=None, n_observations=117951, branch_id=1, created_on_id=1, space_id=1, storage_id=1, run_id=70, schema_id=None, created_by_id=7, created_at=2026-04-10 17:04:28 UTC, is_locked=False, version_tag=None, is_latest=True); to track this artifact as an input, use: ln.Artifact.get()
Artifact(uid='9DWigMKiH7zGL1jy0001', key='surface-protein/cite_dimensionality_reduction.h5mu', description='CITE-seq data after dimensionality reduction', suffix='.h5mu', kind='dataset', otype='MuData', size=1498728248, hash='OGdSkrdRzOgP_SJoVwIgpT', n_files=None, n_observations=117951, branch_id=1, created_on_id=1, space_id=1, storage_id=1, run_id=70, schema_id=None, created_by_id=7, created_at=2026-04-10 17:04:28 UTC, is_locked=False, version_tag=None, is_latest=True)
ln.finish()

隐藏代码单元输出

• please hit CTRL + s to save the notebook in your editor .... still waiting .....
.............. ✓
! cells [(0, 3)] were not run consecutively
→ finished Run('2jUW2z0ijgULitLv') after 1m at 2026-04-10 17:30:42 UTC
→ go to: https://lamin.ai/theislab/sc-best-practices/transform/liGMVGre4G5H0004
→ to update your notebook from the CLI, run: lamin save /groups/nils/members/javier/single-cell-best-practices/jupyter-book/surface_protein/dimensionality_reduction.ipynb

37.5. 参考文献#

37.6. 贡献者#

我们衷心感谢以下人员的贡献:

37.6.1. 作者#

  • Javier Marchena-Hurtado

  • Daniel Strobl

  • Ciro Ramírez-Suástegui

37.6.2. 审阅者#

  • Lukas Heumos

  • Anna Schaar