この記事では、分類モデルをどのように評価できるかを紹介します。

前回の記事では、ロジスティック回帰とソフトマックス回帰を用いた二項および多クラス分類を紹介しましたが、モデルの評価については触れませんでした。 この記事では、それらのモデルをどのように評価できるかを見ていきたいと思います。
Accuracy (正解率)
分類モデルを評価する最も簡単な方法の一つは、以下のように予測の正解率を計算することです。
この指標、メトリクスは計算が非常に簡単で理解しやすいため、非常によく使用されます。しかし、場合によっては予測のすべての側面を捉えることができないことがあります。 例えば、テストデータセットに500件のデータポイントがあり、そのうち100件がセトサ、400件がセトサでないとします。モデルAが非常に悪く、 すべてのデータに対してセトサでないと予測した場合、以下のようになります。
モデルがセトサに対して常に間違った予測をしているにもかかわらず、80%の正解率を達成しています。このように正解率はデータセットが不均衡な場合にうまく機能しません。
Confusion Matrix (混同行列)
ここで混同行列が役立ちます。これは、予測されたクラスが実際のクラスとどのように対応しているかを行列でプロットします。以下は、モデルAの上記シナリオの混同行列です。
予測 \ 実際 | セトサ | セトサでない |
---|---|---|
セトサ | 0 | 0 |
セトサでない | 100 | 400 |
予測されたクラスと実際のクラスが共にセトである場合、それを真陽性 (TP) と呼びます。クラスがセトまたは陽性であると正しく予測されたためです。 予測されたクラスと実際のクラスが共にセトサでない場合、それを真陰性 (TN) と呼びます。クラスがセトサでないまたは陰性であると正しく予測されたためです。
予測されたクラスがセトサであるが、実際はセトサでない場合、それを偽陽性 (FP) と呼びます。モデルが誤ってクラスをセトサまたは陽性と予測したためです。 最後に、予測されたクラスがセトサでないが、実際はセトサである場合、それを偽陰性 (FN) と呼びます。モデルが誤ってクラスをセトサでないまたは陰性と予測したためです。 これらの用語を使用して、正解率を次のように書き換えることができます。
モデルが偽陽性を完全に回避し、高い正解率を達成している一方で、偽陰性に関しては非常に悪いパフォーマンスであることがわかります。
Precision (適合率) vs Recall (再現率)
偽陽性と偽陰性に関するモデルの性能を捉えるために、適合率と再現率を使用することができます。モデルBの混同行列が以下のようになったとします。
予測 \ 実際 | セトサ | セトサでない |
---|---|---|
セトサ | 30 | 210 |
セトサでない | 70 | 190 |
モデルBの適合率と再現率は以下のように計算できます。
上記の式からわかるように、適合率は陽性と予測されたデータに対する真陽性の比率であり、再現率は実際の陽性に対する真陽性の比率です。 このことから偽陽性を避けることを優先したい場合には適合率を使用し、偽陰性を避けることを優先したい場合には再現率を使用します。
例えば、患者がコロナに感染しているかどうかを分類するモデルを評価する場合、偽陰性のせいでコロナに感染している患者が外に出てウイルスを広めるような事態は避けたいですが、 偽陽性は患者が家にいる時間が長くなるだけなので許容できます。このような分類モデルを評価する場合、偽陽性を避けたいので再現率を使用できます。
一方、メールがスパムかどうかを分類するモデルを評価する場合、偽陽性のせいで重要なメールがスパムとして分類され、削除されるようなを事態は避けたいですが、 偽陰性は時折スパムメールを見なければならなくなるだけで許容できます。このシナリオでは、モデルの評価に適合率を使用できます。
F1-Score (F1スコア)
多くの状況では、偽陽性と偽陰性を作ることの重要性に違いはありません。このようなシナリオでは、適合率と再現率の調和平均を取ってF1スコアを計算できます。
なぜ算術平均ではなく調和平均を取るのでしょうか。それは、調和平均の場合、F1スコアが高くなるためには、適合率と再現率の両方が十分に高くなければならないからです。 適合率が1.0で再現率が0.1の場合、算術平均は ですが、調和平均またはF1スコアは です。 このように、調和平均は適合率と再現率の両方が高いかどうかを評価できるため、F1スコアの計算に用いられます。
マクロ平均と重み付き平均F1スコア
これまでのところ、二項分類モデルの評価について話してきました。多クラス分類モデルではどのように計算するのでしょうか。非常に簡単です。 他のクラスを陰性として扱い、各クラスに対して適合率、再現率、F1スコアを計算できます。Irisデータセットで学習したモデルCの例を使って、 どのように機能するかを見てみましょう。
予測 \ 実際 | セトサ | ヴァーシカラ | ヴァージニカ |
---|---|---|---|
セトサ | 30 | 40 | 50 |
ヴァーシカラ | 30 | 10 | 20 |
ヴァージニカ | 40 | 50 | 30 |
まず、以下のように各種に対して3つの混同行列を生成できます。
予測 \ 実際 | セトサ | セトサでない |
---|---|---|
セトサ | 30 | 90 |
セトサでない | 70 | 110 |
予測 \ 実際 | ヴァーシカラ | ヴァーシカラでない |
---|---|---|
ヴァーシカラ | 10 | 50 |
ヴァーシカラでない | 90 | 150 |
予測 \ 実際 | ヴァージニカ | ヴァージニカでない |
---|---|---|
ヴァージニカ | 30 | 90 |
ヴァージニカでない | 70 | 110 |
これを使用して、各種に対するF1スコアを以下のように計算できます。
これらを1つのメトリクスにまとめるために、単純に各種のF1スコアの算術平均をとるマクロ平均F1スコアを以下のように使用できます。
しかし、データに偏りがある場合、それを平均に反映させなければいけません。そのような場合、各種のデータと全体のデータの比を、各種の重みとして 重み付きのF1スコアの平均を取る重み付き平均F1スコアを以下のように使用できます。
今回の例ではデータに偏りがないため、マクロ平均F1スコアと重み付き平均F1スコアが同じです。
コードの実装
では、今まで見てきたメトリクスがLogisticRegressionGD
やSoftmaxRegressionGD
にどのように利用できるかを
見てみましょう。
LogisticRegressionGD
メトリクスの計算の前に、テストデータセットに対してモデルの予測を行います。
pred = lr.predict(X_test)
pred = np.round(pred) # 分類のために四捨五入
ここで重要なのは、モデルは0から1の範囲でセトサである確率を予測しているため、分類を行うために四捨五入する必要があるということです。
その後、sklearn.metrics
のconfusion_matrix
を使用して混同行列を描画し、ConfusionMatrixDisplay
を使用して表示できます。
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
cm = confusion_matrix(y_test, pred)
disp = ConfusionMatrixDisplay(confusion_matrix=cm)
disp.plot()
plt.show()
上記を実行すると、以下のようなものが表示されるはずです。

