機械学習で使われる評価関数まとめ

# はじめに

評価関数（評価指標）についてあやふやな理解だったので、代表的な評価関数をまとめてみました。
評価関数とはそもそもどんなものなのか、それぞれの評価関数はどんな意味を持つのか、実際に使う時のサンプルコードを簡単にまとめています。

評価関数の追加や内容の修正は下記でしています。

https://amateur-engineer-blog.com/machine-learning-metrics

# 評価関数とは

評価関数とは**学習させたモデルの良さを測る指標**を指します。

## 目的関数との違い

機械学習を勉強していると、目的関数や損失関数、コスト関数などいろいろな名前を目にします。
まずは、目的関数との違いについて確認します。

- 目的関数
  - モデルの学習で最適化される関数
  - 微分できる必要がある

つまり、学習中に最適化されるのが目的関数、学習後に良さを確認するための指標が評価関数ということになります。

損失関数、コスト関数、誤差関数は目的関数の一部になるそうです。
（いくつか議論がありそうなのですが、ほとんど同じものと考えても良さそうです。）

# 回帰

まずは、回帰問題の評価関数について、まとめていきます。
サンプルデータで扱う真の値と予測の値は以下のようになります。

```python
y_true = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]
y_pred = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 5.0]
```

## MAE(Mean Absolute Error)

平均絶対誤差。
真の値と予測の値の差の絶対値の平均を表します。

- 外れ値の影響を小さく評価

```math
\textrm{MAE} = \frac{1}{N}\sum_{i=1}^{N}|y_{i}-\hat{y}_{i}|
```

```math
N : レコード数 \\
y_{i} : i番目のレコードの真の値 \\
\hat{y}_{i} : i番目のレコードの予測値
```

```python
from sklearn.metrics import mean_absolute_error
mean_absolute_error(y_true, y_pred)
# => 0.5
```

## MSE(Mean Squared Error)

平均二乗誤差。
真の値と予測の値の差を二乗した平均を表します。

- 外れ値の影響を大きく評価
- 単位が目的変数の二乗

```math
\textrm{MSE} = \frac{1}{N}\sum_{i=1}^{N}(y_{i}-\hat{y}_{i})^{2}
```

```python
from sklearn.metrics import mean_squared_error
mean_squared_error(y_true, y_pred)
# => 2.5
```

## RMSE(Root Mean Squared Error)

平均平方二乗誤差。
真の値と予測の値の差を二乗した平均を表します。

- 外れ値の影響を大きく評価
- 単位が目的変数と同じ

```math
\textrm{RMSE} = \sqrt{\frac{1}{N}\sum_{i=1}^{N}(y_{i}-\hat{y}_{i})^{2}}
```

scikit-learnのモジュールでは直接計算できないため、`mean_squared_error`から計算する必要があります。

```python
from sklearn.metrics import mean_squared_error
import numpy as np
np.sqrt(mean_squared_error(y_true, y_pred))
# => 1.5811388300841898
```

## RMSLE(Root Mean Squared Logarithmic Error)

真の値と予測の値の対数をそれぞれとったあとの差を二乗した平均を表します。

- 目的変数のとりうる値の範囲が広いデータに利用
- 差を比率として表現

```math
\textrm{RMSLE} = \sqrt{\frac{1}{N}\sum_{i=1}^{N}(\log (1+y_{i})-\log (1+\hat{y}_{i}))^{2}}
```

```python
from sklearn.metrics import mean_squared_log_error
import numpy as np
np.sqrt(mean_squared_log_error(y_true, y_pred))
# => 0.19167697106586185
```

## 決定係数

$\textrm{R}^{2}$。
回帰分析の当てはまりの良さを表します。

- 目的変数のスケールに依存せず評価可能
- 0から1の値をとる

```math
\textrm{R}^{2} = 1 - \frac{\sum_{i=1}^{N}(y_{i}-\hat{y_{i}})^{2}}{\sum_{i=1}^{N}(y_{i}-\bar{y_{i}})^{2}}
```

```math
\bar{y} = \frac{1}{N}\sum_{i=1}^{N}y_{i}
```

```python
from sklearn.metrics import r2_score
r2_score(y_true, y_pred)
# => 0.696969696969697
```

# 二値分類（正例か負例を予測する場合）

分類問題で、正例か負例かを予測する問題で扱う評価関数について、まとめていきます。

## 混同行列

評価指標ではないですが、正例と負例を予測する評価指標で利用されるため、最初に説明します。

混同行列は、以下の分類結果を表形式で表します。

- TP(True Positive) : 正例を正しく予測
- TN(True Negative) : 負例を正しく予測
- FP(False Positive) : 正例と誤って予測
- FN(False Negative) : 負例と誤って予測

```python
from sklearn.metrics import confusion_matrix
confusion_matrix(y_true, y_pred)
```

以下の形式で出力されます。

| | 予測値が負例 | 予測値が正例
--- | --- | ---
**真の値が負例** | TN | FP
**真の値が正例** | FN | TP

## Accuracy

正解率。
予測結果全体に対して、予測が正しい割合を表します。

```math
正解率(\textrm{Accuracy}) = \frac{TP + TN}{TP + TN + FP + FN}
```

```python
from sklearn.metrics import accuracy_score
accuracy_score(y_true, y_pred)
```

## Precision

適合率。
正例と予測したなかで正しく予測できた割合を表します。

```math
適合率(\textrm{Precision}) = \frac{TP}{TP + FP}
```

```python
from sklearn.metrics import precision_score
precision_score(y_true, y_pred)
```

## Recall

再現率。
実際に正例のなかで正しく予測できた割合を表します。

