# 1つの細胞の中で働く遺伝子を読む（全10回・1回15分・v1.2）

**この講座のゴール**：公開データから、細胞ごとにどの遺伝子が働いているかを自分で読み取る。

高校の生物と数学を終えた学部生向けです。マウスの胎児の膵臓で、ホルモンを作る細胞（インスリンを作る β 細胞など）が育っていく途中を、細胞1個ずつ測った公開データを使います。自分の手でデータを開き、捨てる細胞を決め、細胞に名前を付け、「その差は本物か」を確かめるところまで進みます。最後に「自分はいま何を判断できるか」を1枚に書きます。

> 英語で学びたい人は、最初に『Please teach this course in English.』と伝えてください。

版：v1.2（2026年11月）。実際に使った人のフィードバックで直した版です（下の「この版で直したこと」）。

---

## はじめに（この講座の使い方）

### これは何か
神戸大学大学院医学系研究科 神経生理学分野が、学生の自習用に公開している教材です。1回15分、全10回の対話型の講座です。研究室で、医学部の学生や研究者の方に「1日15分ずつ」使っていただいた道すじを、公開データだけで進められる形に作り直しました。

### 対象
- 高校の生物（DNA・遺伝子・細胞分裂）と数学（割合・対数）で足ります。
- プログラムを書いたことが無くても構いません。毎回10〜25行の Python（パイソン：計算の手順を書く言葉）を写して動かし、1〜2か所だけ自分の値に書き換えます。
- 「表の、どこに何がつながっているのか」が分からなくなるのが、初めての人がいちばん詰まる所です。第1回は、そこだけを小さな表で片づけます。

### 準備するもの
- 対話型の AI（チャットで質問に答えてくれるもの）。このファイルを読み込ませて使います。
- Python が動く所。**無料でブラウザで動かせるノートブック環境（インストール不要）でよい**です。第1回の最初のセルで道具を入れます（約1分）。手元のパソコンで動かす場合は `pip install scanpy igraph leidenalg statsmodels` を1回だけ打ちます。
- 公開データを1つ落とします（第2回・約52MB）。第3回以降は、それを使い回します。
- メモ（紙でも画面でも）。毎回の終わりに1〜3行の「記録」を書きます。この記録が、最後の1枚の材料になります。

### 進め方
1. このファイルを丸ごと対話型の AI に読み込ませる。
2. 「第1回を始めてください」と打つ。
3. AI の問いに、自分の言葉で答える（正しくなくて構いません）。コードは自分で写して動かし、出た結果を AI に貼る。
4. 15分で区切る。次の日に同じファイルを読み込ませ「第2回を始めてください」と打つ。
- AI を使わない人は、各回を上から読み、確認の問いに自分で答えてから「答えと考え方」を開いてください。
- **コードを読まなくても筋が分かるように書いてあります。** 各回の「説明」と「出るはずの結果」だけを読んでも、何を確かめ、何が分かったかは追えます。コードは、自分の手で同じ結果を出したい人のためのものです。
- ノートブック環境によっては、閉じるとファイルが消えます。その時は、第2・3・4回のコードを続けて実行すれば作り直せます（計算は合わせて1分ほど）。

全10回の見取り図:

| 回 | 題 | 手を動かす課題 |
|---|---|---|
| 1 | 入れ物を小さく作る ― 3つの部屋と並び順 | 3細胞×4遺伝子の表を自分で組む（空欄を埋める） |
| 2 | 本物の公開データを開ける | 3,696細胞の表を読み込み、別の道で数を確かめる |
| 3 | どの細胞を捨てるか | 品質の線を先に書き、捨てる細胞の内訳を見る |
| 4 | 細胞の地図と名前 | 答えを見る前に、目印の表だけで名前を付ける |
| 5 | 遺伝子の組で細胞を拾う | 全部の種類の表を見て、間違いを「境目」と「特異性」に分ける |
| 6 | 浅いデータは読めるか | 合否の線を先に書き、練習用の6本を判定する |
| 7 | 「見つからない」は「無い」か | 深さから期待される数と比べる |
| 8 | 何を「1つ」と数えるか | 1本の試料の中の雌と雄を見分け、まとめ数えを作る |
| 9 | その「有意」は本物か | 名札を入れ替えて確かめる（全体で／深さの層の中で） |
| 10 | 地図に細胞を置く | 地図に無い種類がどこへ着くかを、目印と同じ表で見る |

### 用語集（最初に一度、目を通してください）

新しい言葉がまとめて出る回（第3〜5回・第7〜9回）は、各回の頭に「この回で初めて出る言葉」として、この表の番号を書いてあります。分からなくなったら、ここへ戻ってください。

| 番号 | 言葉 | 意味（短く） | 初めて出る回 |
|---|---|---|---|
| 用1 | 遺伝子発現 | 遺伝子の写し（mRNA：メッセンジャー RNA）がどれだけ作られているか | 1 |
| 用2 | NGS | 次世代シークエンサー。細かく切った断片の並びを何千万本も一度に読む装置 | 1 |
| 用3 | 1細胞の RNA の読み取り | 細胞を1個ずつ分け、それぞれの mRNA を数える方法 | 1 |
| 用4 | 分子の数（UMI の数） | 同じ分子のコピーを1回と数えるための目印を使って数えた、mRNA の分子の数 | 2 |
| 用5 | 入れ物（AnnData）／3つの部屋 | 数の表 `X`（細胞×遺伝子）、細胞の説明の表 `obs`、遺伝子の説明の表 `var` を1つに束ねたもの | 1 |
| 用6 | 並び順による連結 | `X` の1行目の細胞と `obs` の1行目は同じ細胞、という約束。名札（行の名前）で結ばれている | 1 |
| 用7 | 深さ | 1個の細胞で数えた分子の総数。深いほど、少ない遺伝子まで見つかる | 3 |
| 用8 | 品質の確かめ（QC） | 壊れた細胞や空の滴を、数で見つけて外すこと | 3 |
| 用9 | ミトコンドリアの割合 | 全分子のうちミトコンドリアの遺伝子が占める割合。壊れた細胞で高くなりやすい | 3 |
| 用10 | 正規化・対数 | 細胞ごとの深さを同じ総数（1万）にそろえ、log(1＋x) で大きな値の暴れを抑えること | 4 |
| 用11 | よく動く遺伝子 | 細胞の間で値の違いが大きい遺伝子。地図を作る時はこれだけを使う | 4 |
| 用12 | 主成分分析（PCA） | たくさんの遺伝子の情報を、少ない数の「方向」に縮めること | 4 |
| 用13 | 群に分ける（クラスタリング）・解像度 | 似た細胞どうしをまとめること。解像度を上げると小さな群がたくさんできる | 4 |
| 用14 | UMAP | 細胞の近さを2次元の絵に描く方法。島どうしの距離や大きさは当てにならない | 4 |
| 用15 | 目印の遺伝子（マーカー） | ある種類の細胞で特に使われ、見分けの手がかりになる遺伝子 | 4 |
| 用16 | 系譜・段階 | 同じ細胞が育っていく道と、その途中の各段階（導管の細胞→Ngn3 が少しの前駆細胞→Ngn3 が多い前駆細胞→ホルモンを作る直前の細胞→α・β・δ・ε の4種類に分かれる） | 4 |
| 用17 | **隣の段階** | 同じ系譜の上で、調べたい段階の**すぐ前か、すぐ後**の段階。道が枝分かれする所では、すぐ後の枝は全部が隣（枝どうしは隣ではない）。目印の遺伝子を共有しているだけの、系譜の上で離れた細胞は「隣」ではない | 5 |
| 用18 | 境目の問題／特異性の問題 | 隣の段階が混ざる＝境目の問題（育ちは連続なので避けにくい）。隣でない細胞が混ざる＝特異性の問題（選んだ遺伝子がその細胞だけのものではない） | 5 |
| 用19 | 点数（スコア）・線 | 選んだ遺伝子の組で各細胞に付けた点と、「ここから上を拾う」と決めた値 | 5 |
| 用20 | 陽性的中率・感度 | 拾った中で当たっていた割合・本物のうち拾えた割合 | 5 |
| 用21 | もともとの割合 | 拾いたい種類が、全部の細胞の中に何割いるか。線を決める手がかり | 5 |
| 用22 | 間引き | 分子をでたらめに捨てて、わざと浅くすること。深さをそろえて比べる時に使う | 6 |
| 用23 | 取りこぼし | 本当は mRNA があるのに、1分子も数えられないこと。浅いほど多い | 7 |
| 用24 | 深さから期待される数 | 基準の群と同じ割合で作られていたら、この深さで何個の細胞に見つかるはずか | 7 |
| 用25 | 独立に取った単位 | 互いに影響し合わずに取った1つ（ふつうは動物1匹）。比べる時の「1件」 | 8 |
| 用26 | まとめ数え（疑似バルク） | 同じ単位の細胞の分子を足し合わせ、単位ごとに1列にした表 | 8 |
| 用27 | 倍率の対数 | 2つの群の値の比を log2 で表したもの。+1 なら2倍、−1 なら半分 | 8 |
| 用28 | p 値・補正 | 「本当は差が無いのに、これ以上の差が偶然出る確率」と、たくさんの遺伝子を一度に調べた時の水増しを直す計算 | 9 |
| 用29 | 疑似反復 | 同じ動物の細胞を、別々に取ったものとして数えてしまうこと。差を大げさに見せる | 9 |
| 用30 | 交絡 | 2つの要因（例：群と測った回）がいつも一緒に変わり、どちらの効果か分けられないこと | 9 |
| 用31 | 入れ替えの確かめ（並べ替え検定） | 群の名札をでたらめに入れ替えて、偶然でどれだけの差が出るかを直接作ること | 9 |
| 用32 | 層の中で入れ替える | 深さの近い細胞どうしの中だけで入れ替えること。深さの差が群の差に見えるのを防ぐ | 9 |
| 用33 | 地図に置く（ラベルの移し替え） | 別の細胞で作った地図の上に、自分の細胞を置き、近い群の名前を借りること | 10 |
| 用34 | GEO | 米国の国立生物工学情報センター（NCBI）が運営する、遺伝子発現データの公開の倉庫 | 2 |
| 用35 | 循環（同じデータで二度使う） | 群を分けるのに使った遺伝子で、その群どうしを比べること。差は必ず出るので、証拠にならない | 9 |

### この版で直したこと（v1.1 → v1.2）
- 題材のデータを、マウスの膵臓で内分泌の細胞（ホルモンを作る細胞）が育つ途中を測った公開データ1本に替えました。約52MB のファイルを1回落とせば、全10回が進められます。
- 前の版に寄せられた声で直した4点は、そのまま残しています。①答え合わせの表の横に、その群の目印の値を並べた（第4・10回）②選んだ遺伝子が全部の種類でどれだけ見つかるかの表を最初に出す（第5回）③「隣の段階」を1文で定義した（用語集の用17・第5回）④用語集を最初に置き、言葉が多い回から番号で引けるようにした。
- 第10回を「地図に無い種類の細胞は、どこへ着くか」を自分で試す形にしました。
- コードを読まない人も筋を追えるように、各回の「説明」と「出るはずの結果」だけで話がつながる書き方にしました。
- 最後の1枚の各行に「なぜなら」を必ず書く形は、前の版のままです。

### 注意
- **AI は間違えることがあります。** 大事な所は教科書や原典（論文・公式の説明）で確かめてください。この講座の「出るはずの結果」も、道具の版や乱数で少し変わることがあります。
- 自分や他人の個人情報・診療の情報・他人のデータを AI に入れないでください。この講座で AI に貼ってよいのは、公開データから自分で出した結果だけです。
- この講座は医療上の助言を目的としていません。膵臓やインスリンが出てきますが、病気の診断や治療の話はしません。

### フィードバックのお願い（必須）

> **この講座は、使った人の声で毎回直しています。使った方は、必ずフィードバックをお送りください。**
>
> 送り先：研究室ホームページの『連絡先』のページにあるアドレス
> 件名：「講座フィードバック：NGSの遺伝子発現解析」
> 書いてほしい4点：
> 1. 何回目まで進んだか
> 2. 分かりにくかった所（どの回の、どの表・どの言葉か）
> 3. 良かった所
> 4. 1回にかかった時間
>
> （あれば）足してほしい図や例、最後の1枚も添えてください。途中でやめた人の声も、同じくらい役に立ちます。この講座の4つの直しは、実際に送っていただいた声から生まれました。

### 利用の条件
- 個人の学習・授業での利用は自由です。
- 改変して配る時は、研究室へご連絡ください。
- 使う公開データは、論文と道具の論文を引用し、GEO の利用の条件に従ってください（第2回・最後の「使ったデータと文献」）。
- 内容は 2026年11月時点のものです。

---

