mcpField
C
cell-type-annotation

cell-type-annotation

github.com/awslabs数据与数据库6877 次安装4 周前更新
代码仓库

关于 cell-type-annotation

用于单细胞 RNA-seq 细胞类型注释的流程技能,面向使用聚类后 AnnData 或 SingleCellExperiment 数据的用户。它指导自动、参考数据、标记基因及分层注释,并包含置信度检查和验证步骤。

主要功能

  1. 01指导使用 CellTypist 自动注释
  2. 02从参考数据转移标签
  3. 03依据标记基因分配类型
  4. 04分层细化注释标签
  5. 05检查置信度并验证标签

适用场景

  1. 01注释聚类后的单细胞 RNA-seq 数据
  2. 02从参考图谱转移细胞标签
  3. 03复核不确定的细胞类型分配
  4. 04将宽泛标签细化为亚型

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/awslabs/hcls-agent-skills --skill cell-type-annotation

安装后在 Claude Code 中输入/cell-type-annotation确认已加载。

详细介绍

细胞类型注释

概述

此流水线技能可生成用于注释单细胞 RNA-seq 数据中细胞类型的代码。它涵盖四种互补方法:

  1. 自动化 — CellTypist(基于整理后的图谱训练的逻辑回归分类器)。
  2. 基于参考数据 — SingleR(R)或 scANVI/sc.tl.ingest(Python)标签转移。
  3. 基于标记基因 — 根据经典标记基因面板手动分配。
  4. 分层式 — 先分配粗略细胞区室,再进行专门的精细注释。

当用户拥有聚类后的 AnnData(或 SingleCellExperiment),并需要在 adata.obs 中添加细胞类型标签时,可使用此技能。

用法

决策树:选择注释方法

按照此决策树选择合适的方法:

  1. 是否有适用于你的组织和物种的 CellTypist 模型?
    • 是 → 使用 CellTypist(以下步骤 1–6)
    • 否 → 转到步骤 2
  2. 是否有来自相同组织、带标签的参考 AnnData?
    • 是,批次/技术相同 → 使用 sc.tl.ingest(步骤 12)
    • 是,批次不同 → 使用 scANVI 标签转移(步骤 13)
    • 否 → 转到步骤 3
  3. 你是否在 R 中使用 bulk 或分选细胞参考数据?
    • 是 → 使用 SingleR(步骤 7–9)
    • 否 → 转到步骤 4
  4. 是否有预期细胞类型的经典标记基因面板?
    • 是 → 使用基于标记基因的注释(步骤 10–11)
    • 否 → 从 CellTypist 最宽泛的模型(Immune_All_Low.pkl 或 Developing_Human_Brain.pkl)开始,然后使用标记基因进行细化
注释工作流(15 个步骤)

步骤 1 — 确认归一化。 CellTypist 要求使用 log1p(CP10k)。检查是否存在 adata.uns['log1p'],否则运行归一化。如果数据位于 adata.raw 或某个图层中,请进行相应的子集处理。

步骤 2 — 验证基因符号。 确认 adata.var_names 是 HGNC(人类)或 MGI(小鼠)符号,而不是 Ensembl ID。如有需要,使用 sc.queries.biomart_annotations 进行转换。

步骤 3 — 选择 CellTypist 模型。 选择与物种和组织相匹配的模型。使用 celltypist.models.models_description() 列出可用选项。如果不确定,可从适用于该细胞区室的最广泛模型开始。

步骤 4 — 运行 CellTypist 注释。 使用 celltypist.annotate(),设置 majority_voting=True,并选择合适的 p_thres(默认值为 0.5;若要进行严格判定,可提高到 0.7)。

步骤 5 — 通过 to_adata() 提取结果。 调用 predictions.to_adata(),获取 .obs 中的注释。通过 adata_result.obs['conf_score'] 获取置信度。

步骤 6 — 筛除低置信度细胞。 将 conf_score < 0.5 的细胞(或低于用户指定阈值的细胞)标记为 'Unknown'。

步骤 7 — (SingleR)安装参考数据集。 使用 BiocManager::install("celldex") 并加载合适的参考数据集。

步骤 8 — (SingleR)运行预测。 使用 assay.type.test = "logcounts" 调用 SingleR(test, ref, labels)。

步骤 9 — (SingleR)剔除低质量判定结果。 使用 pruneScores(pred) 找出不可靠的分类,并将其设为 "Unknown"。

步骤 10 — (基于标记基因)定义面板。 根据文献为每种细胞类型提供至少 3 个标记基因。在有参考价值时,也纳入阴性标记。

