機械学習（回帰モデル）で使用する評価指標を整理してみた

* 製造業出身のデータサイエンティストがお送りする記事
* 今回は回帰モデルで使用する評価指標を整理してみました。
 
##はじめに
今回は、機械学習の評価指標（回帰モデル）を整理してみました。
また、各評価指標を使用する際のポイントについても纏めてみました。

##1. 決定係数
決定係数$R^2$では、推定された回帰モデルの当てはまりの良さを評価します。
数式は下記の通りです。

```math
\begin{eqnarray}
R^2 = 1 - \sum \frac{(y_i - \hat{y_i})^2}{(y_i - \bar{y})^2}
\end{eqnarray}
```

$y_i$ : $i$番目サンプルの実測値
$\hat{y_i}$ : $i$番目サンプルの予測値
$\bar{y}$ : 実測値の平均

|項目|概要|
|:---|:---|
|判断基準|・1に近いほど良い値　|
|解釈|・回帰モデルの当てはまりの良さを評価　|
|特徴|・説明変数が多くなると1に近づいていく <br> ・非線形モデルを評価することはできない　|

pythonのコードは下記の通りです。

```php
# スコア計算のためのライブラリ
from sklearn.metrics import r2_score

# trueが真の値（実測値）、predが予測値
true = [1.0, 1.5, 2.0, 1.2, 1.8]
pred = [0.8, 1.5, 1.8, 1.3, 2.0]

# 決定係数R2の値を算出
r2_score(true, pred)
```

##2. MAE
MAE(Mean Absolute Error)では、予測値の誤差の大きさを評価します。
数式は下記の通りです。

```math
\begin{eqnarray}
MAE = \frac{1}{N} \sum|y_i - \hat{y_i}|
\end{eqnarray}
```

$y_i$ : $i$番目サンプルの実測値
$\hat{y_i}$ : $i$番目サンプルの予測値
$N$ : サンプル数

|項目|概要|
|:---|:---|
|判断基準|・0に近いほど良い値　|
|解釈|・予測値と実測値の平均的なズレ（誤差）の大きさ　|
|特徴|・大きく予測を外したケースをあまり重要視していない <br> ・MAEを基準として良いモデルを選ぶと最大誤差が大きくなる傾向にある　|

pythonのコードは下記の通りです。

```php
# スコア計算のためのライブラリ
from sklearn.metrics import mean_absolute_error

# trueが真の値（実測値）、predが予測値
true = [1.0, 1.5, 2.0, 1.2, 1.8]
pred = [0.8, 1.5, 1.8, 1.3, 2.0]

# MAEの値を算出
mean_absolute_error(true, pred)
```

##3. MSE
MSE(Mean Squared Error)では、大きな誤差を重要視して評価します。
数式は下記の通りです。

```math
\begin{eqnarray}
MSE = \frac{1}{N} \sum(y_i - \hat{y_i})^2
\end{eqnarray}
```

$y_i$ : $i$番目サンプルの実測値
$\hat{y_i}$ : $i$番目サンプルの予測値
$N$ : サンプル数

|項目|概要|
|:---|:---|
|判断基準|・0に近いほど良い値　|
|解釈|・予測値と実測値のズレの大きさと解釈できる <br> ・MAEと類似しているが、MAEのように実際の平均的な誤差とは異なる　|
|特徴|・大きく予測を外したケースを重要視している <br> ・予測を大きく外すと大幅にMSEが大きくなる傾向にある　|

pythonのコードは下記の通りです。

```php
# スコア計算のためのライブラリ
from sklearn.metrics import mean_squared_error

# trueが真の値（実測値）、predが予測値
true = [1.0, 1.5, 2.0, 1.2, 1.8]
pred = [0.8, 1.5, 1.8, 1.3, 2.0]

# MSEの値を算出
mean_squared_error(true, pred)
```

##4. RMSE
RMSE(Root Mean Squared Error)では、大きな誤差を重要視して評価します。
数式は下記の通りです。

```math
\begin{eqnarray}
RMSE = \sqrt{\frac{1}{N} \sum(y_i - \hat{y_i})^2}
\end{eqnarray}
```

$y_i$ : $i$番目サンプルの実測値
$\hat{y_i}$ : $i$番目サンプルの予測値
$N$ : サンプル数

|項目|概要|
|:---|:---|
|判断基準|・0に近いほど良い値　|
|解釈|・予測値と実測値のズレの大きさと解釈できる <br> ・MAEと類似しているが、MAEのように実際の平均的な誤差とは異なる　|
|特徴|・大きく予測を外したケースを重要視している <br> ・予測を大きく外すと大幅にRMSEが大きくなる傾向にある　|

pythonのコードは下記の通りです。

```php
# スコア計算のためのライブラリ
import numpy as np
from sklearn.metrics import mean_squared_error

# trueが真の値（実測値）、predが予測値
true = [1.0, 1.5, 2.0, 1.2, 1.8]
pred = [0.8, 1.5, 1.8, 1.3, 2.0]

# RMSEの値を算出
np.sqrt(mean_squared_error(true, pred))
```