## AI への指示（先生役のやり方）

この節は、このファイルを読み込んだ AI が従う決まりです。

1. **1回15分で区切る。** 各回の頭の「時間の目安」を守る。越えそうなら、次のきりのよい所で止めて記録を書かせ、残りは次の回へ回す。
2. **1度に1つだけ問い、相手の答えを待つ。** 1回の発言は200字以内（英語なら100語以内）。「もっと詳しく」と言われた時だけ伸ばす。
3. **答えを先に言わない。** 線（品質の線・点数の線）や遺伝子の組は、まず学習者に自分の値を書かせ、そのあとで AI の案を出す。「答えと考え方」の折りたたみは、学習者が答えた後か「答えを見せて」と言った時だけ使う。
4. **数は別の道で確かめさせる。** AI が数（線・個数・倍率）を言ったら、学習者の出力と照らすか、別の計算（`.shape` と `len()`、表と図など）で確かめるよう促す。生物の主張も、AI の言葉ではなくデータの中の遺伝子で確かめさせる。
5. **作らない。** このファイルに無いデータの番号・遺伝子名・p 値・論文を作らない。論文を勧める時は DOI か PubMed の番号を付け「実在と中身を確かめてください」と添える。
6. **見ていない物を「見えます」と言わない。** 学習者の出力が貼られていなければ、貼るよう頼む。
7. **コードは学習者が写して動かす。** 各回のコードを長く書き換えたり、手順を足したりしない。エラーが貼られたら、どの行で何が起きたかを1つずつ説明する。出た結果を、各回の「出るはずの結果」と比べさせる（版によって少し違ってよい。大きく違えば、その前の回の線や設定を一緒に見直す）。コードを動かさない学習者には、「説明」と「出るはずの結果」の表を一緒に読み、同じ問いに答えさせる。
8. 各回の初めに、前の回の要点から思い出しの問いを1つ出す。前の回に間違えた所があれば、それを優先する。新しい言葉が3つ以上出る回は、用語集の該当の番号を最初に示し、その場で1つずつ短く言い直す。
9. 各回の「図」は、説明のその場面で枠のまま見せる。
10. 第5回以降、間違えて拾った細胞の話になったら、用語集の用17の定義（同じ系譜の、すぐ前かすぐ後の段階だけが「隣」。枝分かれの先は全部が隣）で判定させる。目印を共有しているだけの、系譜の上で離れた細胞を「隣」と呼ばない。
11. 各回の「この回でやることを1文で」では、学習者の文に「どの部屋（X・obs・var）の、どの列か」が入っているかを見て、入っていなければ1つだけ足すよう促す（AI に作業を頼む指示文の練習）。
12. 各回の終わりに、要点3つとミニ確認問題2問を出す。続けて記録の1〜3行を一緒に整え、最後にかかった時間を聞く。
13. 次の回へ勝手に進まない。学習者が「第N回を始めてください」と打った時だけ始める。
14. 学習者が医療の相談や、自分・他人の個人情報、他人のデータを書いたら、扱わずに断り、一般の説明に戻る。
15. 第1回の最初に1問ずつ聞く：「この講座で何ができるようになりたいですか」「Python を動かしたことはありますか」「表計算で表の行と列を扱ったことはありますか」。答えに合わせて例えと速さを変える。
16. 第10回の後（または途中でやめると言われた時）に、修了の1枚（各行に「なぜなら」）を一緒に仕上げ、フィードバックの4点を1つずつ聞き、メールにそのまま貼れる形に整えて渡す。送り先は研究室ホームページの『連絡先』のページ。
17. 学習者の人柄ではなく、表・線・理由について話す。良かった点を1つ、直す点は2つまで。
18. 学習者が英語を求めたら英語で進める。専門用語は英語を併記する。

---
## 第1回　入れ物を小さく作る ― 3つの部屋と「並び順」

**問い**：細胞の種類（たとえば「β 細胞」）という情報は、数の表のどこに書いてあるのでしょうか？
**↓** 数の表の中にはどこにもありません。別の表に書いてあり、2つの表は「並び順」だけでつながっています。

**時間の目安**：読む 5分・打つ 8分・記録 2分

**この回のねらい**
1. 1細胞のデータの入れ物が、3つの部屋（`X`・`obs`・`var`）でできていると言える。
2. 部屋どうしが「並び順（行の名札）」でつながっていると言える。
3. 並びが崩れても、エラーが出ずに違う値が返ることを、自分の目で見る。

### 説明
体の細胞は、ほとんど同じ DNA を持っています。それでも膵臓の β 細胞と皮膚の細胞が違うのは、どの遺伝子をどれだけ写しているか、つまり遺伝子発現（遺伝子の写しの mRNA がどれだけ作られているか）が違うからです。NGS（次世代シークエンサー：細かく切った断片の並びを一度に何千万本も読む装置）を使うと、この mRNA を数えられます。1細胞の RNA の読み取り（細胞を1個ずつ分け、それぞれの mRNA を数える方法）では、細胞1個ごとに「どの遺伝子の分子が何個あったか」が出てきます。

出てくるのは、結局1枚の大きな表です。行が細胞、列が遺伝子、中身は数えた分子の数です。ところが、この表だけでは「この行の細胞は何の細胞か」が分かりません。そこで Python の入れ物（AnnData：アンデータ）は、部屋を3つ持っています。

数の表そのものが `X`、細胞の説明の表が `obs`（細胞1個につき1行）、遺伝子の説明の表が `var`（遺伝子1個につき1行）です。**3つの部屋をつないでいるのは、並び順（行の名札）だけです。** `X` の1行目の細胞と `obs` の1行目は同じ細胞、という約束しかありません。

この約束は、破れても誰も教えてくれません。今日は、それを3細胞×4遺伝子の小さな表で確かめます。初めてこの種のデータを扱った人が一番苦労したのは、「属性のデータがどこにどうつながっているのか」でした。最初にここを片づけておくと、後の9回がずっと楽になります。

### 図
```text
              var（遺伝子の説明：1遺伝子＝1行）
              Ins1   Gcg    Sox9   Mki67
            ┌──────────────────────────────┐
 obs        │                              │
 cellA β細胞 │  5      0      1      0      │  ← X（数の表）の1行目 ＝ obs の1行目
 cellB α細胞 │  0      8      0      2      │
 cellC 導管  │  0      1      7      3      │
            └──────────────────────────────┘
 obs（細胞の説明：1細胞＝1行）   つなぐのは「並び順」だけ
```

### 手を動かす課題（Python・空欄を埋める）
ノートブックの最初のセルで、道具を入れます（約1分。`ERROR` と出なければ大丈夫）。

```python
!pip -q install scanpy igraph leidenalg statsmodels
```

次のセルの `____` の3か所を埋めてください。Ins1 はインスリンの遺伝子で β 細胞の目印、Gcg はグルカゴンの遺伝子で α 細胞の目印、Sox9 は導管（膵液を運ぶ管）の細胞の目印です。各細胞で一番大きい数の遺伝子から、種類を決めます。

```python
import numpy as np, pandas as pd, anndata as ad
X = np.array([[5, 0, 1, 0],
              [0, 8, 0, 2],
              [0, 1, 7, 3]], dtype=np.float32)
toy = ad.AnnData(X)
toy.obs_names = ["cellA", "cellB", "cellC"]           # 行の名札（細胞）
toy.var_names = ["Ins1", "Gcg", "Sox9", "Mki67"]      # 列の名札（遺伝子）
toy.obs["cell_type"] = [____, ____, ____]             # ← "β細胞" "α細胞" "導管" を正しい順に
print(toy)
print(toy.obs)
print(toy[toy.obs["cell_type"] == "α細胞", "Gcg"].X)  # 名前で取り出す
ok = float(toy[toy.obs["cell_type"] == "α細胞", "Gcg"].X[0, 0]) == 8.0
print("◯ 並びが揃っている" if ok else "× 並びがずれている：表のどの細胞でどの遺伝子が大きいかを見直す")
```

**出るはずの結果**：`AnnData object with n_obs × n_vars = 3 × 4`、取り出した値 `[[8.]]`、最後に `◯ 並びが揃っている`。

続けて、**わざと**並びを間違えます。`cell_type` の行を `["α細胞", "β細胞", "導管"]` に書き換えて、もう一度実行してください。何が返るか、実行する前に予想してから動かします。

**この回でやることを1文で**：今日の課題を、AI に頼む指示文として1文で書いてください。例の形「`toy` は行＝細胞の AnnData です。`obs` の `cell_type` の列に、`X` の行の順で種類を入れてください」。どの部屋の、どの列かを名指しすると、狙いどおりの答えが一回で返りやすくなります。

**記録（例）**：`第1回　3つの部屋＝X・obs・var。つなぐのは並び順だけ。並びを崩すと [[0.]] が返り、エラーは出なかった。`

### 確認の問い
1. `obs` の1行は、何を表していますか。
2. 並びを間違えた時、なぜエラーが出なかったのでしょうか。
3. 遺伝子を半分に減らしたら（`var` の行が減ったら）、`obs` の行の数は変わりますか。

<details><summary>答えと考え方（AI 用・学習者は答えてから開く）</summary>

- 課題の空欄：`["β細胞", "α細胞", "導管"]`（cellA は Ins1＝5、cellB は Gcg＝8、cellC は Sox9＝7 が最大）。
- 並びを間違えた版：`[[0.]]` が返り、最後に `× 並びがずれている…` と出る（作り手の環境で確認）。「α細胞」と書かれた cellA の Gcg は 0 だから。
- 問1：細胞1個。その細胞の種類などの説明が並ぶ。
- 問2：プログラムは「1行目どうしは同じ細胞」という約束を信じて動くだけで、中身が正しいかは知らないから。だから自分の目で確かめる手順（今日の ◯× のセル）を置く。
- 問3：変わらない。遺伝子（列）を減らしても細胞（行）の並びは崩れない。だから `obs` の `cell_type` はそのまま使える。

</details>

### まとめ
- 入れ物は3つの部屋：数の表 `X`、細胞の説明 `obs`、遺伝子の説明 `var`。
- 部屋をつなぐのは並び順だけ。崩れてもエラーは出ない。
- AI への指示は「どの部屋の、どの列か」を名指しすると伝わる。

---

## 第2回　本物の公開データを開ける

**問い**：論文の著者が「3,696個の細胞を測りました」と書いていたら、読み込んだ表が本当にそうなっているかは、どう確かめればよいでしょう？
**↓** 同じ数を、違う道で2回数えます。一致すれば、読み込み方が合っている証拠になります。

**時間の目安**：読む 4分・打つ 9分・記録 2分（約52MB を落とします。1分前後）

**この回のねらい**
1. 公開データのファイルを取り、3つの部屋の中身を言える。
2. 細胞の数を、別の道でもう一度数えて確かめられる。
3. 要らない棚を外し、生の数を控えの棚に移せる。

### 説明
今日使うのは、マウスの胎児（受精から15.5日目）の膵臓で、ホルモンを作る細胞が育つ途中を測った公開データです（Bastidas-Ponce ら 2019, *Development* 146(12):dev173849, doi:10.1242/dev.173849）。もとのデータは GEO（米国の国立生物工学情報センターが運営する、遺伝子発現データの公開の倉庫）の **GSE132188** に置かれています。今日は、その15.5日目の分を、解析の道具（scVelo：スケベロ）の作り手が練習用に1つのファイルにまとめた物（約52MB）を使います。

膵臓では、導管（膵液を運ぶ管）の細胞の仲間から、Ngn3（ニューロジェニン3）という遺伝子を使い始めた前駆細胞が生まれ、ホルモンを作る直前の段階を通って、4種類のホルモンの細胞に分かれます。インスリンの β 細胞、グルカゴンの α 細胞、ソマトスタチンの δ 細胞、グレリンの ε 細胞です。このファイルの著者は、細胞1個1個にこの段階の名前を付けています。

中身は、分子の数（UMI の数：同じ分子のコピーを1回と数えるための目印を使って数えた数）の表です。このファイルは、はじめから入れ物（AnnData）の形なので、読み込むだけで3つの部屋がそろいます。ただし、著者の地図や別の解析用の棚もたくさん付いています。今日は、著者の付けた名前だけを `cell_type` という列に残し、ほかの付録は外します。名前は第4回まで「答え」として取っておき、先には見ません。

確かめの考え方は簡単です。細胞の説明の表 `obs` の行の数と、数の表 `X` の行の数と、著者の名前ごとの細胞の数の合計は、同じ細胞を別の道で数えた数です。合わなければ、どこかで読み落としや取り違えがあります。

### 図
```text
 ファイル（はじめから入れ物の形）            今日の形
 X        細胞 × 遺伝子 の数             X       細胞 × 遺伝子 の数
 obs      著者の名前・ほかの数   ─外す→   obs     cell_type（著者の名前）だけ
 付録の棚  著者の地図・別の解析用          layers  counts（生の数の控え）
```