步骤 11 — (基于标记基因)评分并分配类型。 使用 sc.pl.dotplot 进行可视化,然后将聚类映射到细胞类型。对于有歧义的聚类,标记为 'Unknown'。

步骤 12 — (Ingest)将查询数据投射到参考数据集。 需要共享 PCA 空间;运行 sc.tl.ingest(adata_query, adata_ref, obs='cell_type')。只有当查询数据和参考数据使用相同技术且批次效应极小时,效果才较好。

步骤 13 — (scANVI)半监督迁移。 在参考数据集上训练 SCVI,使用标签扩展为 SCANVI,然后对查询数据运行 load_query_data。可原生处理批次效应。

步骤 14 — 验证注释。 按已分配的细胞类型对经典标记基因绘制 dotplot,以确认注释结果。检查各样本的比例是否符合生物学预期。

步骤 15 — 分层细化。 如果细分类标签不稳定,先注释较粗略的细胞区室(通过 PTPRC/EPCAM/COL1A1 区分免疫/基质/上皮细胞),再进行子集处理,然后使用专用模型或标记基因分别重新注释。

分支判断
  • 在步骤 4:如果 >30% 的细胞 conf_score < 0.5,说明模型不适用 → 改用基于标记基因的方法或尝试其他模型。
  • 在步骤 6:如果某个标签意外地占据 >80% 的细胞,应怀疑模型不匹配或数据未归一化。
  • 在步骤 12:如果 ingest 后查询数据的 UMAP 与参考数据集无法对齐,说明批次效应过强 → 改用 scANVI(步骤 13)。
  • 在步骤 14:如果细胞比例不符合生物学预期(例如,PBMC 中成纤维细胞占 60%),请重新检查归一化和模型选择。

响应格式

  • 首先给出用户需要的命令或代码,然后再解释。
  • 结构按以下顺序组织:确认输入 → 可运行代码 → 关键参数说明 → 注意事项。
  • 每项任务提供一个完整且可运行的示例;不要展示所有替代方案。
  • 代码注释应精简且实用。
  • 目标:50–100 行代码,并附简短说明。
  • 始终包含置信度提取和筛选步骤。

核心概念

1. CellTypist(自动化,Python)
import scanpy as sc
import celltypist
from celltypist import models

# Input: log1p-normalized to 10,000 counts/cell
sc.pp.normalize_total(adata, target_sum=1e4)
sc.pp.log1p(adata)

# Download models (first run only)
models.download_models()
print(models.models_description())  # list available models

# Load tissue-matched model
model = models.Model.load(model='Immune_All_Low.pkl')

# Annotate with majority voting
predictions = celltypist.annotate(
    adata,
    model=model,
    majority_voting=True,       # smooth labels over neighborhood graph
    over_clustering='leiden',   # obs key for majority voting resolution
    p_thres=0.5,               # minimum probability threshold (raise for stringency)
)

# Extract results — modern API (CellTypist >=1.3)
adata_result = predictions.to_adata()
# Annotations now in adata_result.obs:
#   'predicted_labels'        — per-cell raw predictions
#   'majority_voting'         — smoothed labels
#   'conf_score'              — max probability per cell

# Transfer to original adata
adata.obs['cell_type'] = adata_result.obs['majority_voting']
adata.obs['cell_type_conf'] = adata_result.obs['conf_score']

# Filter low-confidence assignments
adata.obs.loc[adata.obs['cell_type_conf'] < 0.5, 'cell_type'] = 'Unknown'

celltypist.annotate() 的关键参数:

参数默认值效果
majority_votingFalse在 kNN 图上平滑标签;始终启用
over_clusteringNone用于投票分辨率的 obs 键(例如 'leiden');聚类越精细,分辨率越高
p_thres0.5分配标签所需的最低概率;若只保留高置信度结果,则提高到 0.7
mode'best match'在多标签场景中使用 'prob match'

常用模型:Immune_All_Low、Immune_All_High、Healthy_COVID19_PBMC、Human_Lung_Atlas、Cells_Intestinal_Tract、Developing_Human_Brain、Adult_Mouse_Gut。请匹配物种和组织。

2. SingleR(基于参考数据,R)
if (!requireNamespace("BiocManager", quietly = TRUE))
    install.packages("BiocManager")
BiocManager::install(c("SingleR", "celldex", "SingleCellExperiment"))

library(SingleR)
library(celldex)
library(SingleCellExperiment)

# Choose reference matching species/tissue
ref <- celldex::HumanPrimaryCellAtlasData()
# ref <- celldex::MonacoImmuneData()       # sorted human immune
# ref <- celldex::ImmGenData()             # mouse immune
# ref <- celldex::BlueprintEncodeData()    # human stromal + immune

