cell-type-annotation について
クラスタリング済みの AnnData または SingleCellExperiment を扱うユーザー向けの、シングルセル RNA-seq 細胞型アノテーションのパイプラインスキルです。自動、参照ベース、マーカー遺伝子、階層的な手法を案内し、信頼度の確認と検証も扱います。
主な機能
- 01CellTypistによる自動アノテーションの案内
- 02参照データからのラベル転送
- 03マーカー遺伝子による細胞型判定
- 04階層的なラベルの細分化
- 05信頼度の確認とラベルの検証
活用シーン
- 01クラスタリング済みシングルセルRNA-seqデータの注釈
- 02参照アトラスからの細胞ラベル転送
- 03不確かな細胞型判定の確認
- 04大分類ラベルからサブタイプへの細分化
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ awslabs/ hcls-agent-skills --skill cell-type-annotationインストール後、Claude Code で/cell-type-annotationを入力して読み込まれたか確認します。
詳細
細胞型アノテーション
概要
このパイプラインスキルは、シングルセル RNA-seq データの細胞型をアノテーションするコードを生成します。以下の4つの相補的なアプローチを扱います。
- 自動 — CellTypist(キュレーション済みアトラスで学習したロジスティック回帰分類器)。
- 参照ベース — SingleR(R)または scANVI/
sc.tl.ingest(Python)によるラベル転送。 - マーカーベース — 標準的なマーカー遺伝子パネルに基づく手動での割り当て。
- 階層型 — 大まかなコンパートメントの割り当て後に、専門的で詳細なアノテーションを実施。
クラスタリング済みの AnnData(または SingleCellExperiment)があり、adata.obs に細胞型ラベルを追加する必要がある場合に使用します。
使用方法
決定木:アノテーション手法の選択
この決定木に従って、適切な手法を選択します。
- 組織と種に一致する CellTypist モデルがありますか?
- はい → CellTypist を使用します(以下の手順 1~6)
- いいえ → 手順 2 に進みます
- 同じ組織のラベル付き参照 AnnData がありますか?
- はい、同じバッチ/テクノロジーです →
sc.tl.ingestを使用します(手順 12) - はい、バッチが異なります → scANVI によるラベル転送を使用します(手順 13)
- いいえ → 手順 3 に進みます
- はい、同じバッチ/テクノロジーです →
- R でバルクまたはソート済み細胞の参照データを使っていますか?
- はい → SingleR を使用します(手順 7~9)
- いいえ → 手順 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 が Ensembl ID ではなく、HGNC(ヒト)または MGI(マウス)のシンボルであることを確認してください。必要に応じて、sc.queries.biomart_annotations で変換してください。
ステップ 3 — CellTypist モデルを選択します。 種と組織に合ったものを選んでください。celltypist.models.models_description() を使用して選択肢を一覧表示します。判断に迷う場合は、該当するコンパートメントに対して最も幅広く対応するモデルから始めてください。
ステップ 4 — CellTypist によるアノテーションを実行します。 majority_voting=True と適切な p_thres(デフォルトは 0.5、厳密な判定には 0.7 に引き上げます)を指定して、celltypist.annotate() を使用してください。
ステップ 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 — アノテーションを検証します。 割り当てた細胞型ごとにグループ化した、標準的なマーカーのドットプロットで確認してください。サンプルごとの割合が生物学的に妥当かどうかも確認します。
ステップ 15 — 階層的に詳細化します。 詳細なラベルが安定しない場合は、まず粗いコンパートメント(PTPRC/EPCAM/COL1A1 による免疫/間質/上皮)をアノテーションし、サブセット化してから、各コンパートメントを専用モデルまたはマーカーで再アノテーションしてください。
分岐点
- ステップ 4:細胞の
>30%でconf_score < 0.5となる場合、モデルが適合していません → マーカーに基づく方法に切り替えるか、別のモデルを試してください。 - ステップ 6:単一のラベルが予期せず細胞の
>80%を占める場合、モデルが誤っているか、データが未正規化である可能性を疑ってください。 - ステップ 12:Ingest 後にクエリの UMAP が参照データと整合しない場合、バッチ効果が強すぎます → scANVI(ステップ 13)に切り替えてください。
- ステップ 14:割合が生物学的に妥当でない場合(例:PBMC の 60% が線維芽細胞)、正規化とモデルの選択を再確認してください。
回答形式
- 必要なコマンドまたはコードを最初に示し、その後に説明してください。
- 次の構成にしてください:入力の確認 → 動作するコード → 重要なパラメーターの説明 → 注意点。
- 各タスクにつき、完全に動作する例を 1 つ示してください。すべての代替案を並べないでください。
- コードコメントは最小限にし、実用的な内容にしてください。
- 目安:コード 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_voting | False | kNN グラフ上でラベルを平滑化します。常に有効にしてください |
over_clustering | None | 投票の解像度に使う obs キー(例:'leiden')です。クラスターを細分化すると、解像度が向上します |
p_thres | 0.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/免疫の自動アノテーション | CellTypist | models.Model.load('Immune_All_Low.pkl') |
| 肺アトラスへのマッピング | CellTypist | 'Human_Lung_Atlas.pkl' |
| 腸/腸管 | CellTypist | 'Cells_Intestinal_Tract.pkl' |
| 広範なヒト参照データ(R) | SingleR | celldex::HumanPrimaryCellAtlasData() |
| ソート済み免疫参照データ(R) | SingleR | celldex::MonacoImmuneData() |
| マウス免疫(R) | SingleR | celldex::ImmGenData() |
| クエリから参照データへの転送 | scanpy | sc.tl.ingest(adata_q, adata_ref, obs='cell_type') |
| バッチを考慮した転送 | scvi-tools | SCANVI.load_query_data(...) |
| マーカーの確認 | scanpy | sc.pl.dotplot(adata, markers, groupby='leiden') |
| 信頼度(CellTypist) | CellTypist | predictions.to_adata().obs['conf_score'] |
| 信頼度(SingleR) | SingleR | is.na(pred$pruned.labels) は品質の低い結果を示します |
必須入力:
- CellTypist:
adata.Xは log1p(CP10k) で正規化し、adata.var_namesの遺伝子名には HGNC シンボルを使います。 - SingleR:
logcountsアッセイを含むSingleCellExperiment。 - scANVI:
adata.layers['counts']の生カウント、参照データのbatch_keyとlabels_key。
数値しきい値
| 指標 | しきい値 | 対応 |
|---|---|---|
CellTypist conf_score | < 0.5 | 'Unknown' とラベル付けします |
CellTypist conf_score | < 0.7 | 手動確認が必要なものとしてフラグを付けます |
CellTypist p_thres | 0.5(デフォルト) | 厳密なアノテーションには 0.7 に上げます |
| SingleR delta score | < median - 3×MAD | プルーニングされます(NA に設定) |
| クラスターサイズ | < 20 細胞 | 希少なサブタイプは割り当てず、親ラベルを使います |
| マーカードットプロットの割合 | < 0.3 | マーカーの発現は信頼できません。割り当てに使わないでください |
| 予測割合の逸脱 | > 文献上の範囲の 3× | モデルまたは正規化に誤りがある可能性があります |
よくある間違い
-
誤り: 生のカウント値をCellTypistに入力する 正しい方法: アノテーションの前に、必ず
sc.pp.normalize_total(adata, target_sum=1e4)+sc.pp.log1p(adata)を実行します 理由: CellTypistは、1細胞あたり10,000に正規化したカウント値のlog1pを想定しています。生データやSCTransform済みデータを使うと、意味のないラベルが生成されます -
誤り: 組織や種に合わない参照モデルを使用する 正しい方法: CellTypistモデルまたはSingleR参照データを選ぶ際は、種(
Human_*とMouse_*)と組織の種類を一致させます 理由: 上皮性腫瘍細胞にImmune_All_Lowを使用したり、マウスデータにHumanPrimaryCellAtlasDataを使用したりすると、確信度は高いものの誤ったラベルが生成されます -
誤り: Ensembl IDまたは大文字・小文字が混在した遺伝子シンボルをCellTypist/SingleRに渡す 正しい方法: アノテーションの前に、
adata.var_namesをHGNC(ヒト)またはMGI(マウス)のシンボルに変換します 理由: Ensembl IDや誤った大文字・小文字表記(Cd3dとCD3Dなど)では、特徴量が警告なしに除外され、モデルの性能が低下します -
誤り: 信頼度スコアの取得に
predictions.probability_matrix.max(axis=1)を使う 正しい方法: CellTypist ≥1.3で安定したAPIとして提供されているpredictions.to_adata().obs['conf_score']を使います 理由: 確率行列を使う方法は脆弱で、バージョンに依存します。アップデートによって動作しなくなったり、誤った値を返したりする可能性があります -
誤り: 20細胞未満のクラスターに希少なサブタイプのラベルを付ける 正しい方法: クラスターのサイズが20細胞未満の場合は、親細胞型にまとめるか、
'Unknown'とします 理由: ごく小さなクラスターへの希少なサブタイプの割り当ては、統計的検出力が不足しており、明確な識別マーカーがない限り信頼できません -
誤り: ドットプロットを確認して明確なマーカーがないクラスターに、無理にラベルを付ける 正しい方法: 次善の推測を選ぶのではなく、曖昧なクラスターは
'Unknown'のままにします 理由: 無理に付けたラベルは下流の解析(DE、軌跡解析)に誤りを伝播させ、誤った生物学的解釈につながります -
誤り:
majority_voting=FalseでCellTypistを実行し、細胞ごとのラベルをそのまま使う 正しい方法: 近傍グラフ上でラベルを平滑化するため、必ずmajority_voting=Trueを有効にします 理由: 細胞ごとの予測にはノイズが含まれます。多数決はクラスター構造を活用し、一貫性があり安定したアノテーションを生成します -
誤り: バッチ補正なしでラベル転送に
sc.tl.ingestを実行する 正しい方法: まずクエリと参照データを統合するか、バッチをネイティブに処理するscANVIのload_query_dataパスを使います 理由:ingestはクエリと参照データが同じ埋め込み空間を共有していると仮定します。バッチ効果があると位置合わせが崩れ、誤ったラベルが転送されます -
誤り: 細胞型の割合を生物学的な想定と照らし合わせて検証しない 正しい方法: サンプルごとの細胞型の割合を、既知の組織構成と必ず照合します 理由: PBMCサンプルの線維芽細胞が80%を占める場合、モデルの選択ミス、正規化エラー、またはデータ品質の問題を示す警告サインです
-
誤り: 階層的な絞り込みをせず、1つの解像度だけでアノテーションする 正しい方法: まず大まかな区画(免疫系/間質系/上皮系)にアノテーションし、その後、各区画を専用モデルまたはマーカーで絞り込みます 理由: 分離が不十分なクラスターに対する詳細なラベルは不安定です。階層的なアノテーションにより、より信頼性の高い結果が得られます
参考文献
- CellTypist:Dominguez Conde et al. Science 2022, https://doi.org/10.1126/science.abl5197
- SingleR:Aran et al. Nat Immunol 2019, https://doi.org/10.1038/s41590-018-0276-y
- scANVI:Xu et al. Mol Syst Biol 2021, https://doi.org/10.15252/msb.20209620
- celldex:Aran et al. 2019, https://bioconductor.org/packages/celldex