### 手を動かす課題（Python・空欄1か所）
`____` を埋めてから実行します。ヒント：生の数が入っているのは、第1回の3つの部屋のうちの、どの部屋でしたか。

```python
import urllib.request, os, scanpy as sc, pandas as pd
url = ("https://github.com/theislab/scvelo_notebooks/raw/master/"
       "data/Pancreas/endocrinogenesis_day15.h5ad")
if not os.path.exists("endocrinogenesis_day15.h5ad"):
    urllib.request.urlretrieve(url, "endocrinogenesis_day15.h5ad")     # 約 52MB
adata = sc.read_h5ad("endocrinogenesis_day15.h5ad").copy()
print(adata)                                       # 読み込んだままの姿
adata.obs = adata.obs[["clusters"]].rename(columns={"clusters": "cell_type"})  # 著者の名前だけ残す
del adata.obsm, adata.obsp, adata.uns, adata.layers                   # 著者の地図と付録は外す
adata.layers["counts"] = adata.____.copy()         # ← 生の数を、別の棚に控えておく
print(adata)
print("細胞の数（obs の行）:", adata.n_obs, "  数の表の行:", adata.X.shape[0])
tab = adata.obs["cell_type"].value_counts()
print(tab.to_string())
print("◯ 別の道で数えても同じ" if tab.sum() == adata.n_obs == adata.X.shape[0] else "× 数が合わない")
adata.write_h5ad("ngs_day2.h5ad")
```

**出るはずの結果**（作り手の環境で確認。読み込みの時に、置き場所の移し替えについての注意書きが出ることがありますが、気にしなくて大丈夫です）：
```text
AnnData object with n_obs × n_vars = 3696 × 27998
細胞の数（obs の行）: 3696   数の表の行: 3696
Ductal           916
Ngn3 high EP     642
Pre-endocrine    592
Beta             591
Alpha            481
Ngn3 low EP      262
Epsilon          142
Delta             70
◯ 別の道で数えても同じ
```
著者の名前は8つです。`Ductal` は導管の細胞、`Ngn3 low EP`・`Ngn3 high EP` は Ngn3 を少し／たくさん使っている内分泌の前駆細胞（EP は endocrine progenitor の略）、`Pre-endocrine` はホルモンを作る直前の細胞、`Alpha`・`Beta`・`Delta`・`Epsilon` は4種類のホルモンの細胞です。

**この回でやることを1文で**：「`adata` の `obs` の `cell_type` の列で、名前ごとの細胞の数を数え、合計が `obs` の行の数と同じかを確かめてください」のように、部屋と列を名指しして書いてみてください。

**記録（例）**：`第2回　膵臓の15.5日目のデータ 3696細胞×27998遺伝子。名前は8つ（導管916〜δ70）。3つの道で数えて一致。`

### 確認の問い
1. `3696 × 27998` の、どちらが細胞でどちらが遺伝子ですか。コードを見ずに答えてください。
2. いちばん少ない種類は何個ですか。少ない種類は、後の回でどんな困りごとを起こしそうですか。
3. `print(adata.X[:3].sum(1))` で、最初の3つの細胞の分子の総数を見てください。細胞によって数が違うのは、なぜだと思いますか。

<details><summary>答えと考え方（AI 用）</summary>

- 空欄：`X`（`adata.layers["counts"] = adata.X.copy()`）。このファイルの `X` には、数えたままの整数が入っている（作り手の環境で、整数だけであることを確認）。
- 問1：3,696 が細胞（行）、27,998 が遺伝子（列）。
- 問2：`Delta` の70個。細胞が少ない群では、「見つからなかった」が偶然でも起きやすい（第7回）し、群の割合も揺れやすい。
- 問3：作り手の環境では 4954・7071・4070。細胞の大きさや、壊れ方、読み取りの具合で、数えられた分子の総数（深さ）が違う。第3回で使う。

</details>

### まとめ
- 公開データは、論文と番号（GSE132188）と利用の条件をセットで扱う。
- 数は別の道でもう一度数え、一致を確かめる。
- 著者の名前は「答え」として取っておき、先には見ない。

**データの出どころと条件**：もとのデータは GSE132188（NCBI GEO）。使う時は、Bastidas-Ponce ら 2019 の論文と、練習用のファイルを配っている道具の論文（Bergen ら 2020, *Nature Biotechnology* 38(12):1408–1414, doi:10.1038/s41587-020-0591-3）を引用し、GEO の利用の条件（NCBI は制限を設けていないが、登録者が権利を主張する場合がある）に従ってください。

---

## 第3回　どの細胞を捨てるか ― 品質の線を先に引く

**問い**：品質の悪い細胞を捨てる線は、データを見てから決めればよいのでは？
**↓** 線を先に書き、捨てた細胞の「内訳」を見ます。ある種類だけが大量に消えていたら、捨てているのは雑音ではなく生物学です。

**時間の目安**：読む 3分・打つ 10分・記録 2分

**この回で初めて出る言葉**：用7 深さ・用8 品質の確かめ・用9 ミトコンドリアの割合（用語集を見てから進めてください）

**この回のねらい**
1. 細胞ごとの3つの数（深さ・見つかった遺伝子の数・ミトコンドリアの割合）を言える。
2. 自分の線を書き、それで何個の細胞が消えるかを数えられる。
3. 消えた細胞の種類ごとの割合を見て、線を直すか判断できる。

### 説明
細胞を1個ずつ分ける時、途中で壊れる細胞や、細胞が入っていない滴もあります。それを見つけるのが品質の確かめ（QC：壊れた細胞や空の滴を数で見つけて外すこと）です。使う数は3つです。深さ（1細胞で数えた分子の総数）、見つかった遺伝子の数、そしてミトコンドリアの割合（全分子のうちミトコンドリアの遺伝子が占める割合）です。細胞の膜が破れると、細胞質の mRNA は逃げますが、ミトコンドリアの中の mRNA は残りやすいので、この割合が上がります。

ここで大事なのは順番です。まず自分の線を書く。次に、その線で何個消えるかを数える。最後に、消えた細胞が**どの種類に偏っているか**を見る。もともと mRNA の少ない種類の細胞があれば、一律の線はその種類だけを削ってしまいます。

このデータには、もう1つ手がかりがあります。深さの最小値と、ミトコンドリアの割合の最大値を見てください。とても浅い細胞も、ミトコンドリアの多い細胞も、1つもありません。これは、著者が登録の前に既に捨てている、ということです。

### 図
```text
 線を書く ──▶ 何個消える？ ──▶ どの種類が消える？
                                 ├ どの種類もほぼ同じ割合 → 雑音を捨てている
                                 └ 1つの種類だけ多い     → 生物学を捨てているかも
```

### 手を動かす課題（Python）
`MIN_GENES` と `MAX_MT` に、**結果を見る前に**自分の値を書いてから実行します（下の例は 1000 と 5）。

```python
import scanpy as sc, pandas as pd
adata = sc.read_h5ad("ngs_day2.h5ad")
adata.var["mt"] = adata.var_names.str.startswith("mt-")      # ミトコンドリアの遺伝子
sc.pp.calculate_qc_metrics(adata, qc_vars=["mt"], inplace=True)
print(adata.obs[["total_counts", "n_genes_by_counts", "pct_counts_mt"]].describe().round(1))
MIN_GENES, MAX_MT = 1000, 5                    # ← 自分の線を先に書く
keep = (adata.obs["n_genes_by_counts"] >= MIN_GENES) & (adata.obs["pct_counts_mt"] <= MAX_MT)
print("捨てる細胞:", (~keep).sum(), "個 /", adata.n_obs, "個")
rate = 100 * (~keep).groupby(adata.obs["cell_type"], observed=True).mean()
n = adata.obs["cell_type"].value_counts()
print(pd.DataFrame({"捨てる割合%": rate.round(1), "細胞数": n}).sort_values("捨てる割合%", ascending=False).head(5))
adata = adata[keep].copy()
adata.write_h5ad("ngs_day3.h5ad")
```

**出るはずの結果**（作り手の環境・線 1000 と 5）：深さ（`total_counts`）の最小は 3020、見つかった遺伝子の数の最小は 1473、ミトコンドリアの割合の最大は 4.3%。捨てる細胞は **0個**／3696個でした。

続けて `MIN_GENES` だけを 2000 にして、もう一度動かしてください（最後の `write_h5ad` の行は動かさず、次の回は 1000 と 5 の版で進めると、以後の「出るはずの結果」と比べやすくなります）。作り手の環境では、捨てる細胞は 374個になり、その内訳は `Pre-endocrine`（ホルモンを作る直前の細胞）が 23.8%、`Ngn3 high EP` が 15.6%、`Alpha` が 10.8% でした。育ちの途中の段階ほど、見つかる遺伝子が少なく、一律の線で削られやすいのです。

**この回でやることを1文で**：「`obs` の `n_genes_by_counts` と `pct_counts_mt` で細胞を選び、消えた細胞を `cell_type` ごとの割合で見せてください」のように書いてみましょう。

**記録（例）**：`第3回　線＝遺伝子1000以上・ミトコンドリア5%以下で0個。最小の深さ3020・ミトコンドリア最大4.3%＝著者が先に捨てている。遺伝子2000にすると Pre-endocrine が23.8%消える。`

### 確認の問い
1. 深さの最小が 3020、ミトコンドリアの割合の最大が 4.3% だという事実から、何が分かりますか。
2. 遺伝子の線を 2000 に上げた時、ホルモンを作る直前の細胞が4分の1近く消えました。あなたなら線をどうしますか。理由も1つ。
3. 「線は AI に決めてもらえばよい」という意見に、1文で答えてください。

<details><summary>答えと考え方（AI 用）</summary>

- 問1：著者が登録の前に、浅い細胞と壊れた細胞を既に捨てている。自分の線を引いても、ほとんど何も消えないのはそのため。
- 問2：正解は1つではない。例＝2000 にはしない（消えるのは壊れた細胞ではなく、もともと遺伝子の少ない段階の細胞だから）／種類ごとに別の線にする。大事なのは「消えた細胞の内訳を見てから決めた」ことと、その理由を記録に書くこと。
- 問3：例＝AI の案は自分の値を書いた後に聞き、消える細胞の数と内訳で、どちらがよいかをデータで決める。

</details>

### まとめ
- 品質の数は3つ：深さ・見つかった遺伝子の数・ミトコンドリアの割合。
- 線は先に書く。消えた細胞の種類ごとの割合を必ず見る。
- 公開データは、既に誰かが一度線を引いていることがある。

---

## 第4回　細胞の地図を作り、答えを見る前に名前を付ける

**問い**：計算で分けた細胞の群に、著者の名前（答え）を先に重ねて見てはいけないのでしょうか？
**↓** 先に見ると、自分の目で読む練習になりません。目印の表だけで名前を付け、そのあと**同じ表の右端**で答え合わせをします。

**時間の目安**：読む 3分・打つ 10分（計算に約30秒）・記録 2分

**この回で初めて出る言葉**：用10 正規化・対数・用11 よく動く遺伝子・用12 主成分分析・用13 群に分ける・用14 UMAP・用15 目印の遺伝子・用16 系譜・段階（言葉が多い回です。先に用語集を開いてください）

**この回のねらい**
1. 決まった手順（正規化→よく動く遺伝子→主成分分析→近さのつながり→地図→群に分ける）を、各段の目的とともに言える。
2. 目印の遺伝子の平均の表から、群に名前を付けられる。
3. 膵臓でホルモンの細胞が育つ段階を、順番に言える。

### 説明
細胞ごとに深さが違うので、まず正規化（深さを同じ総数1万にそろえ、log(1＋x) で大きな値の暴れを抑えること）をします。次に、細胞の間で違いの大きい「よく動く遺伝子」2,000個だけを使い、主成分分析（たくさんの遺伝子の情報を少ない数の方向に縮めること）で30の方向に縮めます。そこから、各細胞に近い細胞を結び、群に分けます（クラスタリング：似た細胞どうしをまとめること）。UMAP（細胞の近さを2次元の絵に描く方法）は、その結果を目で見るための絵です。島どうしの距離や島の大きさは当てにならないので、絵だけで結論しないでください。

名前は、目印の遺伝子（ある種類の細胞で特に使われる遺伝子）で付けます。このデータの細胞は、次の道を順に通って育ちます。この道を系譜と呼びます。

導管の細胞（Sox9 が高い）→ Ngn3 を使い始めた前駆細胞（Neurog3＝Ngn3 の遺伝子が高い。分裂中の細胞は Mki67 も高い）→ ホルモンを作る直前の細胞（Fev が高い）→ 4種類に分かれる（β＝Ins1、α＝Gcg、δ＝Sst、ε＝Ghrl）。

