---
title: "[第27回](https://www.iu.a.u-tokyo.ac.jp/kadota/r_seq2.html#book_JSLAB_27)のウェブ資料"
date: '最終更新: `r format(Sys.Date(), "%Y/%m/%d")`'
output: 
  html_document:
    toc: TRUE
    toc_float: TRUE
    code_download: TRUE
---
```{r klippy, echo=FALSE, include=TRUE}
klippy::klippy()
```

# W1 はじめに
　[連載第26回のウェブ資料](https://www.iu.a.u-tokyo.ac.jp/kadota/book/JSLAB26.html)を一通りやられている方は、[caret](https://cran.r-project.org/package=caret)パッケージのインストールを追加で行うだけで構いません。今回（第27回）のみやられるかたは、順番通りに行ってください。

## W1.1 事前準備1
　このページは、[データ解析環境R](https://www.r-project.org/)を用いた作図実習を含みます。**実習に取り組みたい方**は、[こちらのリンク先](https://www.iu.a.u-tokyo.ac.jp/textbook/appendix.html)の「R1.010 R本体とRStudioとパッケージのインストール」および「R1.020 RStudioの基本的な利用法」を一通り行っておいて下さい。以下は、[リンク先](https://www.iu.a.u-tokyo.ac.jp/textbook/appendix.html)のスクショです。①、②の順に各自のOS用のものを行ってください（約3時間）。**RまたはRStudioの基本的な利用法が理解できていれば、ここはスキップしてもかまいません**。

![](https://www.iu.a.u-tokyo.ac.jp/kadota/book/Rinstall.png){width="600"}

## W1.2 事前準備2
　ここでは、[ggsankeyfier](https://CRAN.R-project.org/package=ggsankeyfier)と[tidyverse](https://www.tidyverse.org/)と[caret](https://cran.r-project.org/package=caret)のインストールを行います。3つのパッケージは、以下のコピペでインストールできます。[caret](https://cran.r-project.org/package=caret)は、機械学習用のパッケージであり、混同行列から各種性能評価指標を算出する際に利用しています。
```{r, message=FALSE, error=TRUE, warning=FALSE, eval=FALSE, comment=""}
if (!require("BiocManager", quietly = TRUE))     # BiocManagerパッケージがインストールされてなければ...
    install.packages("BiocManager")              # BiocManagerをインストールせよ
BiocManager::install("ggsankeyfier", update=F)   # パッケージのインストール（ggsankeyfier）
BiocManager::install("tidyverse", update=F)      # パッケージのインストール（tidyverse）
BiocManager::install("caret", update=F)          # パッケージのインストール（caret）
```

## W1.3 エラー遭遇時の対処法
　ここはエラーに遭遇したヒト用の補足情報です。R本体のバージョンが古いと、上記スクリプトではうまくいかないことがあります。例えば、2025年6月21日現在のR本体の最新版は4.5.1ですが、バージョンが4.3.0以下ですとおそらくコケます。**1つの対処法は、R本体のバージョンを上げて上記をやり直すこと**です。そしてもう1つの対処法は、**現在利用中のRのままで以下を実行すること**です。
```{r, message=FALSE, error=TRUE, warning=FALSE, eval=FALSE, comment=""}
install.packages("ggsankeyfier", repos = "https://cloud.r-project.org/")
install.packages("tidyverse", repos = "https://cloud.r-project.org/")
install.packages("caret", repos = "https://cloud.r-project.org/")
```

# W2 二値分類問題

- 図1a  
入力データは、[JALAB27.csv](https://www.iu.a.u-tokyo.ac.jp/kadota/book/JSLAB27.csv")です。
- [連載第24回](https://www.iu.a.u-tokyo.ac.jp/kadota/r_seq2.html#book_JSLAB_24)  
ウェブ資料は[こちら](https://www.iu.a.u-tokyo.ac.jp/kadota/book/JSLAB24.html)です。
- [連載第25回](https://www.iu.a.u-tokyo.ac.jp/kadota/r_seq2.html#book_JSLAB_25)  
ウェブ資料は[こちら](https://www.iu.a.u-tokyo.ac.jp/kadota/book/JSLAB25.html)です。
- [HM-280](https://www.beiresources.org/Catalog/otherProducts/HM-280.aspx) ([Gevers et al., PLoS Comput Biol., 2012](https://pubmed.ncbi.nlm.nih.gov/23209389/))  
HM-280の原著論文です。
- [SRP125723](https://www.ncbi.nlm.nih.gov/sra/?term=SRP125723) ([Hallmaier-Wacker et al., Sci Rep., 2018](https://pubmed.ncbi.nlm.nih.gov/29674641/))  
これはHM-280サンプルを用いてリードデータを取得した論文になります。
- [dada2](https://bioconductor.org/packages/release/bioc/html/dada2.html)：[Callahan et al., Nat Methods, 2016](https://pubmed.ncbi.nlm.nih.gov/27214047/)  
- [連載第26回](https://www.iu.a.u-tokyo.ac.jp/kadota/r_seq2.html#book_JSLAB_26)  
ウェブ資料は[こちら](https://www.iu.a.u-tokyo.ac.jp/kadota/book/JSLAB26.html)です。
- [ggsankeyfier](https://CRAN.R-project.org/package=ggsankeyfier)

# W3 混同行列

- [混同行列](https://ja.wikipedia.org/wiki/%E6%B7%B7%E5%90%8C%E8%A1%8C%E5%88%97)
- [正方行列](https://ja.wikipedia.org/wiki/%E6%AD%A3%E6%96%B9%E8%A1%8C%E5%88%97)
- [caret](https://cran.r-project.org/package=caret)

## W3.1 図1c-dと図3a-b
　ここでは、[caret](https://cran.r-project.org/package=caret)パッケージの`confusionMatrix`関数を利用して混同行列（confusion matrix）の作成や各種性能評価指標の計算行いましたが、[連載第21回](https://www.iu.a.u-tokyo.ac.jp/kadota/r_seq2.html#book_JSLAB_21)で紹介した[tidymodels](https://www.tidymodels.org/)を利用しても構いません。図1cは、ここで見えている混同行列と実質的に同じです。また、図1dの各種性能評価指標は、以下で見えているスクリプト実行結果と同じです（但しF値を除く）。図3aとbは、ここで見えているスクリプトおよび実行結果のスクショです。
```{r, message=FALSE, error=TRUE, warning=FALSE, eval=TRUE, comment="", results=TRUE}
in_f <- "https://www.iu.a.u-tokyo.ac.jp/kadota/book/JSLAB27.csv" # 入力ファイル名

# 必要なパッケージをロード
library(tidyverse)                               # パッケージの読込
library(caret)                                   # パッケージの読込

# 入力ファイルの読み込み
data <- read_csv(in_f)                           # in_fで指定したファイルの読込

# 混同行列の作成
predi <- rep(data$Prediction, data$Frequency)    # Frequency列の出現頻度情報を反映したバイナリベクトルの作成（Prediction列）
truth <- rep(data$Truth, data$Frequency)         # Frequency列の出現頻度情報を反映したバイナリベクトルの作成（Truth列）
tbl <- table(Predicted = predi,                  # 予測結果情報のベクトル（predi）をPredictedという名前、
             Actual = truth)                     # 正解情報のベクトル（truth）をActualという名前にして混同行列を作成

# 各種性能評価指標の算出
confusionMatrix(data = tbl, positive = "P")      # 混同行列（tbl）を入力、"P"をpositiveとして各種性能評価指標を算出
```

# W4 性能評価指標

## W4.1 図2
　以下のコピペで得られます。
```{r, message=FALSE, error=TRUE, warning=FALSE, eval=TRUE, comment="", results=TRUE}
in_f <- "https://www.iu.a.u-tokyo.ac.jp/kadota/book/JSLAB27.csv" # 入力ファイル名

# 必要なパッケージをロード
library(tidyverse)                               # パッケージの読込
library(ggsankeyfier)                            # パッケージの読込

# 入力ファイルの読み込み
data <- read_csv(in_f)                           # in_fで指定したファイルの読込

# 前処理（描画させたい列情報の抽出とlong型への変換
matome <- pivot_stages_longer(                   # long型データへの変換
              data = data,                       # 入力はdataオブジェクト   
              stages_from = c("Prediction", "Truth"), # 描画させたいカテゴリ名情報
              values_from = "Frequency")         # 頻度をカウントしたい列名情報

# 作図1（サンキー図の基本形まで作成した結果をgに格納）
pos <- position_sankey(v_space = "auto",         # ノード名情報描画時の位置情報（ノード間の縦幅間隔は自動）
                       order = "as_is")          # ノード名情報描画時の位置情報（項目名の並びはそのまま）
g <- ggplot(data = matome,                       # ggplot関数実行結果をgに格納。入力はmatomeオブジェクト
  mapping = aes(x = stage, y = Frequency,        # matomeのstage列とFreqency列をx軸とy軸として利用
                group = node, fill = node,       # groupとfillは、matome内のnode列で行う（変更不要）
                edge_id = edge_id,               # edge_idはmatome内のedge_id列（変更不要）
                connector = connector)) +        # connectorはmatome内のconnector列（変更不要）
  geom_sankeynode(position = pos) +              # ノード情報を追加
  geom_sankeyedge(position = pos)                # エッジ情報を追加

# 作図2-1（ノードに付随する情報を描画する際に利用する微調整用のパラメータ作成）
# y軸の高さは入力ファイルの行数次第なので、nrow(data)の何%程度上下にずらすかという感じの計算をしている
# nudge_xとnudge_yは、x軸とy軸それぞれの方向に少しずらしたい値です（nudgeは小突くという意味）
nudge_val_y <- sum(data$Frequency)*0.025         # y軸上の描画位置をベースラインから上下にずらしたい高さの幅情報
pos1 <- position_sankey(v_space = "auto",        # ノード名情報描画時の位置情報（ノード間の縦幅間隔は自動）
                        order = "as_is",         # ノード名情報描画時の位置情報（項目名の並びはそのまま）
                        nudge_x = 0.06,          # ノード名情報描画時の位置情報（x軸情報の位置を0.06右にずらす）
                        nudge_y = nudge_val_y)   # ノード名情報描画時の位置情報（y軸情報の位置をnudge_val_y上にずらす）
pos2 <- position_sankey(v_space = "auto",        # 頻度情報描画時の位置情報（ノード間の縦幅間隔は自動）
                        order = "as_is",         # ノード名情報描画時の位置情報（項目名の並びはそのまま）
                        nudge_x = 0.06,          # 頻度情報描画時の位置情報（x軸情報の位置を0.06右にずらす）
                        nudge_y = -nudge_val_y)  # 頻度情報描画時の位置情報（y軸情報の位置をnudge_val_y下にずらす）

# 作図2-2（基本形gをベースとして、ノードに付随する情報を追加した結果をg2に格納）
# stat = "sankeynode"は、描画するのがノード情報だという指令
# label = nodeは、描画するのがノード名だという指令
# label = Freqは、描画するのがノードに付随する頻度値だという指令
# position = pos1は、微調整用情報としてpos1を利用せよという指令
# position = pos2は、微調整用情報としてpos2を利用せよという指令
# hjust = 0は、文字を左揃えで描画せよという指令（デフォルトは中央揃え）
# size = 4は、サイズ4にせよという指令（この値に応じてnudge_yも適宜調整する）
g2 <- g + 
      geom_text(aes(label = node), stat = "sankeynode", position = pos1, hjust = 0, size = 4) + 
      geom_text(aes(label = Frequency), stat = "sankeynode", position = pos2, hjust = 0, size = 4)

# 作図3（g2をベースとして、背景や凡例などを消すなどの調整を行った結果をg3に格納）
g3 <- g2 + theme_minimal() +                     # 背景を白に変更
      theme(panel.grid = element_blank(),        # グリッド線を消す
            legend.position = 'none',            # 凡例を消す
            axis.title = element_blank(),        # 軸のタイトルを消す
            axis.text.y = element_blank(),       # y軸のメモリ表示を消す
            axis.text.x = element_text(size = 15)) # x軸（カテゴリ名）はサイズ15にせよ
g3
```

# W5 dada2実行結果の性能評価指標

- [連載第25回](https://www.iu.a.u-tokyo.ac.jp/kadota/r_seq2.html#book_JSLAB_25)  
ウェブ資料は[こちら](https://www.iu.a.u-tokyo.ac.jp/kadota/book/JSLAB25.html)です。
- [dada2](https://bioconductor.org/packages/release/bioc/html/dada2.html)：[Callahan et al., Nat Methods, 2016](https://pubmed.ncbi.nlm.nih.gov/27214047/)  

# W6 Caretで性能評価指標を算出
図3aとbは、W3.1で示されています。
- [caret](https://cran.r-project.org/package=caret)

## W6.1 図3c
　実際に見えているものとは若干見栄えが異なりますが、以下のコピペの表示結果と同じ中身が得られます。
```{r, message=FALSE, error=TRUE, warning=FALSE, eval=TRUE, comment="", results=TRUE}
data

c("A", "B", "C")
c(2, 4, 3)
rep(c("A", "B", "C"), c(2, 4, 3))

data$Prediction
data$Frequency
predi

truth

tbl

```

## W6.2 図4a
入力ファイルは、[JALAB27_2.csv](https://www.iu.a.u-tokyo.ac.jp/kadota/book/JSLAB27_2.csv")です。
```{r, message=FALSE, error=TRUE, warning=FALSE, eval=TRUE, comment="", results=TRUE}
in_f <- "https://www.iu.a.u-tokyo.ac.jp/kadota/book/JSLAB27_2.csv" # 入力ファイル名

# 必要なパッケージをロード
library(tidyverse)                               # パッケージの読込
library(caret)                                   # パッケージの読込

# 入力ファイルの読み込み
data <- read_csv(in_f)                           # in_fで指定したファイルの読込

# 混同行列の作成
predi <- rep(data$Prediction, data$Frequency)    # Frequency列の出現頻度情報を反映したバイナリベクトルの作成（Prediction列）
truth <- rep(data$Truth, data$Frequency)         # Frequency列の出現頻度情報を反映したバイナリベクトルの作成（Truth列）
tbl <- table(Predicted = predi,                  # 予測結果情報のベクトル（predi）をPredictedという名前、
             Actual = truth)                     # 正解情報のベクトル（truth）をActualという名前にして混同行列を作成

# 各種性能評価指標の算出
confusionMatrix(data = tbl, positive = "P")      # 混同行列（tbl）を入力、"P"をpositiveとして各種性能評価指標を算出
```


## W6.3 図4b
入力ファイルは、[JALAB27_3.csv](https://www.iu.a.u-tokyo.ac.jp/kadota/book/JSLAB27_3.csv")です。
```{r, message=FALSE, error=TRUE, warning=FALSE, eval=TRUE, comment="", results=TRUE}
in_f <- "https://www.iu.a.u-tokyo.ac.jp/kadota/book/JSLAB27_3.csv" # 入力ファイル名

# 必要なパッケージをロード
library(tidyverse)                               # パッケージの読込
library(caret)                                   # パッケージの読込

# 入力ファイルの読み込み
data <- read_csv(in_f)                           # in_fで指定したファイルの読込

# 混同行列の作成
predi <- rep(data$Prediction, data$Frequency)    # Frequency列の出現頻度情報を反映したバイナリベクトルの作成（Prediction列）
truth <- rep(data$Truth, data$Frequency)         # Frequency列の出現頻度情報を反映したバイナリベクトルの作成（Truth列）
tbl <- table(Predicted = predi,                  # 予測結果情報のベクトル（predi）をPredictedという名前、
             Actual = truth)                     # 正解情報のベクトル（truth）をActualという名前にして混同行列を作成

# 各種性能評価指標の算出
confusionMatrix(data = tbl, positive = "P")      # 混同行列（tbl）を入力、"P"をpositiveとして各種性能評価指標を算出
```


## W6.4 何でも陽性と返す分類器の場合
入力ファイルは、[JALAB27_4.csv](https://www.iu.a.u-tokyo.ac.jp/kadota/book/JSLAB27_4.csv")です。
```{r, message=FALSE, error=TRUE, warning=FALSE, eval=TRUE, comment="", results=TRUE}
in_f <- "https://www.iu.a.u-tokyo.ac.jp/kadota/book/JSLAB27_4.csv" # 入力ファイル名

# 必要なパッケージをロード
library(tidyverse)                               # パッケージの読込
library(caret)                                   # パッケージの読込

# 入力ファイルの読み込み
data <- read_csv(in_f)                           # in_fで指定したファイルの読込

# 混同行列の作成
predi <- rep(data$Prediction, data$Frequency)    # Frequency列の出現頻度情報を反映したバイナリベクトルの作成（Prediction列）
truth <- rep(data$Truth, data$Frequency)         # Frequency列の出現頻度情報を反映したバイナリベクトルの作成（Truth列）
tbl <- table(Predicted = predi,                  # 予測結果情報のベクトル（predi）をPredictedという名前、
             Actual = truth)                     # 正解情報のベクトル（truth）をActualという名前にして混同行列を作成

# 各種性能評価指標の算出
confusionMatrix(data = tbl, positive = "P")      # 混同行列（tbl）を入力、"P"をpositiveとして各種性能評価指標を算出
```

# W7 おわりに

## W7.1 二値分類問題にサンキー図を交えた記事
質問は「二値分類問題にサンキー図を交えて解説した記事は存在しますか？」としました。ウェブ検索では、「二値分類 サンキー図」での結果として見つけられなかったこと、そして生成AIでは、[Perplexity](https://www.perplexity.ai/)ではヒットせず、[Gemini](https://gemini.google.com/)では英語版のページが1つ例示されていただけでした。[Gemini](https://gemini.google.com/)ではその後、「日本語のページはありますか？」および「具体例を挙げてください。」の結果として、ピンポイントで特定することができなかったという回答を得ています。これらが本文中で述べた「サンキー図を交えた日本語の解説はおそらく本稿が初」の根拠になります。

### W7.1.1 Perplexityの回答
2025年8月時点で、「二値分類問題にサンキー図を交えて解説した記事」として、そのものズバリの日本語記事は検索結果から発見できませんでした。
具体的には、二値分類問題（binary classification）の解説記事や、サンキー図の使い方・事例記事は存在するものの、二値分類の説明や評価指標の可視化等にサンキー図を直接用いた解説記事はヒットしませんでした。

### W7.1.2 Geminiの回答
はい、二値分類問題にサンキー図を交えて解説した記事は存在します。

特に、混同行列（Confusion Matrix）をサンキー図で可視化するというアプローチで解説されている記事がいくつか見られます。これは、二値分類モデルの予測結果（True Positive, True Negative, False Positive, False Negative）と実際のクラス（True Class）の関係を視覚的に分かりやすく表現するのに非常に効果的です。

検索結果からいくつかの例を挙げると、

Towards AIの "[A Unique Way of Visualising Confusion Matrix — Sankey Chart](https://towardsai.net/p/l/a-unique-way-of-visualising-confusion-matrix%E2%80%8A-%E2%80%8Asankey-chart)" という記事は、まさに二値分類における混同行列をサンキー図で表現する方法について詳しく解説しています。True Class（正解クラス）とPredicted Class（予測クラス）をノードとして、その間のフローをサンキー図で示すことで、モデルがどのように正しく分類し、どのように誤分類したかを直感的に理解できるようになっています。

## W7.2 Detection Rateについて
質問は「性能評価指標の1つであるDetection Rateについて教えてください。」としました。

### W7.2.1 Perplexityの回答
Detection Rate（ディテクションレート）は、性能評価指標のひとつで、全評価対象のうち、真陽性（True Positive: TP）が占める割合を示す指標です。  
式で表すと、  
...  
ここで、TP（True Positive）は「正例」と正しく判定した件数、Mは全サンプル数（TP+TN+FP+FN）です。

ポイント:  

- Detection Rateは、単に「全体の中で何件正しく検出できたか（正答率のうちTPのみ）」を見る指標です。
- 似た指標として「再現率（Recall）」がありますが、Recallは「本来の正例の中でモデルがどれだけ検出できたか」を見るのに対し、Detection Rateは「全体」に対するTPの割合です。
- 通常、真陰性（TN）や偽陽性（FP）、偽陰性（FN）も含めたすべての予測対象が分母になっています。
- 必ずしも評価指標として主流ではありませんが、検出漏れのリスクが重視される分野では活用されます。

### W7.2.2 Geminiの回答
Detection Rate（検出率）は、二値分類問題の性能評価指標の一つで、特に**感度（Sensitivity）や真陽性率（True Positive Rate, TPR）**と同じ意味で使われることが多いです。

Detection Rateは、実際に陽性であるものの中から、モデルが正しく陽性と予測できたものの割合を示します。

計算式は以下の通りです。

Detection Rate = 真陽性 (True Positive, TP) / (真陽性 (TP) + 偽陰性 (False Negative, FN))

真陽性 (TP): 実際に陽性であり、モデルも陽性と予測したケース

偽陰性 (FN): 実際に陽性であるが、モデルが陰性と予測してしまったケース（見逃し）

Detection Rateが何を意味するか

高いDetection Rate: 実際に陽性であるものを、モデルがどれだけ多く見つけることができたかを示します。例えば、病気の診断モデルであれば、実際に病気である患者をどれだけ正確に「病気」と判断できたか、といった重要性があります。

低いDetection Rate: 陽性であるものを見逃している可能性が高いことを意味します。