pred <- SingleR(
    test = sce,
    ref = ref,
    labels = ref$label.main,
    assay.type.test = "logcounts"
)

sce$cell_type <- pred$labels
table(pred$labels)

# Prune low-confidence calls (delta < median - 3*MAD)
sce$cell_type[is.na(pred$pruned.labels)] <- "Unknown"
3. 基于标记基因(手动,Python)
import scanpy as sc

marker_genes = {
    'T cells':      ['CD3D', 'CD3E', 'CD2'],
    'CD4 T':        ['CD4', 'IL7R'],
    'CD8 T':        ['CD8A', 'CD8B'],
    'B cells':      ['CD79A', 'MS4A1', 'CD19'],
    'NK cells':     ['NKG7', 'GNLY', 'KLRD1'],
    'Monocytes':    ['CD14', 'LYZ', 'S100A8'],
    'Dendritic':    ['FCER1A', 'CST3', 'CLEC10A'],
    'Fibroblasts':  ['COL1A1', 'DCN', 'COL3A1'],
    'Endothelial':  ['PECAM1', 'VWF', 'CDH5'],
    'Epithelial':   ['EPCAM', 'KRT18', 'KRT19'],
}

sc.pl.dotplot(adata, marker_genes, groupby='leiden', standard_scale='var')

# Assign after reviewing the dotplot
cluster_to_celltype = {
    '0': 'T cells', '1': 'Monocytes', '2': 'B cells',
    '3': 'NK cells', '4': 'Unknown',
}
adata.obs['cell_type'] = adata.obs['leiden'].map(cluster_to_celltype).astype('category')
4. 从参考图谱进行标签迁移
# Quick path: sc.tl.ingest (PCA/UMAP projection, kNN labels)
# Only use when batch effects are minimal
import scanpy as sc
sc.pp.pca(adata_ref)
sc.pp.neighbors(adata_ref)
sc.tl.umap(adata_ref)
sc.tl.ingest(adata_query, adata_ref, obs='cell_type')

# Robust path: scANVI (semi-supervised, handles batch)
import scvi
scvi.model.SCVI.setup_anndata(adata_ref, batch_key='batch')
scvi_model = scvi.model.SCVI(adata_ref)
scvi_model.train()

scvi.model.SCANVI.setup_anndata(
    adata_ref, labels_key='cell_type', unlabeled_category='Unknown', batch_key='batch'
)
scanvi_model = scvi.model.SCANVI.from_scvi_model(scvi_model, unlabeled_category='Unknown')
scanvi_model.train(max_epochs=20)

scanvi_model = scvi.model.SCANVI.load_query_data(adata_query, scanvi_model)
scanvi_model.train(max_epochs=100, plan_kwargs={'weight_decay': 0.0})
adata_query.obs['cell_type_pred'] = scanvi_model.predict(adata_query)
5. 验证
# Confirm assigned labels express their markers
sc.pl.dotplot(adata, marker_genes, groupby='cell_type', standard_scale='var')
sc.pl.violin(adata, ['CD3D', 'MS4A1', 'CD14'], groupby='cell_type', rotation=90)

# Sanity-check proportions per sample
adata.obs.groupby(['sample', 'cell_type']).size().unstack(fill_value=0)

对于没有明确标记基因支持的簇,请标记为 'Unknown',而不要强行赋予标签。

6. 分层注释
# Step 1: coarse compartments
compartment_markers = {
    'Immune':     ['PTPRC'],           # CD45
    'Epithelial': ['EPCAM', 'KRT8'],
    'Stromal':    ['COL1A1', 'PECAM1'],
}
# Step 2: subset and re-annotate each compartment
adata_immune = adata[adata.obs['compartment'] == 'Immune'].copy()
model = models.Model.load('Immune_All_Low.pkl')
preds = celltypist.annotate(adata_immune, model=model, majority_voting=True)
adata_immune_result = preds.to_adata()
adata_immune.obs['cell_type_fine'] = adata_immune_result.obs['majority_voting']

快速参考

任务工具关键调用
PBMC / 免疫细胞自动注释CellTypistmodels.Model.load('Immune_All_Low.pkl')
肺图谱映射CellTypist'Human_Lung_Atlas.pkl'
肠道 / 肠道组织CellTypist'Cells_Intestinal_Tract.pkl'
广泛的人类参考数据(R)SingleRcelldex::HumanPrimaryCellAtlasData()
分选的免疫细胞参考数据(R)SingleRcelldex::MonacoImmuneData()
小鼠免疫细胞(R)SingleRcelldex::ImmGenData()
查询数据→参考数据迁移scanpysc.tl.ingest(adata_q, adata_ref, obs='cell_type')
感知批次的迁移scvi-toolsSCANVI.load_query_data(...)
标记基因检查scanpysc.pl.dotplot(adata, markers, groupby='leiden')
置信度(CellTypist)CellTypistpredictions.to_adata().obs['conf_score']
置信度(SingleR)SingleRis.na(pred$pruned.labels) 标记低质量结果