答え合わせの表は、**目印の値の表の右端に、著者の名前を並べた1枚**にします。2つの表を行ったり来たりすると、群の番号を取り違えやすいからです（実際に使った方から「表を切り替えるうちに名前を間違えた」という声がありました）。

### 図
```text
 育ちの順 ─────────────────────────────────────────────────────▶
 Ductal → Ngn3 low EP → Ngn3 high EP → Pre-endocrine ─┬→ Beta    （Ins1）
  Sox9      Neurog3 少し    Neurog3 多い     Fev        ├→ Alpha   （Gcg）
                                                      ├→ Delta   （Sst）
                                                      └→ Epsilon （Ghrl）
```

### 手を動かす課題（Python）
```python
import scanpy as sc, pandas as pd
adata = sc.read_h5ad("ngs_day3.h5ad")
sc.pp.normalize_total(adata, target_sum=1e4); sc.pp.log1p(adata)
sc.pp.highly_variable_genes(adata, n_top_genes=2000)
sc.pp.pca(adata, n_comps=30, mask_var="highly_variable")
sc.pp.neighbors(adata, n_pcs=30); sc.tl.umap(adata)
sc.tl.leiden(adata, resolution=0.5, flavor="igraph", n_iterations=2)
markers = ["Sox9", "Mki67", "Neurog3", "Fev", "Ins1", "Gcg", "Sst", "Ghrl"]
mk = sc.get.obs_df(adata, keys=markers).groupby(adata.obs["leiden"], observed=True).mean().round(1)
print(mk.to_string())                      # (1) まずこれだけを見て、各群に名前を付ける
ct = pd.crosstab(adata.obs["leiden"], adata.obs["cell_type"])
mk["著者の名前"] = ct.idxmax(axis=1)
mk["割合"] = (ct.max(axis=1) / ct.sum(axis=1)).round(2)
mk["細胞数"] = ct.sum(axis=1)
print(mk.to_string())                      # (2) 名前をメモしてから、同じ表の右端で答え合わせ
sc.pl.umap(adata, color=["leiden", "cell_type"], legend_fontsize=7)
adata.write_h5ad("ngs_day4.h5ad")
```

(1) の表が出たら、**(2) を見る前に**、各群の番号の横に自分の付けた名前をメモしてください。

**出るはずの結果**（作り手の環境・scanpy 1.11.5。群の数と番号は版で変わります）：群は10個。

```text
     Sox9 Mki67 Neurog3  Fev Ins1  Gcg  Sst Ghrl  著者の名前     割合  細胞数
0     0.4  0.0    1.3   2.6  0.2  0.1  0.0  0.2  Pre-endocrine  0.81  529
1     1.7  0.0    0.5   0.0  0.1  0.2  0.1  0.2  Ductal         0.71  687
2     1.6  0.7    0.3   0.0  0.1  0.1  0.0  0.1  Ductal         0.83  514
3     0.1  0.0    0.2   1.3  0.3  2.7  0.0  0.2  Alpha          0.84  548
4     0.3  0.0    3.2   0.2  0.1  0.1  0.0  0.2  Ngn3 high EP   0.91  459
5     0.5  1.1    2.8   0.3  0.2  0.2  0.1  0.2  Ngn3 high EP   0.88   26
6     0.5  0.0    0.5   1.3  0.2  0.2  2.7  0.2  Delta          0.50  137
7     0.2  0.0    0.2   1.0  2.7  0.2  0.2  0.2  Beta           0.99  464
8     0.5  0.0    3.4   0.0  0.2  0.1  0.0  0.1  Ngn3 high EP   1.00  166
9     0.2  0.0    0.8   0.6  0.2  1.3  0.0  5.5  Epsilon        0.84  166
```

目印の1つが飛び抜けて高い群は、名前がそのまま当たります（Ins1 が 2.7 の群7＝β・割合 0.99、Ghrl が 5.5 の群9＝ε）。一方で、著者の名前の1つ `Ngn3 low EP` は、どの群でも最多になりませんでした。導管の群1・群2 に混ざっています（群1 の割合が 0.71 と低いのはそのため）。Sst の高い群6 も、割合は 0.50 で、残りの多くはホルモンを作る直前の細胞でした。

**この回でやることを1文で**：「`obs` の `leiden` の群ごとに、`markers` の遺伝子の平均を表にし、右端に `cell_type` の最多の名前と割合を足してください」のように書いてみましょう。

**記録（例）**：`第4回　群10個。目印だけで名前を付け …群中…群が一致。Ngn3 low EP は自分の群を持たず導管の群に混ざる。δの群は割合0.50（直前の細胞と混ざる）。`

### 確認の問い
1. `Ngn3 low EP` が自分の群を持たず、導管の群に混ざったのは、なぜだと思いますか。
2. 割合が 0.50 の群（群6）に、あなたならどんな名前を付けますか。
3. `resolution=0.5` を 1.0 にすると、群の数はどうなると思いますか。

<details><summary>答えと考え方（AI 用）</summary>

- 問1：導管の細胞から Ngn3 を使い始めた細胞へは連続的に移る。使い始めの細胞は、まだ遺伝子の多くが導管の細胞と同じなので、近さで分けると導管の側にまとまる。境目に名前の箱を置くと、箱どうしが混ざる。
- 問2：正解は1つではない。例＝「δ と、δ になる直前の細胞」。目印の値（Sst 2.7・Fev 1.3）と割合を書き添えれば、混ざっていることが読む人に伝わる。無理に1つの名前に丸めない。
- 問3：群が増え、小さく分かれる（作り手は試していない。学習者に試させてよい）。

</details>

### まとめ
- 正規化→よく動く遺伝子→主成分分析→近さ→群、の各段には目的がある。
- 名前は目印の表で先に付け、同じ表の右端で答え合わせをする。
- このデータの細胞は、導管の細胞から4種類のホルモンの細胞へ、枝分かれする道（系譜）を育つ。

---

## 第5回　遺伝子の組で細胞を拾う ― 「境目」と「特異性」を分ける

**問い**：Ngn3 を多く使う前駆細胞（`Ngn3 high EP`）を拾うのに、教科書でおなじみの「内分泌の細胞の目印」を5個選べば十分でしょうか？
**↓** 選んだ5個を**全部の種類**で並べてみると、狙った段階より、すぐ後の段階でずっと多く見つかる遺伝子が混ざっています。1個ずつ見ていると気づきません。

**時間の目安**：読む 3分・打つ 9分・記録 3分

**この回で初めて出る言葉**：用17 隣の段階・用18 境目の問題／特異性の問題・用19 点数と線・用20 陽性的中率と感度・用21 もともとの割合

**この回のねらい**
1. 選んだ遺伝子が、全部の種類で何%の細胞に見つかるかを1枚の表で見られる。
2. 拾った結果を、陽性的中率と感度の2つの数で言える。
3. 間違えて拾った細胞を、「隣の段階」（境目の問題）と「隣でない細胞」（特異性の問題）に分けられる。

### 説明
狙いは `Ngn3 high EP` です。遺伝子を5個選び、各細胞にその組の点数（選んだ遺伝子がどれだけ高いかの点）を付け、線より上を「拾った」とします。

拾った結果は2つの数で言います。陽性的中率（拾った中で当たっていた割合）と感度（本物のうち拾えた割合）です。片方だけ良くするのは簡単です。線をとても高くすれば陽性的中率は上がり、低くすれば感度は上がります。線の手がかりは、もともとの割合（拾いたい種類が全部の細胞の何割か）です。`Ngn3 high EP` はこのデータで全体の約17%なので、「上位17%を拾う」線から始めると、2つの数の釣り合いが取りやすくなります。

間違えて拾った細胞は、2種類に分けて考えます。ここでの「隣」には、はっきりした決まりがあります。

> **隣の段階とは、同じ系譜の上で、狙った段階のすぐ前か、すぐ後の段階のことです。** 道が枝分かれする所では、すぐ後の枝は全部が隣です。枝分かれした後の4種類どうし（β と α など）は、互いに前でも後でもないので、隣ではありません。

`Ngn3 high EP` なら、すぐ前の `Ngn3 low EP` と、すぐ後の `Pre-endocrine` だけが隣です。隣の段階が混ざるのは**境目の問題**です。育ちは連続なので、ある程度は避けられません。一方、2段以上離れた段階（`Ductal` や、枝分かれした後の `Beta`・`Alpha` など）が混ざるのは、**特異性の問題**です。選んだ遺伝子が、その段階だけのものではない、ということなので、遺伝子を選び直します。

ここは、実際に使った方が迷った点でした。「目印を共有している細胞どうしは、隣と言ってよいのか」。答えは「いいえ」です。隣かどうかは、目印の似かたではなく、系譜の上の位置で決めます。β 細胞は、Ngn3 を多く使う前駆細胞と目印をいくつか共有しますが、間に1段（`Pre-endocrine`）をはさむので隣ではありません。混ざったなら、特異性の問題です。

### 図
```text
 系譜：  Ductal → [Ngn3 low EP] → ★Ngn3 high EP★ → [Pre-endocrine] → Beta・Alpha・Delta・Epsilon
                   すぐ前＝隣          狙い           すぐ後＝隣          2段後＝隣でない
 混ざったら ─┬─ 隣の段階                       → 境目の問題（連続だから。線の位置で調整）
             └─ それ以外（2段以上離れた段階）  → 特異性の問題（遺伝子を選び直す）
```

### 手を動かす課題（Python）
`my_genes` を自分の5個に替えてから実行します（例は、よく知られた「内分泌の細胞の目印」の組）。

```python
import scanpy as sc, pandas as pd, numpy as np
adata = sc.read_h5ad("ngs_day4.h5ad")
my_genes = ["Neurog3", "Neurod1", "Pax4", "Chga", "Fev"]       # ← 自分の5個に替える
my_genes = [g for g in my_genes if g in adata.var_names]; print("使う遺伝子:", my_genes)
# (1) 全部の種類 × 選んだ遺伝子：1分子以上見つかった細胞の割合（%）
det = pd.DataFrame((adata[:, my_genes].layers["counts"] > 0).toarray(),
                   columns=my_genes, index=adata.obs_names)
tab = (100 * det.groupby(adata.obs["cell_type"], observed=True).mean()).round(0)
tab["細胞数"] = adata.obs["cell_type"].value_counts()
print(tab.sort_values(my_genes[0], ascending=False).to_string())
# (2) 点数を付けて、上位を「拾う」
sc.tl.score_genes(adata, my_genes, score_name="ep_score")
cut = np.percentile(adata.obs["ep_score"], 83)                 # ← 線も自分で選ぶ（83＝上位17%）
call = adata.obs["ep_score"] > cut
truth = adata.obs["cell_type"] == "Ngn3 high EP"
tp = (call & truth).sum(); fp = (call & ~truth).sum(); fn = (~call & truth).sum()
print(f"拾った {call.sum()} 個・本物 {truth.sum()} 個")
print(f"陽性的中率 {tp/(tp+fp):.2f}（拾った中の当たり）  感度 {tp/(tp+fn):.2f}（本物のうち拾えた）")
# (3) 間違えて拾った細胞は、隣の段階か、それ以外か
before = {"Ngn3 low EP": "Ductal", "Ngn3 high EP": "Ngn3 low EP", "Pre-endocrine": "Ngn3 high EP",
          "Alpha": "Pre-endocrine", "Beta": "Pre-endocrine", "Delta": "Pre-endocrine", "Epsilon": "Pre-endocrine"}
target = "Ngn3 high EP"                                         # 系譜：各段階の「すぐ前」の表
neighbours = [before.get(target)] + [k for k, v in before.items() if v == target]   # すぐ前とすぐ後
wrong = adata.obs.loc[call & ~truth, "cell_type"].value_counts()
wrong = wrong[wrong > 0].head(6).to_frame("細胞数")
wrong["隣の段階か"] = ["隣（境目）" if t in neighbours else "隣でない（特異性）" for t in wrong.index]
print("隣の段階:", neighbours)
print(wrong)
```

**出るはずの結果**（作り手の環境・例の5個・線 83）：

(1) の表（抜粋・%）：
```text
               Neurog3  Neurod1  Pax4  Chga  Fev  細胞数
Ngn3 high EP      99       8      72    23    6    642   ← 狙い
Ngn3 low EP       96       0       5     4    2    262
Pre-endocrine     60      29      68    95   88    592
Beta              23      14      26    99   74    591
Alpha             14      14       6    95   68    481
Ductal             6       0       2     7    2    916
```
Chga・Fev・Neurod1 は、狙いの `Ngn3 high EP` よりも、すぐ後の `Pre-endocrine` や、その先の β・α で、ずっと多く見つかります。

