36. 双细胞检测#

   关键要点

对于 ADT 数据中的异型双细胞(heterotypic doublet),可以利用互斥的细胞类型标记(如 CD3、CD19、CD14)来识别并去除:同时表达两种标记的细胞,很可能就是双细胞。

动机
   环境设置
  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 来获取旧版本。

36.1. 动机#

质量控制 一章中,我们仅根据细胞过高的计数去除了可能是双细胞的细胞,还基于按样本的分布对细胞做了过滤。现在,我们将聚焦于异型双细胞,也就是包含不同细胞类型的双细胞。借助 ADT 数据,我们可以用细胞类型特异的表面标记来检测它们 [Sun et al., 2021]

36.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()
→ loaded Transform('xo1WtNUmrJCK0003', key='doublet_detection.ipynb'), re-started Run('hDXP6BIj1dnyLVwy') at 2026-04-10 17:27:34 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("xo1WtNUmrJCK")

36.3. 加载数据#

我们载入上一章 归一化 末尾保存的 MuData 对象:

af = ln.Artifact.connect("theislab/sc-best-practices").get(
    key="surface-protein/cite_normalization.h5mu", is_latest=True
)
mdata = af.load()
mdata
MuData object with n_obs × n_vars = 118563 × 36741
  var:	'gene_ids', 'feature_types'
  2 modalities
    rna:	118563 x 36601
      obs:	'donor', 'batch'
      var:	'gene_ids', 'feature_types'
    prot:	118563 x 140
      obs:	'donor', 'batch', 'n_genes_by_counts', 'log1p_n_genes_by_counts', 'total_counts', 'log1p_total_counts', 'n_counts', 'outliers'
      var:	'gene_ids', 'feature_types', 'n_cells_by_counts', 'mean_counts', 'log1p_mean_counts', 'pct_dropout_by_counts', 'total_counts', 'log1p_total_counts'
      layers:	'counts'

36.4. 用细胞类型标记检测到的双细胞#

现在我们来看那些互斥的细胞类型标记。例如 CD3(T 细胞标记)与 CD19(B 细胞标记),可用于识别 T/B 细胞双细胞。由于在生理条件下并不存在同时表达 B 细胞和 T 细胞特异标记的细胞,因此这些液滴包含的是 T/B 细胞双细胞。

对于同时表达 T 细胞(CD3)和单核细胞(CD14)标记的细胞,情况也是如此。

sc.pl.scatter(mdata["prot"], x="CD3", y="CD19-1", color="log1p_total_counts")

在这张图中,左下方可以看到大量既不表达 T 细胞、也不表达 B 细胞标记的细胞;左上和右下是只表达其中一种标记的细胞;右上则是一些同时表达两种标记的细胞。

表达两个标记的细胞都是双细胞,可以移除。

我们还可以利用 CD3 和 CD14 来检测 T 细胞/单核细胞双细胞。

sc.pl.scatter(mdata["prot"], x="CD3", y="CD14-1", color="log1p_total_counts")

看起来,在两种标记上表达水平都高于 2.5 的细胞就是双细胞。我们以“在两种标记上表达水平均高于 2.5”作为标记双细胞的标准。

genes2filter = ["CD3", "CD19-1", "CD14-1"]
temp = mdata["prot"][:, genes2filter].X.T.tolist()
mdata["prot"].obs["doublets_markers"] = [
    (temp[0][i] > 2.5 and temp[1][i] > 2.5) or (temp[0][i] > 2.5 and temp[2][i] > 2.5)
    for i in range(mdata.shape[0])
]
mdata["prot"].obs["doublets_markers"] = (
    mdata["prot"].obs["doublets_markers"].astype(str)
)

双细胞通常计数更高,因为它来自不止一个细胞、计数相应增加。在用我们的标记被分类为双细胞的那些细胞中,可以看到这种效应:

sc.pl.violin(mdata["prot"], keys="log1p_total_counts", groupby="doublets_markers")

我们剔除了同时表达两种标记的细胞。

mdata = mdata[mdata["prot"].obs["doublets_markers"] == "False"].copy()
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'

我们从数据中删除了 612 个双细胞。

在本章中,我们利用 ADT 数据,通过去除高表达两种互斥标记的细胞来去除双细胞。另一种去除双细胞的方法,是使用基于 scRNA-seq 数据来检测双细胞的方法。关于那些方法,请参阅 双细胞检测(位于 scRNA-seq 预处理与可视化一章)。

af_doublet_detection = ln.Artifact.from_mudata(
    mdata,
    key="surface-protein/cite_doublet_detection.h5mu",
    description="CITE-seq data after doublet detection",
)
af_doublet_detection.save()

隐藏代码单元输出

→ returning artifact with same hash: Artifact(uid='I1sQCEySclEA4f2N0001', key='surface-protein/cite_doublet_detection.h5mu', description='CITE-seq data after doublet detection', suffix='.h5mu', kind='dataset', otype='MuData', size=1551251184, hash='HbBznISXUygGg0yATntRWk', n_files=None, n_observations=117951, branch_id=1, created_on_id=1, space_id=1, storage_id=1, run_id=69, schema_id=None, created_by_id=7, created_at=2026-04-10 17:01:29 UTC, is_locked=False, version_tag=None, is_latest=True); to track this artifact as an input, use: ln.Artifact.get()
Artifact(uid='I1sQCEySclEA4f2N0001', key='surface-protein/cite_doublet_detection.h5mu', description='CITE-seq data after doublet detection', suffix='.h5mu', kind='dataset', otype='MuData', size=1551251184, hash='HbBznISXUygGg0yATntRWk', n_files=None, n_observations=117951, branch_id=1, created_on_id=1, space_id=1, storage_id=1, run_id=69, schema_id=None, created_by_id=7, created_at=2026-04-10 17:01:29 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('hDXP6BIj1dnyLVwy') after 34s at 2026-04-10 17:28:09 UTC
→ go to: https://lamin.ai/theislab/sc-best-practices/transform/xo1WtNUmrJCK0003
→ to update your notebook from the CLI, run: lamin save /groups/nils/members/javier/single-cell-best-practices/jupyter-book/surface_protein/doublet_detection.ipynb

36.5. 参考文献#

[SBO+21]

Bo Sun, Emmanuel Bugarin-Estrada, Lauren Elizabeth Overend, Catherine Elizabeth Walker, Felicia Anna Tucci, and Rachael Jennifer Mary Bashford-Rogers. Double-jeopardy: scrna-seq doublet/multiplet detection using multi-omic profiling. Cell Reports Methods, 1(1):100008, May 2021. doi:10.1016/j.crmeth.2021.100008.

36.6. 贡献者#

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

36.6.1. 作者#

  • Javier Marchena-Hurtado

  • Daniel Strobl

  • Ciro Ramírez-Suástegui

36.6.2. 审阅者#

  • Lukas Heumos

  • Anna Schaar