##5. MAPE
MAPE(Mean Absolute Percentage Error)では、実測値の大きさあたりの予測誤差の大きさを評価します。
数式は下記の通りです。

```math
\begin{eqnarray}
MAPE = \frac{1}{N} \sum|\frac{y_i - \hat{y_i}}{y_i}|
\end{eqnarray}
```

$y_i$ : $i$番目サンプルの実測値
$\hat{y_i}$ : $i$番目サンプルの予測値
$N$ : サンプル数

|項目|概要|
|:---|:---|
|判断基準|・0に近いほど良い値　|
|解釈|・実測値の大きさに対する予測値の平均的なズレ（誤差）の割合　|
|特徴|・実測値に対する予測誤差の割合の大きさを重要視している <br> ・実測値が0を取るケースでは使用できない　|

pythonのコードは下記の通りです。

```php
# スコア計算のためのライブラリ
import numpy as np

# trueが真の値（実測値）、predが予測値
true = np.array([1.0, 1.5, 2.0, 1.2, 1.8])
pred = np.array([0.8, 1.5, 1.8, 1.3, 2.0])

# MAPEの値を算出
np.mean(np.abs((true - pred) / true)) * 100
```

##6. SMAPE
SMAPE(Symmetric Mean Absolute Percentage Error)では、実測値の大きさあたりの予測誤差の大きさを評価します。
数式は下記の通りです。

```math
\begin{eqnarray}
SMAPE = \frac{100}{N} \sum|\frac{2(y_i - \hat{y_i})}{(|y_i|+|\hat{y_i}|)}|
\end{eqnarray}
```

$y_i$ : $i$番目サンプルの実測値
$\hat{y_i}$ : $i$番目サンプルの予測値
$N$ : サンプル数

|項目|概要|
|:---|:---|
|判断基準|・0に近いほど良い値　|
|解釈|・実測値の大きさに対する予測値の平均的なズレ（誤差）の割合　|
|特徴|・実測値に対する予測誤差の割合の大きさを重要視している <br> ・MAPEと異なり、実測値が0を取るケースでも使用できる　|

pythonのコードは下記の通りです。

```php
# スコア計算のためのライブラリ
import numpy as np

# trueが真の値（実測値）、predが予測値
true = np.array([1.0, 1.5, 2.0, 1.2, 1.8])
pred = np.array([0.8, 1.5, 1.8, 1.3, 2.0])

# SMAPEの値を算出
100/len(true) * np.sum(2 * np.abs(pred - true) / (np.abs(pred) + np.abs(true)))
```

##スクリプトの纏め
今までのスクリプトを整理します。

```php
# スコア計算のためのライブラリ
import numpy as np
import pandas as pd
from sklearn.metrics import r2_score
from sklearn.metrics import mean_absolute_error
from sklearn.metrics import mean_squared_error

def mape(true, pred):  
    """MAPEを計算する

    Parameters
    ----------
    true (np.array) : 実測値
    pred (np.array) : 予測値

    Returns
    -------
    np.array        : mapeの計算結果

    """
    return np.mean(np.abs((true - pred) / true)) * 100

# SMAPEの計算
def smape(true, pred):
    """SMAPEを計算する

    Parameters
    ----------
    true (np.array) : 実測値
    pred (np.array) : 予測値

    Returns
    -------
    np.array        : smapeの計算結果

    """
    return 100/len(true) * np.sum(2 * np.abs(pred - true) / (np.abs(pred) + np.abs(true)))

def calculate_scores(true, pred):
    """全ての評価指標を計算する

    Parameters
    ----------
    true (np.array)       : 実測値
    pred (np.array)       : 予測値

    Returns
    -------
    scores (pd.DataFrame) : 各評価指標を纏めた結果

    """
    scores = pd.DataFrame({'R2': r2_score(true, pred),
                          'MAE': mean_absolute_error(true, pred),
                          'MSE': mean_squared_error(true, pred),
                          'RMSE': np.sqrt(mean_squared_error(true, pred)),
                          'MAPE': mape(true, pred),
                          'SMAPE': smape(true, pred)},
                          index = ['scores'])
    return scores

def main():

    true = np.array([1.0, 1.5, 2.0, 1.2, 1.8])
    pred = np.array([0.8, 1.5, 1.8, 1.3, 2.0])

    scores = calculate_scores(true, pred)

    print(scores)

if __name__ == "__main__":
    main()
```

<div>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>R2</th>
      <th>MAE</th>
      <th>MSE</th>
      <th>RMSE</th>
      <th>MAPE</th>
      <th>SMAPE</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>scores</th>
      <td>0.808824</td>
      <td>0.14</td>
      <td>0.026</td>
      <td>0.161245</td>
      <td>9.888889</td>
      <td>10.254971</td>
    </tr>
  </tbody>
</table>
</div>

##さいごに
最後まで読んで頂き、ありがとうございました。
訂正要望がありましたら、ご連絡頂けますと幸いです。