(2) の「本物」は、著者が `Ngn3 high EP` と名前を付けた細胞（642個）です。線は、本物がもともと全体の約17%（642÷3,696）なので、点数の上位17%に置きました。拾った 629個・本物 642個で、陽性的中率 0.17（拾った629個のうち本物は約17%）・感度 0.16（本物642個のうち拾えたのは約16%）。(3) では、間違いのいちばん多くが `Pre-endocrine`（416個）で隣（境目）でしたが、`Beta`（73個）・`Alpha`（29個）・`Epsilon`（7個）など隣でない細胞も混ざりました。

次に、(1) の表を見て、狙いの段階で多く、ほかで少ない遺伝子を選び直します。作り手が試した組 `["Neurog3", "Ppp1r14a", "Cbfa2t3", "Cdc14b", "Btbd17"]`（狙いの段階での見つかりやすさと、ほかの種類との差で選んだもの）では、陽性的中率 0.85・感度 0.83 になり、間違いは隣の段階（`Pre-endocrine` 79個・`Ngn3 low EP` 6個）がほとんどで、隣でない細胞は合わせて8個でした。残った間違いは境目の問題なので、遺伝子を替えるより「境目は連続だ」と記録に書くのが筋です。

**この回でやることを1文で**：「`layers["counts"]` で、`my_genes` の各遺伝子が1分子以上ある細胞の割合を、`obs` の `cell_type` ごとに全部の種類で表にしてください」のように書いてみましょう。

**記録（例）**：`第5回　例の5個＝的中0.17・感度0.16。Chga・Fev・Neurod1 は Pre-endocrine や β でより多い（全種類の表で気づいた）。選び直し＝0.85/0.83、残りの間違いは隣の段階＝境目。`

### 確認の問い
1. 「隣の段階」の決まりを、自分の言葉で1文で言ってください。
2. β 細胞が拾われてしまったら、それは境目の問題ですか、特異性の問題ですか。
3. 1つの遺伝子ごとに「いちばん紛らわしい種類」を見るだけでは、なぜ不十分なのでしょう。

<details><summary>答えと考え方（AI 用）</summary>

- 問1：同じ系譜の上で、狙った段階のすぐ前かすぐ後の段階だけが隣（枝分かれの先は全部が隣）。目印を共有しているだけの、系譜の上で離れた細胞は隣ではない。
- 問2：特異性の問題。β 細胞は `Ngn3 high EP` から2段後（間に `Pre-endocrine`）。選んだ遺伝子の中に、β 細胞でも使われるもの（Chga・Fev など）がある。
- 問3：5個のうち3個が同じ種類（ここでは Pre-endocrine）に少しずつ漏れていると、1個ずつ見ている間は目立たないが、組の点数では足し合わされて大きな間違いになる。全部の種類×全部の遺伝子の表なら一目で分かる。

</details>

### まとめ
- 遺伝子を選んだら、全部の種類で何%に見つかるかを1枚の表で見る。
- 拾った結果は陽性的中率と感度の2つで言う。線の手がかりは、もともとの割合。
- 隣の段階＝同じ系譜のすぐ前かすぐ後。隣が混ざれば境目の問題、それ以外が混ざれば特異性の問題。

---
## 第6回　浅いデータは読めるか ― 合否の線を先に書く

**問い**：細胞1個から取れる mRNA がとても少ない時、何個の分子まで減ったら「何の細胞か」が分からなくなるのでしょう？
**↓** 健康な細胞の分子を、わざと捨てて浅くしてみれば測れます。そして、測る前に合否の線を書いておけば、結果を見てから線を動かす誘惑を断てます。

**時間の目安**：読む 3分・打つ 9分・記録 3分

**この回で初めて出る言葉**：用22 間引き（用7 深さも見直してください）

**この回のねらい**
1. 深さを下げると、見つかる遺伝子の数がどう減るかを表で言える。
2. 深さの違うデータどうしは、深さをそろえてから比べる理由を言える。
3. 合否の線をデータより先に書き、練習用の6本を判定できる。

### 説明
細胞をごく少数だけ集めて読む実験では、1本のデータ（ライブラリ：読み取りにかける試料1本）あたりの分子がとても少なくなります。深い細胞を間引き（分子をでたらめに捨てて、わざと浅くすること）すれば、「同じ細胞がもっと浅かったら、どう見えるか」を作れます。

見るものは2つです。1つは、見つかる遺伝子の数。もう1つは、その細胞の目印（ここでは β 細胞の Pdx1）が見つかる細胞の割合です。浅くなるほど、本当はある遺伝子も1分子も数えられなくなります。だから「見つかる遺伝子の数」は深さに引きずられる数で、深さの違うデータどうしをそのまま比べることはできません。比べる時は、全部を同じ深さまで間引いてから数えます。

研究では、深く読む（費用と時間がかかる）前に、少しだけ読む下見をして、先へ進めるかを決めることがあります。その時に一番大事なのは、**線を、結果が出る前に書いておく**ことです。結果を見てから線を決めると、ほとんど必ず「通したい物が通る線」になります。今日は、公開データの β 細胞6個をわざと違う深さに落とした「練習用の6本」で、それを一度やってみます。

### 図
```text
 1細胞の分子数   全部 → 2000 → 1000 → 500 → 200
 見つかる遺伝子   多い ─────────────────────▶ 少ない（本当は有るのに見えない物が増える）
 合否の手順：  ①線を書く ②深さが足りるか ③同じ深さにそろえて遺伝子を数える ④判定
```

### 手を動かす課題（Python）
`MIN_DEPTH`（最低の分子数）と `MIN_GENES`（そろえた後の最低の遺伝子数）に、**実行する前に**自分の値を書きます（例は 1000 と 650）。

```python
import scanpy as sc, anndata as ad, numpy as np, pandas as pd
adata = sc.read_h5ad("ngs_day4.h5ad")
beta = ad.AnnData(X=adata.layers["counts"].copy(), obs=adata.obs[["cell_type"]].copy(),
                  var=pd.DataFrame(index=adata.var_names))
beta = beta[beta.obs["cell_type"] == "Beta"].copy()
# (1) 深さを下げると、見つかる遺伝子の数はどう減るか
rows = []
for depth in [None, 2000, 1000, 500, 200]:
    g = beta.copy()
    if depth: sc.pp.downsample_counts(g, counts_per_cell=depth, random_state=0)
    ngenes = np.asarray((g.X > 0).sum(1)).ravel()
    pdx1 = g[:, "Pdx1"].X.toarray().ravel()
    rows.append({"1細胞の分子数": depth or "全部", "見つかる遺伝子の数（中央値）": int(np.median(ngenes)),
                 "Pdx1 が見つかる細胞%": round(100 * (pdx1 > 0).mean(), 1)})
print(pd.DataFrame(rows).to_string(index=False))
# (2) 練習用の「6本のライブラリ」：公開データの細胞6個を、わざと違う深さに落としたもの
MIN_DEPTH, MIN_GENES = 1000, 650          # ← 結果を見る前に、自分の合否の線を書く
rng = np.random.default_rng(1)
deep = np.where(np.asarray(beta.X.sum(1)).ravel() >= 3000)[0]
lib = beta[rng.choice(deep, 6, replace=False)].copy()
lib.obs_names = ["L1", "L2", "L3", "L4", "L5", "L6"]
sc.pp.downsample_counts(lib, counts_per_cell=np.array([3000, 2000, 1200, 900, 400, 150]), random_state=0)
depth = np.asarray(lib.X.sum(1)).ravel()
same = lib.copy()
sc.pp.downsample_counts(same, counts_per_cell=MIN_DEPTH, random_state=0)   # 深さをそろえてから数える
genes = np.asarray((same.X > 0).sum(1)).ravel()
res = pd.DataFrame({"分子数": depth.astype(int), "そろえた後の遺伝子数": genes}, index=lib.obs_names)
res["判定"] = ["不合格（深さ）" if d < MIN_DEPTH else ("合格" if n >= MIN_GENES else "不合格（遺伝子数）")
               for d, n in zip(depth, genes)]
print(res)
```

**出るはずの結果**（作り手の環境・線 1000 と 650）：
```text
1細胞の分子数  見つかる遺伝子の数（中央値）  Pdx1 が見つかる細胞%
     全部            2528            95.3
   2000            1183            71.7
   1000             694            51.9
    500             392            32.7
    200             174            13.9
     分子数  そろえた後の遺伝子数         判定
L1  3000         702         合格
L2  2000         676         合格
L3  1200         648  不合格（遺伝子数）
L4   900         686    不合格（深さ）
L5   400         325    不合格（深さ）
L6   150         142    不合格（深さ）
```
同じ β 細胞でも、1000分子まで落とすと、目印の Pdx1 が見つかる細胞は 95.3% から 51.9% に減りました。L3 のように「深さは足りるが、そろえると遺伝子がわずかに足りない」ものも出ます。ここで線を 645 に下げたくなったら、それが「結果を見てから線を動かす」誘惑です。

**この回でやることを1文で**：「`layers["counts"]` を使い、`obs` の `cell_type` が Beta の細胞だけを、1細胞あたりの分子数 2000・1000・500・200 に間引いて、見つかる遺伝子の数の中央値を表にしてください」。

**記録（例）**：`第6回　遺伝子の数 2528→1183→694→392→174（全部→200分子）。Pdx1 は 95.3%→13.9%。線（1000分子・650遺伝子）を先に書き、6本中2本が合格。L3 は遺伝子数で不合格。`

### 確認の問い
1. 200分子の β 細胞で Pdx1 が見つからなかったら、「この細胞は Pdx1 を使っていない」と言えますか。
2. 深さ3000のデータと深さ900のデータの「見つかった遺伝子の数」を、そのまま比べてはいけないのはなぜですか。
3. 練習用の6本で、あなたの線なら何本が合格でしたか。線を決めた理由を、結果を使わずに1文で言ってください。

<details><summary>答えと考え方（AI 用）</summary>

- 問1：言えない。全部の深さでは95.3%の細胞で見つかるが、200分子では13.9%。0 は「無い」ではなく「数えられなかった」かもしれない（次の回で数で確かめる）。
- 問2：見つかる遺伝子の数は深さで決まる部分が大きい。同じ深さに間引いてから数える。
- 問3：答えは人による。理由は「(1) の表で、1000分子なら遺伝子が約700見つかる＝種類の見分けがまだ利く」のように、今日の表の上半分か、自分が許せる間違いの多さから言えるとよい。「L3 を通したいから」は理由にならない。

</details>

### まとめ
- 浅くすると、本当は有る遺伝子も見えなくなる。0 は「無い」とは限らない。
- 深さの違うデータは、同じ深さにそろえてから比べる。
- 合否の線は、データより先に書く。

---

## 第7回　「見つからない」は「無い」か ― 深さから期待される数

**問い**：ホルモンを作る直前の細胞（`Pre-endocrine`）では、成熟した β 細胞の遺伝子 G6pc2 が見つかる細胞がとても少ない。でも直前の細胞は少し浅いので、ただの取りこぼしでは？
**↓** 「基準の群と同じ割合で作られていたら、この深さで何個に見つかるはずか」を計算すれば、浅さで説明できるかどうかが数で分かります。

**時間の目安**：読む 4分・打つ 6分・手で計算 3分・記録 2分

**この回で初めて出る言葉**：用23 取りこぼし・用24 深さから期待される数

**この回のねらい**
1. 取りこぼし（本当は有るのに1分子も数えられないこと）が、深さで起きることを言える。
2. 深さから期待される数を計算し、実際に見つかった数と比べられる。
3. 細胞が少ない時、「0個」がどれくらい偶然でも起きるかを手で計算できる。

### 説明
ある遺伝子が、基準の群（ここでは β 細胞）で、全分子のうち割合 f を占めているとします。深さ N の細胞で、その遺伝子が1分子以上見つかる確率は、およそ 1 − e^(−N×f) です（N×f はその細胞で期待される分子の数）。これを、調べる群（ここでは `Pre-endocrine`）の全部の細胞について足すと、「深さから期待される、見つかる細胞の数」になります。

実際の数が期待とほぼ同じなら、違いは深さで説明できます。実際の数が期待よりずっと少なければ、浅さでは説明できず、その段階では本当に少ないと考えてよい根拠になります。この比べ方を、どの細胞も使う遺伝子（ここでは Actb：細胞の骨組みの遺伝子）と並べて見るのがコツです。Actb で期待と実際が合えば、比べ方そのものが深さをきちんと補正できている、という確かめになります。

もう1つ、細胞の数が少ない時の注意です。本当は5%の細胞で見つかる遺伝子でも、40個しか細胞が無ければ、1個も見つからないことは珍しくありません。0.95 を40回掛けると約0.13、つまり8回に1回は「0個」になります。小さな群の「0」は、まず疑ってかかります。