```math
再現率(\textrm{Recall}) = \frac{TP}{TP + FN}
```

```python
from sklearn.metrics import recall_score
recall_score(y_true, y_pred)
```

## F1-score

F値。
precisionとrecallのバランスをとった指標を表します。

precisionとrecallの調和平均で計算されます。

```math
\textrm{F1-score} = \frac{2 \times \textrm{recall} \times \textrm{precision}}{\textrm{recall} + \textrm{precision}}
```

```python
from sklearn.metrics import f1_score
f1_score(y_true, y_pred)
```

# 二値分類（正例である確率を予測する場合）

次に、分類問題で正例である確率を予測する問題で扱う評価関数についてまとめます。

## logloss

cross entropyとも呼ばれることもあります。
予測した確率分布と正解となる確率分布がどのくらい同じかを表します。

- 0から1の値をとる
- 正しく予測できているときに小さくなる

```math
\begin{align}
\textrm{logloss} &= -\frac{1}{N}\sum_{i=1}^{N}(y_{i}\log p_{i} + (1 - y_{i}) \log (1 - p_{i})) \\
&=-\frac{1}{N}\sum_{i=1}^{N} \log \acute{p}_{i}
\end{align}
```

```math
y_{i} : 正例かどうか表すラベル \\
p_{i} : 正例である予測確率 \\
\acute{p}_{i} : 真の値を予測している確率
```

```python
from sklearn.metrics import log_loss
log_loss(y_true, y_prob)
```

## AUC

ROC曲線の下部の面積を表します。

- ランダムな予測は0.5
- 全て正しく予測すると1.0
- 不均衡データでの分類に利用
- 予測確率と正解となる値(1か0か)の関係から評価

```python
from sklearn.metrics import roc_auc_score
roc_acu_score(y_true, y_prob)
```

### ROC曲線とは

予測値を正例とする閾値を0から1に動かした時の真陽性率と偽陽性率の関係をプロットしたグラフです。
閾値を変化させると真陽性率と偽陽性率がどのように変化するかを表します。

- 真陽性率：全体の正例のうち正例と予測した割合
- 偽陽性率：全体の負例のうち正例と予測した割合

<img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/246138/9e4cdb71-5316-68e7-1b14-fc52dab6c872.png">

- (1.0, 1.0)は全て正例と予測
- (0.0, 0.0)は全て負例と予測
- (0.0, 1.0)上は全て正しく予測
- 直線はランダムな予測（AUC=0.5)

# 多クラス分類

## Multi-class accuracy

二値分類のAccuracyを多クラス分類に拡張した指標となります。
正しく予測がされているレコード数の割合を表します。

```python
from sklearn.metrics import accuracy_score
accuracy_score(y_true, y_pred)
```

## mean-F1/macro-F1/micro-F1

F1-scoreを多クラス分類に拡張した指標となります。

- mean-F1：レコードごとのF1-scoreの平均
- macro-F1：クラスごとのF1-scoreの平均
- micro-F1：レコード×クラスのペアごとにTP/TN/FP/FNを計算してF1-scoreを算出

```python
from sklearn.metrics import f1_score
f1_score(y_true, y_pred, average='samples')
f1_score(y_true, y_pred, average='macro')
f1_score(y_true, y_pred, average='micro')
```

## Multi-class logloss

二値分類のloglossを多クラス分類に拡張した指標となります。

```math
\textrm{multiclass logloss} = -\frac{1}{N}\sum_{i=1}^{N}\sum_{m=1}^{M}y_{i,m}\log p_{i,m}
```

```math
M : クラス数 \\
y_{i,m} : レコードiがクラスmに属するか表すラベル \\
p_{i,m} : レコードiがクラスmに属する予測確率 \\
```

```python
from sklearn.metrics import log_loss
log_loss(y_true, y_prob)
```

# 参照

- [sklearn.metrics: Metrics](https://scikit-learn.org/stable/modules/classes.html#module-sklearn.metrics)
- [Kaggleで勝つデータ分析の技術](https://www.amazon.co.jp/Kaggle%E3%81%A7%E5%8B%9D%E3%81%A4%E3%83%87%E3%83%BC%E3%82%BF%E5%88%86%E6%9E%90%E3%81%AE%E6%8A%80%E8%A1%93-%E9%96%80%E8%84%87-%E5%A4%A7%E8%BC%94/dp/4297108437)
- [見て試してわかる機械学習アルゴリズムの仕組み 機械学習図鑑](https://www.amazon.co.jp/%E8%A6%8B%E3%81%A6%E8%A9%A6%E3%81%97%E3%81%A6%E3%82%8F%E3%81%8B%E3%82%8B%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%E3%81%AE%E4%BB%95%E7%B5%84%E3%81%BF-%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E5%9B%B3%E9%91%91-%E7%A7%8B%E5%BA%AD-%E4%BC%B8%E4%B9%9F/dp/4798155659)
- [What is a loss function in decision theory?](https://stats.stackexchange.com/questions/73221/what-is-a-loss-function-in-decision-theory)
- [amateur engineer's blog](https://amateur-engineer-blog.com/)

# 追記

**2020/6/25追記**
混同行列の表が間違っていたので修正しました。
@Fizunimoさん、ありがとうございました。

RMSEとRMSLEのサンプルコードにミスがあったので修正しました。

**2020/7/1追記**
混同行列を混合行列と誤って記載していましたので、修正しました。
@bara6109さん、ありがとうございました。

Recallの説明が誤って記載されていましたので、修正しました。
@uehashuさん、ありがとうございました。

**2020/12/14追記**
log lossの括弧の位置が誤っていたため、修正しました。
@kzaukzaufuさん、ありがとうございました。