モデルがテストデータセットを完全に分類し、偽陽性も偽陰性もないことがわかります。
sklearn.metrics
から提供される事前定義された関数を使用して、正解率、適合率、再現率、F1スコアを計算できます。
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
print(f"Accuracy: {accuracy_score(y_test, pred)}")
print(f"Precision: {precision_score(y_test, pred)}")
print(f"Recall: {recall_score(y_test, pred)}")
print(f"F1 Score: {f1_score(y_test, pred)}")
# =>
# Accuracy: 1.0
# Precision: 1.0
# Recall: 1.0
# F1 Score: 1.0
SoftmaxRegressionGD
SoftmaxRegressionGD
の場合も基本的に同じ手順です。まず予測を行ってみましょう。
pred = sm.predict(X_test)
# ワンホットエンコードされたベクトル -> インデックス
pred = np.argmax(pred, axis=1)
y_test = np.argmax(y_test, axis=1)
ソフトマックス回帰の場合、種をワンホットエンコードされたベクトルとしてエンコードし、モデルは確率分布を予測します。
したがって、argmax
を使って最大のインデックスを取って種に対応する数値に戻す必要があります。混同行列をプロットしてみましょう。
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
cm = confusion_matrix(y_test, pred)
disp = ConfusionMatrixDisplay(confusion_matrix=cm)
disp.plot()
plt.show()
上記を実行すると、以下のようなものが表示されるはずです。

混同行列から、モデルが5つのセトサをヴァーシカラとして誤分類していることがわかります。f1_score
や他の関数を使用してF1スコアや
他のメトリクスを取得することもできますが、多クラス分類にはsklearn.metrics
のclassification_report
を使用する方が便利です。
from sklearn.metrics import classification_report
print(classification_report(y_test, pred))
# =>
# precision recall f1-score support
# 0 1.00 0.67 0.80 15
# 1 0.81 1.00 0.90 22
# 2 1.00 1.00 1.00 13
# accuracy 0.90 50
# macro avg 0.94 0.89 0.90 50
# weighted avg 0.92 0.90 0.90 50
分類レポートから、各クラスに対する適合率、再現率、F1スコア、マクロ平均F1スコア、重み付き平均F1スコアなどのすべての指標が観察できます。 テストデータセットのわずかなクラスの不均衡のため、マクロ平均と重み付き平均の両方の適合率と再現率がわずかに異なることがわかります。
結論
この記事も非常に長くなってきたので、ここで終わりにしたいと思います。分類モデルを評価するための主要なメトリクスのいくつかをカバーしましたが、 ROC曲線、AUCなど、他にも多くの指標があります。タスクに応じて適切なメトリクスを選択することが重要です。多くの場合、その特定のタスクに対して 他の人が使用している標準的な指標があるため、他の人が使用しているものと同じものを使用すればよいです。しかし、新しい課題に取り組んでいる場合は、 さまざまな指標から選択するか、メトリクスを発明する必要があるかもしれません。いずれにしても、指標が何をするのか、 何のために作られているのかを理解して選択することが非常に大切です。