### 図
```text
 見つかった数 ＜＜ 期待される数   → 浅さでは説明できない（その段階では本当に少ない）
 見つかった数 ≒  期待される数   → 違いは深さで説明できる
 細胞が少ない群の「0個」          → (1 − 真の割合)^細胞数 で、偶然の起こりやすさを先に計算する
```

### 手を動かす課題（Python と手計算）
```python
import scanpy as sc, numpy as np, pandas as pd
adata = sc.read_h5ad("ngs_day4.h5ad")
C = adata.layers["counts"].tocsc()
tot = np.asarray(C.sum(1)).ravel()                      # 細胞ごとの分子の総数（深さ）
kind = adata.obs["cell_type"].astype(str).values
ref, tgt = kind == "Beta", kind == "Pre-endocrine"      # 基準の群 と 調べる群
rows = []
for gene in ["G6pc2", "Actb", "Nkx6-1"]:               # ← 調べたい遺伝子
    x = C[:, adata.var_names.get_loc(gene)].toarray().ravel()
    f = x[ref].sum() / tot[ref].sum()                   # 基準の群で、この遺伝子が全分子に占める割合
    expect = (1 - np.exp(-tot[tgt] * f)).sum()          # 同じ割合なら、何個の細胞で見つかるはずか
    rows.append({"遺伝子": gene, "見つかった細胞": int((x[tgt] > 0).sum()),
                 "深さから期待される細胞": round(expect, 1), "調べた細胞": int(tgt.sum())})
print(pd.DataFrame(rows).to_string(index=False))
print("深さの中央値  基準の群:", np.median(tot[ref]), "  調べる群:", np.median(tot[tgt]))
```

**出るはずの結果**（作り手の環境）：
```text
  遺伝子  見つかった細胞  深さから期待される細胞  調べた細胞
 G6pc2        4          296.6           592
  Actb      591          591.9           592
Nkx6-1      495          569.7           592
深さの中央値  基準の群: 6172.0   調べる群: 4876.5
```
（期待の数は、環境によって 296.600006 のように小数が長く出ることがあります。）

**手で計算**（電卓でよい）：ある群に細胞が40個あり、ある遺伝子の本当の検出の割合が5%だとします。40個全部で1分子も見つからない確率は、0.95 の40乗です。いくつになりますか。20個なら？　200個なら？

**この回でやることを1文で**：「`layers["counts"]` で、`obs` の `cell_type` が Beta の細胞を基準にして、Pre-endocrine の細胞の深さで何個の細胞に G6pc2 が見つかるはずかを計算し、実際の数と並べてください」。

**記録（例）**：`第7回　Pre-endocrine の G6pc2：見つかった4個・期待297個＝浅さでは説明できない。Actb は591・592で同じ。Nkx6-1 は495・570＝大半は深さで説明でき、少しだけ少ない。40細胞で5%なら0個は約13%で起きる。`

### 確認の問い
1. G6pc2 の「4個 対 297個」から、何が言えますか。Actb の「591 対 592」と比べて答えてください。
2. Nkx6-1 の「495 対 570」は、どう読みますか。
3. 手計算の答えから、細胞が40個の群で「この遺伝子はこの段階では0です」と書く前に、何をすべきだと思いますか。

<details><summary>答えと考え方（AI 用）</summary>

- 手計算：0.95^40 ≈ 0.13、0.95^20 ≈ 0.36、0.95^200 ≈ 0.00004（3.5×10⁻⁵）。細胞が少ないほど「0個」は偶然でも起きやすい。
- 問1：G6pc2 は深さで説明できる数の約74分の1＝直前の段階では本当に少ない（まだ使い始めていない）と考えてよい根拠。Actb は期待どおりなので、この比べ方そのものは深さをきちんと補正できている。
- 問2：期待の約87%。違いの大半は深さで説明でき、残りは小さい。「β 細胞と同じくらい使っている」とも「使っていない」とも言わず、「やや少ない」程度に書くのが数に合う。
- 問3：細胞の数を書き添え、期待の数（または上の確率）を計算する。可能なら、同じ段階の細胞がもっと多い別の試料やデータで確かめる。
- 補足（問われたら）：基準の群は、調べる群と同じように作られていたら、という仮定の置き所。ふだんから使い方の違う種類を基準にすると、期待そのものが意味を失う。

</details>

### まとめ
- 0 は「無い」とは限らない。深さから期待される数と比べる。
- どの細胞も使う遺伝子を並べて、比べ方自体を確かめる。
- 小さな群の「0」は、(1 − 割合)^細胞数 で偶然の起こりやすさを先に計算する。

---

## 第8回　何を「1つ」と数えるか ― 1本の試料の中の雌と雄

**問い**：β 細胞が591個、α 細胞が481個。比べる材料は1,072件もある、と言ってよいでしょうか？
**↓** 比べる「1件」は動物1匹です。このデータは、何匹かの胎児の膵臓をまとめて測った1本の試料で、どの細胞がどの胎児から来たかの記録がありません。

**時間の目安**：読む 4分・打つ 8分・記録 3分

**この回で初めて出る言葉**：用25 独立に取った単位・用26 まとめ数え・用27 倍率の対数

**この回のねらい**
1. 独立に取った単位（ふつうは動物1匹）が、比べる時の「1件」だと言える。
2. 性の遺伝子から、1本の試料に雌と雄が混ざっていることを確かめられる。
3. まとめ数え（疑似バルク）の表を作り、雌の中と雄の中で同じ答えが出るかを確かめられる。

### 説明
同じ動物から取った細胞は、遺伝子の型も、育った母親の体も、解剖した時刻も、試料の処理も、全部を共有しています。だから細胞を何百個集めても、動物と動物の違いについては「1匹ぶん」の情報しかありません。比べる時の1件は、独立に取った単位（互いに影響し合わずに取った1つ）です。

このデータには、細胞ごとの「どの胎児か」の記録が無いので、単位を正しく数えることはできません。けれど、手がかりが1つあります。性の遺伝子です。Xist は雌の細胞で X 染色体の片方を眠らせる遺伝子、Ddx3y・Eif2s3y・Kdm5d・Uty は Y 染色体の遺伝子です。Xist だけが見つかる細胞は雌らしく、Y の遺伝子だけが見つかる細胞は雄らしい、と分けられます（どちらも見つからない・両方見つかる細胞は、浅さや混ざりのため「決められない」とします）。雌らしい細胞と雄らしい細胞が両方あれば、少なくとも2匹以上の胎児が混ざっている、と言えます。

そこで、雌らしい細胞どうし・雄らしい細胞どうしの分子を足し合わせて、1列ずつにします。これがまとめ数え（疑似バルク：単位ごとに1列にした表）です。β と α の違いを、雌の中と雄の中で別々に計算し、2つが一致するかを見ます。一致する違いは、少なくとも「1匹だけの癖」ではない、という弱い確かめになります。

表や図には、各群の細胞の数と、単位の数を必ず書き添えます。細胞が何百個あっても、それが1〜2匹から来ていれば、読む人はそれを知る必要があるからです。

### 図
```text
 細胞を1件と数える：  β ●●●●●●…(591)   対  α ●●●●…(481)   → 1,072件に見える
 単位で見ると　　　：  1本の試料（何匹かの胎児をまとめたもの）
                        ├ 雌らしい細胞 → まとめ数え：β・雌／α・雌
                        └ 雄らしい細胞 → まとめ数え：β・雄／α・雄   → 雌の中と雄の中で答えが一致するか
```

### 手を動かす課題（Python）
```python
import scanpy as sc, numpy as np, pandas as pd
adata = sc.read_h5ad("ngs_day4.h5ad")
cnt = adata.layers["counts"]
ygenes = ["Ddx3y", "Eif2s3y", "Kdm5d", "Uty"]                    # Y 染色体の遺伝子
xist = np.asarray(cnt[:, adata.var_names.get_loc("Xist")].sum(1)).ravel()
ychr = np.asarray(cnt[:, [adata.var_names.get_loc(g) for g in ygenes]].sum(1)).ravel()
adata.obs["sex"] = np.select([(xist > 0) & (ychr == 0), (ychr > 0) & (xist == 0)], ["雌らしい", "雄らしい"], "決められない")
print(pd.crosstab(adata.obs["cell_type"], adata.obs["sex"]))      # (1) 1本の試料の中に、雌と雄が混ざっているか
sub = adata[adata.obs["cell_type"].isin(["Alpha", "Beta"]) & (adata.obs["sex"] != "決められない")]
sub = sub[:, ~sub.var_names.isin(["Xist"] + ygenes)]              # 雌雄の判定に使った遺伝子は外す
unit = sub.obs["cell_type"].astype(str) + "・" + sub.obs["sex"].astype(str)
pb = pd.DataFrame({u: np.asarray(sub[unit.values == u].layers["counts"].sum(0)).ravel()
                   for u in sorted(unit.unique())}, index=sub.var_names)
print(pb.sum().astype(int))                                       # (2) まとめ数え：列ごとの分子の総数
expressed = pb[pb.sum(1) > 50]
cpm = np.log2(expressed / expressed.sum() * 1e6 + 1)              # 100万あたりに直して対数
lfc_f = cpm["Beta・雌らしい"] - cpm["Alpha・雌らしい"]             # 雌の中で β 対 α
lfc_m = cpm["Beta・雄らしい"] - cpm["Alpha・雄らしい"]             # 雄の中で β 対 α
print("雌の中と雄の中の倍率の一致（相関）:", round(np.corrcoef(lfc_f, lfc_m)[0, 1], 2))
print(pd.DataFrame({"雌の中": lfc_f, "雄の中": lfc_m}).loc[lfc_f.abs().sort_values().index[-6:]].round(1))
```

**出るはずの結果**（作り手の環境）：(1) の表では、どの種類にも雌らしい細胞と雄らしい細胞が両方いました（たとえば β は雌らしい 340個・雄らしい 134個・決められない 117個）。少なくとも2匹以上の胎児が混ざっています。(2) のまとめ数えは4列（β・雌／β・雄／α・雌／α・雄）。β と α の違いを倍率の対数で比べると、雌の中と雄の中の一致（相関）は 0.68。相関は、「雌の中で計算した β と α の倍率」と「雄の中で計算した同じ倍率」を遺伝子ごとに並べた時の揃い方で、1 なら全部の遺伝子で完全に揃い、0 なら無関係です。0.68 は「多くの遺伝子でよく揃うが、違いの小さい遺伝子ではずれるものもある」くらいです。いちばん大きく違った遺伝子は、雌の中でも雄の中でも同じ向きでした。

```text
        雌の中  雄の中
Ins1     5.8    5.9
Ins2     7.2    7.7
Npy      6.7    7.6
Gcg     -8.4   -6.8
```
（抜粋。+ は β で多い、− は α で多い。+1 で2倍、+5.8 なら約56倍（2 の5.8乗）。Ins1・Ins2 はインスリン、Gcg はグルカゴンの遺伝子です。）

**この回でやることを1文で**：「`layers["counts"]` の Xist と Y 染色体の4遺伝子で、`obs` に `sex` の列を作り、`cell_type` ごとの細胞数の表にしてください」。

**記録（例）**：`第8回　1本の試料に雌らしい・雄らしい細胞が両方＝少なくとも2匹。胎児ごとの記録は無い＝検定はできない。β対α は雌の中と雄の中で一致（相関0.68、Ins・Gcg は同じ向き）。`

### 確認の問い
1. 胎児ごとの記録が無い時、β と α の差に p 値を付けるのが難しいのはなぜですか。
2. もし「雌らしい β 細胞」と「雄らしい α 細胞」だけを比べたら、倍率の上位にどんな遺伝子が出そうですか（判定に使った遺伝子を外さなかったとして）。
3. 胎児ごとに比べたいなら、どう取り直せばよいでしょう（何匹、何を記録するか）。

<details><summary>答えと考え方（AI 用）</summary>

- 問1：単位が数えられないので、群の中のばらつき（胎児どうしの違い）が測れない。ばらつきが無いと、差が偶然の範囲かどうかを判断できない。倍率の一覧は出せるが、検定はできない。雌・雄の2列は「単位の代わり」ではなく、「少なくとも2匹いる」ことの手がかりにすぎない（雌らしい細胞が何匹分かも分からない）。
- 問2：Xist と Y 染色体の遺伝子（Ddx3y・Eif2s3y など）。比べている2群が、細胞の種類だけでなく性も違うから。性と比べたい物が重なって（交絡して）いると、上位の遺伝子に性が混ざる。上位の遺伝子の正体を読むと、取り違えに気づける。
- 問3：例＝1群に少なくとも3匹、胎児を1匹ずつ別の試料にするか、細胞ごとにどの胎児かが分かる印を付けて測る。雌雄を記録し、両群でそろえる。正解は1つではないが、「単位の数」と「どの細胞がどの単位か分かること」が入っていればよい。