所需输入:

  • CellTypist:adata.X = 经 log1p(CP10k) 标准化,基因以 HGNC 符号作为 adata.var_names。
  • SingleR:带有 logcounts assay 的 SingleCellExperiment。
  • scANVI:adata.layers['counts'] 中的原始计数,以及参考数据中的 batch_key、labels_key。
数值阈值
指标阈值操作
CellTypist conf_score< 0.5标记为 'Unknown'
CellTypist conf_score< 0.7标记以供人工审核
CellTypist p_thres0.5(默认值)提高到 0.7 以进行严格注释
SingleR delta score< 中位数 - 3×MAD剪枝(设为 NA)
簇大小< 20 个细胞不分配稀有亚型;使用父级标签
标记基因点图比例< 0.3标记基因表达不可靠;不用于赋值
预期比例偏差> 文献范围的 3×怀疑模型错误或标准化错误

常见错误

  1. 错误: 将原始计数值输入 CellTypist 正确做法: 注释前务必运行 sc.pp.normalize_total(adata, target_sum=1e4) + sc.pp.log1p(adata) 原因: CellTypist 需要经过归一化处理、每个细胞总计数为 10,000 的计数值的 log1p;原始数据或经过 SCTransform 处理的数据会产生毫无意义的标签

  2. 错误: 使用与组织或物种不匹配的参考模型 正确做法: 选择 CellTypist 模型或 SingleR 参考数据时,确保物种(Human_* 与 Mouse_*)和组织类型匹配 原因: 对上皮肿瘤细胞使用 Immune_All_Low,或对小鼠数据使用 HumanPrimaryCellAtlasData,都会产生看似可信、实际错误的标签

  3. 错误: 将 Ensembl ID 或大小写混杂的基因符号传给 CellTypist/SingleR 正确做法: 注释前将 adata.var_names 转换为 HGNC(人类)或 MGI(小鼠)符号 原因: Ensembl ID 或大小写错误(Cd3d 与 CD3D)会导致特征被静默丢弃,在没有警告的情况下降低模型性能

  4. 错误: 使用 predictions.probability_matrix.max(axis=1) 获取置信度分数 正确做法: 使用 predictions.to_adata().obs['conf_score'],这是自 CellTypist ≥1.3 起稳定的 API 原因: 概率矩阵的做法很脆弱,并且依赖版本;更新后可能会失效或返回错误值

  5. 错误: 为少于 20 个细胞的簇指定罕见亚型标签 正确做法: 当簇大小少于 20 个细胞时,归并到父细胞类型,或标记为 'Unknown' 原因: 将小簇指定为罕见亚型时,统计效力不足;若缺少强区分标记,这类结果并不可靠

  6. 错误: 查看点图后,仍强行为缺少明确标记的簇指定标签 正确做法: 将有歧义的簇保留为 'Unknown',而不是选择次优猜测 原因: 强行指定标签会将错误传递到下游分析(差异表达、轨迹分析)中,并形成错误的生物学解释

  7. 错误: 运行 CellTypist 时设置 majority_voting=False,并直接使用单细胞标签 正确做法: 务必启用 majority_voting=True,通过局部邻域图平滑标签 原因: 单细胞预测噪声较大;多数投票利用簇结构生成一致、稳定的注释

  8. 错误: 未进行批次校正就运行 sc.tl.ingest 进行标签转移 正确做法: 先整合查询数据与参考数据,或使用 scANVI 的 load_query_data 路径,该路径可原生处理批次 原因: ingest 假定查询数据与参考数据具有相同的嵌入;批次效应会导致错位和错误的标签转移

  9. 错误: 不根据生物学预期验证细胞类型比例 正确做法: 务必将各样本的细胞类型比例与已知组织组成进行交叉核对 原因: 如果 PBMC 样本中有 80% 是成纤维细胞,就是一个危险信号,表明模型错误、归一化有误或数据质量存在问题

  10. 错误: 只在一个分辨率下进行注释,不进行分层细化 正确做法: 先注释粗略的区室(免疫/基质/上皮),再使用专用模型或标记细化各区室 原因: 对区分不佳的簇进行细粒度标注并不稳定;分层注释能产生更可靠的结果

参考文献

评论

支持 Markdown