scRNA-seq解析:手動による細胞型アノテーション(マーカー遺伝子の同定)

scRNA-seq

📚 この記事について:「scRNA-seq解析 実践シリーズ」の細胞型アノテーション編。本記事は手動アノテーション(最も信頼される基準)を、実際のコードで解説します。手法全体の地図は アノテーション手法の全体像 を参照。

🔙 前の記事アノテーション手法の全体像 / 🔜 次の記事マーカーデータベースによる自動アノテーション(scType)

🧩 前提:クラスタリング済みの AnnData(annotated data、scanpy のデータ形式)/正規化済み発現が adata.raw または X にあること/Python の基本。


この記事のゴール

クラスタリングで得た番号つきクラスタ(0, 1, 2, …)に、細胞型の名前を手動で与えること。手動アノテーションには大きく2つのやり方があり、本記事では両方と、その使い分けを扱います。


手動アノテーションの2つのやり方

手動アノテーションの2つのやり方。方法A は文献で確立した既知マーカーを各クラスタの発現と照合して命名する(アノテーションに向く)。方法B は logreg や Wilcoxon 検定でクラスタの高発現遺伝子を計算する(既知なら裏付け、未知なら新規マーカー候補の提案に向く)。
手動アノテーションの2つのやり方。方法A は文献で確立した既知マーカーを各クラスタの発現と照合して命名する(アノテーションに向く)。方法B は logreg や Wilcoxon 検定でクラスタの高発現遺伝子を計算する(既知なら裏付け、未知なら新規マーカー候補の提案に向く)。
  • 方法A:既知マーカーで照合(組織学的・文献ベース)── 既知の細胞型マーカーを各クラスタの発現と突き合わせて命名する。
  • 方法B:計算で高発現遺伝子を出す(logreg・t検定・Wilcoxon)── 各クラスタを特徴づける遺伝子をデータ駆動で求める。

結論を先に言うと、命名そのものは方法A(既知マーカー)が中心で、方法B は裏付けと「新規マーカーの発見」に活きます(後述の経験メモ)。


方法A:既知マーカーで照合(組織学的・文献ベース)

なぜこの方法か

細胞型は、文献で確立したマーカー遺伝子によって定義されています。既知マーカーを各クラスタの発現と照合すれば、生物学的な根拠が明確なまま命名できます。

コード

まず、対象組織の既知マーカーを辞書にまとめ、各クラスタでの発現をドットプロットで確認します。

pythonimport scanpy as sc

# 既知マーカー(例:発生期マウス脳。自分の系・組織に合わせて置換)
marker_genes = {
    "放射状グリア/前駆細胞":   ["Pax6", "Sox2", "Nes", "Hes5"],
    "中間前駆細胞":           ["Eomes", "Neurog2"],
    "興奮性ニューロン":        ["Tbr1", "Neurod6", "Satb2", "Bcl11b"],
    "抑制性ニューロン(GE由来)": ["Gad1", "Gad2", "Dlx2", "Lhx6"],
    "ミクログリア":           ["Cx3cr1", "Aif1"],
    "血管内皮":              ["Cldn5", "Pecam1"],
}

# 各クラスタでの発現をドットプロットで確認(色=平均発現、点の大きさ=発現細胞の割合)
sc.pl.dotplot(adata, marker_genes, groupby="leiden",
              standard_scale="var", dendrogram=True)

UMAP に投影して特異性を確認する

ドットプロットは「どのクラスタでマーカーが強いか」を一覧できますが、値がクラスタごとの平均に要約されているため、クラスタ内のばらつきまでは分かりません。そこで、マーカー遺伝子の発現を UMAP に直接重ねて、本当にそのクラスタに特異的かを目で確かめます。

python# 代表マーカーの発現を UMAP に投影して確認(細胞型ごとに1遺伝子ずつ)
sc.pl.umap(
    adata,
    color=["Pax6", "Eomes", "Neurod6", "Gad2", "Cx3cr1", "Cldn5"],
    ncols=3, cmap="viridis", frameon=False,
)

UMAP に重ねると、ドットプロットでは見えない次の点が確認できます。

  • 他のクラスタにも発現がないか:目的のクラスタ以外にも光っていないか。
  • クラスタ内での広がり:そのクラスタの全細胞で出ているのか、一部の細胞だけか、発現が低いだけか。
  • 複数クラスタにまたがらないか:マーカーによっては生物学的に複数の細胞型で発現することもあります(その場合は他のマーカーと組み合わせて判断します)。

⚠️ 本来発現しないはずのクラスタに発現がある → データ品質を疑う
あるマーカーが、組織学的に発現するはずのないクラスタに出ている場合、マーカー選びの誤りだけでなく、QC の不備やダブレット(2細胞が1つの液滴に入ったもの)の混入を疑います。たとえば、ニューロンのマーカーと血管内皮のマーカーが同じ細胞群で同時に光るなら、それはダブレットかもしれません。このときは QC の閾値やダブレット除去を見直す(→ QCダブレットの検出の記事)のが安全です。

ドットプロットと UMAP で発現を確認したら、「このクラスタはこのマーカー群が特異的に強い」という対応から細胞型を決め、ラベルを付けます。

python# ドットプロットの結果からクラスタ→細胞型を決める(例)
cluster_to_celltype = {
    "0": "興奮性ニューロン",
    "1": "放射状グリア/前駆細胞",
    "2": "抑制性ニューロン(GE由来)",
    "3": "中間前駆細胞",
    # … 全クラスタ分
}
adata.obs["cell_type"] = (
    adata.obs["leiden"].map(cluster_to_celltype).astype("category")
)
sc.pl.umap(adata, color="cell_type", legend_loc="on data", frameon=False)