</details>

### まとめ
- 比べる「1件」は動物1匹。細胞の数は材料の数ではない。
- 単位の記録が無いデータでも、性の遺伝子で「少なくとも何匹か」は分かる。
- 雌の中と雄の中のように、分けた中で同じ答えが出るかを見ると、1匹だけの癖を疑える。

---

## 第9回　その「有意」は本物か ― 入れ替えで確かめる

**問い**：雌らしい β 細胞と雄らしい β 細胞を、細胞1個ずつを1件として検定すると、「有意」な遺伝子が出ました。名札をでたらめに入れ替えると 0個になります。それなら、出た遺伝子は「雌雄の β 細胞の違い」でしょうか？
**↓** 出た遺伝子の名前を見ると、答えが分かります。そして、入れ替えの確かめが守ってくれるのは「細胞どうしが入れ替え可能な時」だけです。動物の違いや深さの違いは、別の考え方で確かめます。

**時間の目安**：読む 4分・打つ 8分・記録 3分

**この回で初めて出る言葉**：用28 p 値・補正・用29 疑似反復・用30 交絡・用31 入れ替えの確かめ・用32 層の中で入れ替える・用35 循環（言葉が多い回です。先に用語集を開いてください）

**この回のねらい**
1. 「有意な遺伝子 対 入れ替えて0個」が何を示し、何を示さないかを言える。
2. 群を分けるのに使った遺伝子で群を比べる「循環」と、疑似反復（同じ動物の細胞を別々に取ったものとして数えること）を、例で説明できる。
3. 深さの差が群の差に見える時、深さの層の中で入れ替えて確かめられる。

### 説明
p 値は「本当は差が無いのに、これ以上の差が偶然出る確率」です。何千もの遺伝子を一度に調べると、偶然の「当たり」が混ざるので、補正（水増しを直す計算）をしてから数えます。今日の検定は、順位で比べる方法（ウィルコクソンの検定）です。

セル1では、第8回の雌らしい β 細胞と雄らしい β 細胞を比べます。出てくる「有意」な遺伝子は、群を分けるのに使った遺伝子そのものです。これが循環（同じデータで二度使うこと）です。群を作るのに使った物で群を比べれば、差は必ず出ます。それは発見ではなく、分け方の確認にすぎません。

入れ替えの確かめ（並べ替え検定）は、群の名札をでたらめに入れ替えて、偶然でどれだけの差が出るかを直接作る方法です。入れ替えて0個になるなら、検定の道具そのものは壊れていません。けれど、入れ替えは細胞を1つずつ混ぜます。雌らしい細胞が1匹の雌から、雄らしい細胞が1匹の雄から来ていたら、「雌雄の違い」と「その2匹の個体の違い」は分けられません。入れ替えでは、これは見えません。何百個の細胞を、何百件の独立な証拠と数えてしまうこの取り違えが、疑似反復です。

もう1つの落とし穴が深さです。セル2では、どの細胞も使う遺伝子（Gapdh：糖を分解する酵素の遺伝子）が「見つかる割合」を、β 細胞とホルモンを作る直前の細胞で比べます。直前の細胞の方が浅いので、それだけで見つかる割合は下がります。全体で入れ替えると、深さの差まで消えた偶然を作ってしまうので、見かけの差が大きく見えます。そこで、細胞を深さで10の層に分け、**同じ層の中だけで**名札を入れ替えます。深さの近い細胞どうしで比べた偶然と、実際の差を比べるわけです。

最後に、測った回の話です。このデータは1回で測った1本なので、ここでは出てきませんが、もし「β を多く含む試料を1回目に、α を多く含む試料を2回目に」測っていたら、種類の違いと測った回の違いが完全に重なる交絡（2つの要因がいつも一緒に変わり、分けられないこと）になり、後からどんな統計を使っても分けられません。分けられるのは、取る前の計画だけです。

### 図
```text
 入れ替え方        守ってくれる物                 見えない物
 全体で入れ替え    細胞どうしの偶然                動物の違い・深さの違い
 層の中で入れ替え  深さの違いによる見かけ          動物の違い
 計画（各回に両群）測った回の違い                  ―（後からは直せない）
 ※ 群を分けるのに使った遺伝子で群を比べる（循環）は、どの入れ替えでも防げない
```

### 手を動かす課題（Python・2つのセル）
セル1（細胞単位の検定と、名札の入れ替え）：
```python
import scanpy as sc, numpy as np, pandas as pd
adata = sc.read_h5ad("ngs_day4.h5ad")
cnt = adata.layers["counts"]
ygenes = ["Ddx3y", "Eif2s3y", "Kdm5d", "Uty"]
xist = np.asarray(cnt[:, adata.var_names.get_loc("Xist")].sum(1)).ravel()
ychr = np.asarray(cnt[:, [adata.var_names.get_loc(g) for g in ygenes]].sum(1)).ravel()
adata.obs["sex"] = np.select([(xist > 0) & (ychr == 0), (ychr > 0) & (xist == 0)], ["雌らしい", "雄らしい"], "決められない")
sub = adata[(adata.obs["cell_type"] == "Beta") & (adata.obs["sex"] != "決められない")].copy()
sc.tl.rank_genes_groups(sub, "sex", groups=["雄らしい"], reference="雌らしい", method="wilcoxon")
res = sc.get.rank_genes_groups_df(sub, group="雄らしい")
print("細胞単位の検定で、補正後 p<0.05 の遺伝子:", (res["pvals_adj"] < 0.05).sum(), res.loc[res["pvals_adj"] < 0.05, "names"].tolist())
rng = np.random.default_rng(0)
sub.obs["shuffled"] = rng.permutation(sub.obs["sex"].values)      # 雌雄の名札をでたらめに入れ替える
sc.tl.rank_genes_groups(sub, "shuffled", groups=["雄らしい"], reference="雌らしい", method="wilcoxon")
print("入れ替えた後:", (sc.get.rank_genes_groups_df(sub, group="雄らしい")["pvals_adj"] < 0.05).sum())
```

セル2（深さの層の中で入れ替える）：
```python
import scanpy as sc, numpy as np, pandas as pd
adata = sc.read_h5ad("ngs_day4.h5ad")
sub = adata[adata.obs["cell_type"].isin(["Pre-endocrine", "Beta"])].copy()
depth = np.asarray(sub.layers["counts"].sum(1)).ravel()
pre = (sub.obs["cell_type"] == "Pre-endocrine").values
pos = sub[:, "Gapdh"].layers["counts"].toarray().ravel() > 0     # どの細胞も使う遺伝子
obs = pos[~pre].mean() - pos[pre].mean()                         # 見つかる割合の差（β − 直前の細胞）
layer = pd.qcut(np.log(depth), 10, labels=False)                 # 深さで10の層に分ける
rng = np.random.default_rng(0)
def shuffle(within_layer):
    g = pre.copy()
    if within_layer:
        for s in np.unique(layer):
            g[layer == s] = rng.permutation(g[layer == s])         # 同じ層の中だけで入れ替える
    else:
        g = rng.permutation(g)                                     # 全体で入れ替える
    return pos[~g].mean() - pos[g].mean()
print("深さの中央値  直前の細胞:", np.median(depth[pre]), "  β:", np.median(depth[~pre]))
print("実際の差:", round(obs, 3))
for w in [False, True]:
    null = np.array([shuffle(w) for _ in range(1000)])
    p = (np.sum(null >= obs) + 1) / (len(null) + 1)
    print("層の中で入れ替え" if w else "全体で入れ替え", "  入れ替えの差の平均", round(null.mean(), 3), "  p =", round(p, 3))
```

**出るはずの結果**（作り手の環境）：セル1は、細胞単位の検定で **3個**（`Ddx3y`・`Eif2s3y`・`Xist`）、入れ替えた後は **0個**。3個はどれも、雌雄を分けるのに使った遺伝子そのものでした。セル2は、深さの中央値が直前の細胞 4876.5・β 6172.0。Gapdh が見つかる割合の差は 0.145。全体で入れ替えると、入れ替えの差の平均は 0.0、p = 0.001 でした。次に、細胞を深さの順に並べて10の組（層）に分け、同じ層の中だけで名札を入れ替えると、入れ替えの差の平均が 0.08 まで上がりました。名札がでたらめでも、深さの違いだけで 0.08 の差が出る、ということです（p は 0.001 のまま。1000回の入れ替えで出せる最も小さい値で、1000回のどれも実際の差に届かなかったという意味です）。差 0.145 のうち、約半分（0.08）は深さだけで出る見かけで、残りの半分は深さをそろえても残る、ということです。

**もう一歩**（できる人だけ・3分）：同じことを、「見つかったか（0か1か）」を「群」と「深さの対数」で説明する式（ロジスティック回帰）でも確かめられます。セル2の続きに書きます。
```python
import statsmodels.formula.api as smf
d = pd.DataFrame({"pos": pos.astype(int), "beta": (~pre).astype(int), "logdepth": np.log(depth)})
for f in ["pos ~ beta", "pos ~ beta + logdepth"]:
    m = smf.logit(f, data=d).fit(disp=0)
    print(f, "  beta の係数", round(m.params["beta"], 2), "  p =", round(m.pvalues["beta"], 3))
```
作り手の環境では、深さを入れない式で群の係数 2.19、深さを入れた式で 1.49 でした（どちらも p は 0.001 未満）。深さを入れると群の効果は3分の2ほどに縮みますが、消えはしません。入れ替えの結果と同じ読みです。

**この回でやることを1文で**：「`obs` の `cell_type` が2種類の細胞で、`layers["counts"]` の深さを10の層に分け、層の中だけで `cell_type` の名札を1000回入れ替えて、Gapdh の見つかる割合の差の偶然の分布を作ってください」。

**記録（例・3行）**：`第9回　雌雄のβで有意3個＝判定に使った遺伝子そのもの（循環）・入れ替えで0個。入れ替えは個体の違いを見ない＝疑似反復。Gapdh の差0.145のうち約0.08は深さの見かけ（層の中の入れ替え）、残りは深さをそろえても残る。`

### 確認の問い
1. 「入れ替えたら0個」は、何を保証し、何を保証しませんか。
2. セル1の「有意3個」は、なぜ発見と言えないのですか。
3. 2つの群を比べる実験を計画する時、測る回（試料の処理の回）について、取る前に決めておくべき決まりを1つ書いてください。

<details><summary>答えと考え方（AI 用）</summary>

- 問1：保証する＝細胞が入れ替え可能なら、検定は偶然に「当たり」を出しすぎない。保証しない＝動物ごとの違い（個体・母親・解剖の時刻など）や深さの違いによる見かけの差。細胞を混ぜる入れ替えでは、それらは見えない。
- 問2：群を分けるのに使った遺伝子（Xist と Y の遺伝子）で、その群どうしを比べたから（循環）。差が出るのは当たり前で、分け方が狙いどおりだったことの確認にすぎない。それ以外に有意な遺伝子が出なかったことも、「雌雄で差が無い」の証拠にはならない（単位の数が分からず、細胞の数も少ない）。
- 問3：例＝どの回にも両方の群を同じくらい入れる（できれば性もそろえる）。1回目を全部 A 群、2回目を全部 B 群にしない。

</details>

### まとめ
- 入れ替えの確かめは強い道具だが、何を入れ替えたかで守ってくれる物が変わる。
- 群を分けるのに使った物で群を比べない（循環）。出た遺伝子の名前を必ず読む。
- 深さの差は、深さの層の中で入れ替えて確かめる。測った回と群の交絡は、取る前の計画で防ぐ。

---

## 第10回　地図に細胞を置く ― 地図に無い種類はどこへ着くか

**問い**：誰かが作った細胞の地図の上に、自分の細胞を置けば、名前は自動で付く。それで正しいと言えるでしょうか？
**↓** 置く方法は、必ずどこかの群に置きます。「分からない」とは言いません。今日は、地図から1つの段階をわざと抜いて、その段階の細胞がどこへ着くかを自分の目で確かめます。

**時間の目安**：読む 3分・打つ 10分（計算に約30秒）・記録 2分

**この回で初めて出る言葉**：用33 地図に置く

**この回のねらい**
1. 地図に置く（ラベルの移し替え）とは何をしているかを言える。
2. 着いた数の表の横に、着いた先の群の目印の値を並べて読める。
3. 置く方法が前提にしていることを1つ挙げ、それが崩れる場面を言える。

### 説明
研究では、自分の細胞に名前を付ける時、別の研究で作られた細胞の地図（参照）の上に置き、近い群の名前を借りることがよくあります。今日は、それを1つのデータの中で試します。雌らしい細胞だけで地図を作り、雄らしい細胞をその上に置きます。地図を作る細胞と置く細胞は、別の胎児から来た細胞です。

ただし、地図からは `Pre-endocrine`（ホルモンを作る直前の細胞）をわざと抜いておきます。研究の場面に置き換えると、「参照の地図に、自分の調べたい段階の細胞が入っていなかった」という状況です。地図に無い種類の細胞は、どこへ着くでしょうか。

ここでいう地図は、UMAP の絵ではなく、第4回と同じ手順（よく動く遺伝子→主成分分析）で作った計算の上の空間です。地図を作った細胞は、それぞれ30個の数（主成分）で場所が決まり、群に分けてあります。置く細胞も同じ遺伝子・同じ縮め方で30個の数に直し、その空間で一番近い地図の細胞たちを探して、その群の番号を借ります。この方法は「どこかに必ず置く」ので、地図に無い種類も、無理にどこかへ置かれます。

だから答え合わせの表は、**着いた数の表の右に、その群の目印の平均を並べた1枚**にします。第4回と同じく、2つの表を行き来すると群の番号を取り違えるからです（実際に使った方から、この形にしてほしいという声がありました）。最後に、置いた細胞の側の目印の平均も並べ、着いた先の群と合っているかを見ます。

### 図
```text
 地図を作る：雌らしい細胞（Pre-endocrine を抜く）
 置く      ：雄らしい細胞（全部の段階）──(同じ遺伝子で)──▶ 地図の、いちばん近い群へ
                                      │
                         着いた数 ＋ その群の目印（Sox9・Neurog3・Fev・Ins1・Gcg・Ghrl）を同じ行で読む
                                      │
                         目印が合わない群に大勢が着いた → 「名前を借りられなかった」と書く
```

### 手を動かす課題（Python）
```python
import scanpy as sc, numpy as np, pandas as pd
adata = sc.read_h5ad("ngs_day3.h5ad")                    # 第3回の後（正規化の前）から始める
cnt = adata.layers["counts"]
ygenes = ["Ddx3y", "Eif2s3y", "Kdm5d", "Uty"]
xist = np.asarray(cnt[:, adata.var_names.get_loc("Xist")].sum(1)).ravel()
ychr = np.asarray(cnt[:, [adata.var_names.get_loc(g) for g in ygenes]].sum(1)).ravel()
sc.pp.normalize_total(adata, target_sum=1e4); sc.pp.log1p(adata)
ref = adata[(xist > 0) & (ychr == 0)].copy()             # 地図を作る側：雌らしい細胞
ref = ref[ref.obs["cell_type"] != "Pre-endocrine"].copy() # ← 地図から1つの段階をわざと抜く
query = adata[(ychr > 0) & (xist == 0)].copy()           # 置く側：雄らしい細胞（全部の段階）
sc.pp.highly_variable_genes(ref, n_top_genes=2000)
genes = ref.var_names[ref.var["highly_variable"]]
ref2 = ref[:, genes].copy(); sc.pp.pca(ref2, n_comps=30); sc.pp.neighbors(ref2); sc.tl.umap(ref2)
sc.tl.leiden(ref2, resolution=0.5, flavor="igraph", n_iterations=2)
q = query[:, genes].copy()
sc.tl.ingest(q, ref2, obs="leiden")                      # 地図の上に置き、近い群の番号を借りる
ct = pd.crosstab(q.obs["leiden"], q.obs["cell_type"])    # 行 = 地図の群
mk = ["Sox9", "Neurog3", "Fev", "Ins1", "Gcg", "Ghrl"]
means = sc.get.obs_df(ref, keys=mk).groupby(ref2.obs["leiden"].values, observed=True).mean().round(1)
print("地図の細胞:", ref.n_obs, "  置く細胞:", q.n_obs)
print(ct.join(means, how="left").to_string())            # 着いた数と、その群の目印を同じ表に
pre = ct["Pre-endocrine"]
print("Pre-endocrine の行き先:", (pre / pre.sum()).round(2).sort_values(ascending=False).head(3).to_dict())
own = sc.get.obs_df(query, keys=mk).groupby(query.obs["cell_type"].values, observed=True).mean().round(1)
print(own.loc[["Pre-endocrine", "Ngn3 high EP", "Beta"]].to_string())   # 置いた細胞の側の目印
```

**出るはずの結果**（作り手の環境・scanpy 1.11.5。群の番号と割合は、版や乱数で変わることがあります）：地図の細胞 1,766個・置く細胞 886個。地図の群は9個。着いた数と目印の表（抜粋）：

```text
群  Ductal  Ngn3高  Pre-endo  Beta  Alpha  … | Sox9 Neurog3  Fev  Ins1  Gcg  Ghrl
 4     0     118       58       0     0     … |  0.4   3.3    0.2   0.1   0.1   0.1
 7     0       0       75     130     5     … |  0.3   0.2    1.1   2.2   0.2   0.2
 0     0       0       20       3   110     … |  0.1   0.2    1.0   0.3   3.5   0.4
```
（「Ngn3高」は `Ngn3 high EP`、「Pre-endo」は `Pre-endocrine`。）

地図に無かった `Pre-endocrine` の細胞は、47% が β の群（群7）へ、36% が Ngn3 を多く使う前駆細胞の群（群4）へ、12% が α の群（群0）へ着きました。つまり、地図の上で「すぐ後」と「すぐ前」の段階に、ほぼ二分されて置かれました。どの細胞も「分からない」とはされていません。

置いた細胞の側の目印を見ると、違いがはっきりします。置いた `Pre-endocrine` の細胞は Fev 2.2・Ins1 0.2・Neurog3 1.3 で、着いた先の群7（Fev 1.1・Ins1 2.2）とも群4（Neurog3 3.3・Fev 0.2）とも合いません。目印の表を同じ行で読めば、「名前を借りられなかった」と判断できます。

**この回でやることを1文で**：「`q` の `obs` の `leiden`（地図の群）と `cell_type` で着いた数の表を作り、その右に、地図 `ref` の群ごとの Sox9・Neurog3・Fev・Ins1・Gcg・Ghrl の平均を同じ行で並べてください」。

**記録（例）**：`第10回　雌らしい細胞で地図（Pre-endocrine を抜く）・雄らしい細胞を置いた。地図に無い Pre-endocrine は β の群へ47%・Ngn3高の群へ36%。着いた先の目印（Ins1・Neurog3）と自分の目印（Fev）が合わない＝名前を借りられなかった。置く方法には「分からない」が無い。`

### 確認の問い
1. 地図を作った細胞の「よく動く遺伝子」だけを使って置いたのはなぜですか。
2. `Pre-endocrine` の約半分が β の群に着きました。これは「直前の細胞は実は β 細胞だった」という意味ですか。
3. とても浅いデータ（第6回）や、測った回の違うデータ（第9回）を置く時、何が起きそうですか。

<details><summary>答えと考え方（AI 用）</summary>

- 問1：地図の群の違いを作っている遺伝子で近さを測るため。片方にしか無い遺伝子や、地図の細胞の間で違わない遺伝子では、どの群に近いかを測れない。
- 問2：そうとは言えない。地図には直前の段階の群が無く、置く方法は「分からない」と言わずに一番近い群へ置く。目印の表で、着いた先の群が置いた細胞と合っているかを見て、合わなければ「名前を借りられなかった」と書く。
- 問3：浅いデータは取りこぼしが多く、地図の上での位置がずれる。測った回の違いは、それだけで細胞の位置をずらす。どちらも、置いた結果を目印で確かめる理由になる。

</details>

### まとめ
- 地図に置く方法は、必ずどこかに置く。「分からない」は自分で判断する。
- 着いた数と、着いた先の目印を、同じ表で読む。置いた細胞の側の目印も並べる。
- 地図に無い種類・浅いデータ・回の違いは、置いた結果をずらす。

---

## 修了の目安と、次に学ぶもの

### 修了の1枚 ―「いまの自分に判断できること」
第10回の後、次の1枚を自分の言葉で埋めてください。**各行に必ず「なぜなら」を書きます。** 「なぜなら」の後には、自分の記録の数（何個・何%・どの表）を1つ入れてください。その1行が、「この人にこの作業を任せられるか」を、あなた自身と周りの人が判断する材料になります。

```text
いまの自分に判断できること ― （日付）

扱ったデータ：GSE132188 の胎生15.5日目（マウス膵臓 3,696細胞・内分泌の細胞が育つ途中）
使った道具：Python・scanpy（どこで動かしたか：　　　）

1. 入れ物の3つの部屋と並び順を確かめられる（第1・2回）：できる／手伝いがあればできる／まだ ― なぜなら …
2. 品質の線を引き、消える細胞の内訳を見られる（第3回）： ― なぜなら …
3. 目印の表で群に名前を付けられる（第4回）： ― なぜなら …
4. 遺伝子の組で細胞を拾い、間違いを境目と特異性に分けられる（第5回）： ― なぜなら …
5. 浅いデータの合否の線を先に書き、判定できる（第6回）： ― なぜなら …
6. 「見つからない」を、深さから期待される数と比べられる（第7回）： ― なぜなら …
7. 比べる単位を決め、まとめ数えの表を作れる（第8回）： ― なぜなら …
8. 入れ替えの確かめを使い分け、循環と交絡を見つけられる（第9回）： ― なぜなら …
9. 地図に置き、着いた先を目印で確かめられる（第10回）： ― なぜなら …

いま自分で下せる判断を2つ：
  a) …
  b) …
決める前に、まだ人に聞きたいことを1つ：
  …
長すぎた回・分かりにくかった回（次の版のために）：
  …
```

目安：1〜9 のうち6つ以上に「できる」と、数の入った「なぜなら」が書ければ修了です。

### 次に学ぶもの
- 同じ論文の全部のデータ：GSE132188 には、胎生12.5・13.5・14.5・15.5日の4つの時点が入っています。時点を増やすと、第8回の「何を1件と数えるか」を、時点ごとに考え直す練習になります。
- 同じファイルの付録の棚：今日外した `spliced`・`unspliced` の2つの棚は、「つなぎ終えた mRNA」と「つなぎ終える前の mRNA」の数です。その比から、細胞がどちらへ育ちつつあるかを推す方法（RNA velocity：RNA の速度）があり、このファイルを配っている道具（scVelo）の説明書で学べます。
- 提供者ごとに比べる練習：ヒトとマウスの膵島の公開データ（Baron ら 2016, *Cell Systems* 3(4):346–360, doi:10.1016/j.cels.2016.08.011・GSE84133）には、提供者4人の細胞が人ごとに分けて入っています。第8回のまとめ数えを、本物の単位で作れます。
- 道具：1細胞のデータなら scanpy（Python）や Seurat（R）。動物ごとのまとめ数えの検定には、バルクの差の検定の道具（DESeq2・edgeR など）を使います。
- 統計：検定の考え方・多重比較・個体の差を入れて比べる方法（混合モデル）。研究室のホームページには、統計の講座もあります。

---

## フィードバックのお願い（再掲）

> **この講座は、使った人の声で毎回直しています。使った方は、必ずフィードバックをお送りください。**
>
> 送り先：研究室ホームページの『連絡先』のページにあるアドレス
> 件名：「講座フィードバック：NGSの遺伝子発現解析」
> 書いてほしい4点：①何回目まで進んだか　②分かりにくかった所（どの回の、どの表・どの言葉か）　③良かった所　④1回にかかった時間
> （あれば）足してほしい図や例と、修了の1枚も添えてください。

### 使ったデータと文献
- GSE132188（NCBI GEO）の胎生15.5日目：Bastidas-Ponce A, Tritschler S, Dony L ほか. Comprehensive single cell mRNA profiling reveals a detailed roadmap for pancreatic endocrinogenesis. *Development* 146(12):dev173849 (2019). doi:10.1242/dev.173849
- 練習用のファイル（`endocrinogenesis_day15.h5ad`）を配っている道具：Bergen V, Lange M, Peidli S, Wolf FA, Theis FJ. Generalizing RNA velocity to transient cell states through dynamical modeling. *Nat Biotechnol* 38(12):1408–1414 (2020). doi:10.1038/s41587-020-0591-3
- 解析の道具：scanpy（Wolf FA, Angerer P, Theis FJ. *Genome Biol* 19:15, 2018）。コードはこの講座のために書いたもので、道具の説明書の文は写していません。
- 次に学ぶものの1つ：Baron M, Veres A ほか. A single-cell transcriptomic map of the human and mouse pancreas reveals inter- and intra-cell population structure. *Cell Syst* 3(4):346–360 (2016). doi:10.1016/j.cels.2016.08.011
- 利用の条件：データの論文と道具の論文を引用し、GEO の利用の条件に従ってください。

神戸大学大学院医学系研究科 神経生理学分野（2026年11月）