💡 モジュールスコアで「まとまり」を見る(任意)
1遺伝子ずつではなく、マーカーセット全体のまとまった発現を1つのスコアにして可視化できます。境界があいまいなときの補助になります。

pythonsc.tl.score_genes(adata, marker_genes["興奮性ニューロン"], score_name="ExN_score")
sc.pl.umap(adata, color="ExN_score", frameon=False)

💬 経験メモ:既知マーカーの方が「きれいに」アノテーションしやすい
筆者の経験では、組織学的に確立した既知マーカーで照合する方が、クラスタと細胞型が素直に対応して命名しやすいと感じます。既知マーカーは細胞型を代表するよう選ばれてきた遺伝子なので、発現パターンが明瞭で、判断に迷いにくいためだと考えています。まずは方法Aで骨格を作るのがおすすめです。


方法B:計算でクラスタの高発現遺伝子を出す(logreg・t検定・Wilcoxon)

なぜこの方法か

各クラスタをデータ駆動で特徴づける遺伝子を、統計的に求める方法です。既知マーカーの裏付けに使えるほか、まだ知られていない特徴遺伝子が見つかることもあります。

コード(scanpy の rank_genes_groups)

python# クラスタごとに高発現遺伝子を計算(scRNA-seq では Wilcoxon が推奨)
sc.tl.rank_genes_groups(adata, groupby="leiden", method="wilcoxon")
sc.pl.rank_genes_groups(adata, n_genes=20, sharey=False)

# 上位マーカーをドットプロットで俯瞰
sc.pl.rank_genes_groups_dotplot(adata, n_genes=5)

# 表として取り出す(クラスタごとの上位遺伝子・統計量)
deg = sc.get.rank_genes_groups_df(adata, group=None)
deg.head()

検定手法(method)は次から選べます。

method 概要 特徴
wilcoxon ノンパラメトリックな順位検定 scRNA-seq で推奨。外れ値に頑健
t-test 平均の差の t 検定 高速・簡便。分布の仮定に弱い
logreg ロジスティック回帰 多変量で相互作用を考慮。係数の解釈は別途必要

🔧 scVI を使っている場合:統合に scVI(single-cell variational inference)を使ったなら、モデルベースの差次的発現も使えます。バッチ効果を考慮した検定になります(📖 詳細:サンプル統合:scVIscvi-tools の全体像)。

python# scVI モデルがある場合のクラスタマーカー(モデルベース DE)
de = model.differential_expression(groupby="leiden_scVI")
de.head()

💬 経験メモ・提案:計算で出た遺伝子は「新規マーカーの提案」に向く
方法B で算出される上位遺伝子には、聞いたことのない遺伝子が混じることがよくあります。これをそのまま細胞型名の決定に使うと、対応する細胞型が分からずアノテーションには使いにくいのが実感です。むしろ、既知マーカーで細胞型が確定したクラスタについて、方法B の上位に来る未知遺伝子は、その細胞型の「新しいマーカー候補」と捉えられます。つまり方法B は、アノテーションそのものより、新規マーカー遺伝子の提案にこそ価値があるのではないか、と筆者は考えています。


2つの使い分け(まとめの視点)

  • まず方法A(既知マーカー)で命名する。発現が明瞭で、骨格を素直に作れる。
  • 方法B(計算DE)は2役で使う:(1) 既知マーカーの裏付け、(2) 確定したクラスタから新規マーカー候補を拾う。
  • 両者を組み合わせると、根拠の明確な命名新しい知見の発見を同時に進められます。

つまずきやすいポイント

  • raw / 正規化済みデータを使う:マーカー発現の確認は、正規化・対数化後の値で行います(use_raw=True など)。生カウントのまま見ない。
  • 1遺伝子で決めない:単一マーカーは他の細胞型でも出ることがあります。複数マーカーの組み合わせで判断します。
  • 未知遺伝子を即マーカー扱いしない:方法B の未知遺伝子は、候補として検証(文献・独立データ・タンパク質発現)してから主張します。

まとめ

  • 手動アノテーションには、A:既知マーカーで照合B:計算で高発現遺伝子を出すの2つがある。
  • 命名は方法A が中心(経験上きれいに対応しやすい)。dotplot で既知マーカーの発現を確認して命名する。
  • 方法B(Wilcoxon / logreg / t検定、または scVI のモデルベース DE)は、裏付けと、新規マーカー候補の提案に活きる。
  • 未知遺伝子は候補として扱い、検証を経てから主張する。

次の記事:マーカーデータベースによる自動アノテーション(scType) — 手動で使った「既知マーカー」を、データベースとして自動照合する方法に進みます。


関連記事


参考文献

  • Luecken, M. D., & Theis, F. J. (2019). Current best practices in single-cell RNA-seq analysis: a tutorial. Molecular Systems Biology, 15, e8746. doi:10.15252/msb.20188746
  • Wolf, F. A., Angerer, P., & Theis, F. J. (2018). SCANPY: large-scale single-cell gene expression data analysis. Genome Biology, 19, 15. doi:10.1186/s13059-017-1382-0
  • Heumos, L., Schaar, A. C., Lance, C., et al. (2023). Best practices for single-cell analysis across modalities. Nature Reviews Genetics, 24, 550–572. doi:10.1038/s41576-023-00586-w
  • Xu, C., Lopez, R., Mehlman, E., et al. (2021). Probabilistic harmonization and annotation of single-cell transcriptomics data with deep generative models. Molecular Systems Biology, 17, e9620. doi:10.15252/msb.20209620

コメント

タイトルとURLをコピーしました