回帰モデルの評価#
機械学習を適用する場面においては、所与のデータに対して複数のモデルを当てはめてみて、あるいは同種のモデルでも異なる「ハイパーパラメータ」の下で当てはめてみて、それらの結果を比較して適切なモデルを選択することがよく行われます。この際、学習したモデルが学習に用いたデータとどの程度適合しているか、また学習に用いなかったデータにもどの程度対応できているかを評価し、比較するための数値的な指標が必要になります。こうした指標は複数のモデルやハイパーパラメータの比較に利用できるのみならず、採用したモデルと学習の方法によっては、そのモデルが未知のデータに対してどれほどの不確かさで以て推論できるかを考察するときの参考にすることもできます。
本稿では、(時系列回帰を含む)回帰モデル一般で利用される基本的な評価指標について説明します。分類モデルで利用される評価指標、また統計的機械学習における尤度・汎化誤差・情報量規準などの概念についての詳細な説明はそれぞれ当該項目を参照してください。
準備#
回帰モデル \(f: \mathcal{X} \to \mathbf{R}\) とデータ \(\mathcal{D} = ( (x_i, y_i) ) _{i = 1, \ldots, n} \in ( \mathcal{X} \times \mathbf{R} ) ^n\) が与えられているものとします。ここで \(\mathcal{X}\) は説明変数の定義域です。このとき、回帰モデルによる予測 \(\hat{\mathbf{y}} = ( \hat{y}_i ) _{i = 1, \ldots, n} = ( f (x_i) ) _{i = 1, \ldots, n}\) が対応する目的変数の値 \(\mathbf{y} = ( y_i ) _{i = 1, \ldots, n}\) からどの程度離れているかの指標が計算できれば、このデータに対する回帰モデルの当てはまりの良さの指標として利用できそうです。
具体的には、適当な関数 \(L: \mathbf{R}^n \times \mathbf{R}^n \to \mathbf{R}\) で \(\hat{\mathbf{y}}\) が \(\mathbf{y}\) によく当てはまっているほど \(L ( \mathbf{y}, \hat{\mathbf{y}} )\) の値が小さくなるような関数を考え、 \(L ( \mathbf{y}, \hat{\mathbf{y}} )\) の値をこのデータに対する回帰モデルの当てはまりの良さの指標として利用することにします。ただし、ここで単純に誤差 \(y_i - \hat{y}_i\) の算術平均をとって
とすると正負の誤差が相殺されてしまうため、予め誤差の二乗や絶対値をとって誤差の大きさの平均を計算できるようにすることがよく行われます。
また、統計的モデル選択や統計的機械学習の文脈では、データの当てはまりのよさを評価するだけでなく回帰モデル \(f\) の複雑性に罰則を課して \(L ( \mathbf{y}, \hat{\mathbf{y}} ) + \Omega ( f )\) や \(L ( \mathbf{y}, \hat{\mathbf{y}} ; f)\) のような形の評価指標を用いることが多々あります。もっとも、本稿では簡単のため \(f\) に依存しない \(L ( \mathbf{y}, \hat{\mathbf{y}} )\) のような形の評価指標のみ扱うことにします。
回帰モデルの評価指標#
本節では主要な回帰モデルの評価指標をいくつか紹介し、併せてそれらのNumPyにおける計算方法を示します。
import numpy as np
この計算において、 \(\mathbf{y}\) および \(\hat{\mathbf{y}}\) の値としてはダミーの乱数列を利用することにします。
n = 50
np.random.seed(42)
y = np.random.normal(loc=10.0, scale=1.0, size=(n, 1)) # dummy values for target
y_hat = np.random.normal(
loc=10.5, scale=0.5, size=(n, 1)
) # dummy values for model prediction
MSE#
平均二乗誤差(mean squared error; MSE)とは
で与えられる値のことです。二乗平均誤差とも呼ばれます。MSEの最小値は0で、値が0に近いほどモデルとデータがよく当てはまっていることを示します。
mse = np.mean(np.square(y - y_hat))
# mse = ((y - y_hat) ** 2).mean()
print(f"MSE: {mse}.")
MSE: 1.4928246592804484.
MSEは回帰モデルの誤差項が(独立同分布で)正規分布に従うと仮定したときの条件付き対数尤度に対応します。このため、回帰モデルの評価自体は別の指標で行う場合でもしばしば学習時の損失関数として設定されることがあります。
RMSE#
二乗平均平方根誤差(root mean squared error; RMSE)とは
で与えられる値のことで、MSEの平方根をとったものです。従ってRMSEの最小値も0で、値が0に近いほどモデルとデータがよく当てはまっていることを示します。
rmse = np.sqrt(np.mean(np.square(y - y_hat)))
# rmse = ((y - y_hat) ** 2).mean() ** 0.5
# rmse = np.sqrt(mse)
print(f"RMSE: {rmse}.")
RMSE: 1.2218120392599052.
目的変数の値 \(y_i\) が物理的に意味のある単位を持っているとき、MSEの単位はその平方として解釈できることがあります。従って、解釈上の要請から「誤差の平均」が元の目的変数と同じ単位を持つようにしたい場合は、しばしばその平方根を取ることが行われます。即ち、今回の例ではモデルの予測した値が真の値から(RMSEの意味で)平均して約1.22だけずれていることになります。こうした「誤差の平均」の指標としてのRMSEは、後述するMAEと比較すると(絶対値が1を超えるような)外れ値に対して影響を受けやすいという特徴があります。
MAE#
平均絶対誤差(mean absolute error; MAE)とは
で与えられる値のことです。MAEの最小値は0で、値が0に近いほどモデルとデータがよく当てはまっていることを示します。
mae = np.mean(np.abs(y - y_hat))
# mae = np.abs(y - y_hat).mean()
print(f"MAE: {mae}.")
MAE: 1.0229284487114587.
RMSEと同様、MAEも「誤差の平均」の指標として利用されることがあります。即ち、今回の例ではモデルの予測した値が真の値から(MAEの意味で)平均して約1.02だけずれていることになります。「誤差の平均」の指標としてのMAEは、RMSEと比較すると(絶対値が1を超えるような)外れ値に対して相対的に頑健であるという特徴があります。
MAEは回帰モデルの誤差項が(独立同分布で)Laplace分布に従うとした仮定したときの条件付き対数尤度に対応します。このため、MSEと同様に(稀にではありますが)回帰モデルの学習時の損失関数として設定されることがあります。
MAPE#
平均絶対百分率誤差(mean absolute percentage error; MAPE)とは
で与えられる値のことです。MAPEの最小値は0で、値が0に近いほどモデルとデータがよく当てはまっていることを示します。
mape = 100.0 * np.mean(np.abs((y - y_hat) / y))
# mape = 100. * np.abs((y - y_hat) / y).mean()
print(f"MAPE: {mape}.")
MAPE: 11.025942391968035.
MAPEは「予測した値が真の値から平均して何パーセントずれているか」を表す値として自然に解釈できます。即ち、今回の例ではモデルの予測した値が真の値から平均して約11%ずれていることになります。
注意点として、定義式より自明ですが、MAPEはデータの絶対値の逆数で重み付けたMAEとも解釈できます。このため、絶対値のより小さい値をよく予測するモデルの方がより小さいMAPEを獲得しやすくなっており、予測すべきデータのスケールに幅があるときは利用に考慮が必要です。同じ理由からMAPEは絶対値の小さい \(y_i\) があるときに値が不安定になりやすく、特に \(y_i = 0\) なるデータがあるときにはそもそも利用できません。
これらの問題を解決するためにsymmetric MAPE (sMAPE) などの指標も提案されています。
R2#
決定係数(coefficient of determination)にはいくつかの定義がありますが、一般的には
で与えられる値を指します。ただし、ここで \(\bar{y} = \sum_{i = 1}^n y_i\) と置きました。定義式より自明ですが、決定係数は \(y_i\) が常に一定の値を取るとき、特に \(n = 1\) のときに定義されません。これまでに紹介した誤差の指標と異なり、R2に限っては値が大きいほど(最大値が1なので、1に近いほど)モデルとデータがよく当てはまっていることを示します。
y_bar = np.mean(y)
r2 = 1 - np.sum(np.square(y - y_hat)) / np.sum(np.square(y - y_bar))
print(f"R2 (directly): {r2}.")
R2 (directly): -0.7474189803928322.
この定義を採用する場合、決定係数はモデルの予測が、常にデータの平均を予測するナイーブな予測と比較してどの程度ましであるかをMSEの意味で比較した指標として解釈できます。即ち、常に \(f_\mathrm{hm} ( x_i ) = \bar{y}\) を返す後知恵のナイーブな予測を \(\hat{\mathbf{y}}_\mathrm{hm} = ( \bar{y} )_{i = 1, \ldots, n}\) と書くことにすると、決定係数の式は
と変形できます。即ち、決定係数の値が1を取るときはモデルの予測がデータと完全に一致しているときであり、それより小さい正の値を取るときはMSEの意味で後知恵のナイーブな予測よりましなとき、0をとるときはそれと同程度なときで、負の値を取るときはそれより悪いときということになります。
r2_ = 1 - mse / np.mean(np.square(y - y_bar))
print(f"R2 (from MSE): {r2}.")
R2 (from MSE): -0.7474189803928322.
いずれにせよ、今回の例では決定係数が0より小さく、(完全にランダムな予測を実行したので当然ですが)MSEの意味ではこの予測より後知恵のナイーブな予測の方がましだということができます。
補助的な指標#
以下の指標を単独で用いることはありませんが、しばしば他の指標と併用してモデルやその予測の性質を詳しく調べるのに用いることがあります。
相関係数#
Pearsonの積率相関係数 (Pearson's correlation coefficient) の推定値
がモデルの評価指標として用いられる場合があります。ただし \(\bar{y} = \sum_{i = 1}^n y_i\) および \(\bar{\hat{y}} = \sum_{i = 1}^n \hat{y}_i\) とおきました。この \(r\) は \(-1 \le r \le 1\) の範囲の値を取り、目的変数の値 \(y_i\) とモデルの予測した値 \(\hat{y}_i\) とのそれぞれの平均からのずれが同じ傾向(片方が平均より大きい/小さいときもう片方も大きい/小さい傾向)であればより \(1\) に近い値、逆の傾向(片方が平均より大きい/小さいときもう片方は小さい/大きい傾向)であればより \(-1\) に近い値を取ります。そういった傾向が強くなければ \(0\) に近い値を取ります。
普通この指標を単独で用いることはありませんが、主にシステム同定の分野でRMSEなど通常の誤差と併せて用いることがあります(例えば [Kano et al. 2009] など)。これはモデルの予測が常にほぼ一定の値に縮退しているのでなく、模倣すべきセンサーの値の上下動にきちんと追従しているかを確認する意味があります。この場合、RMSEなど通常の誤差の指標が十分小さいことを前提に相関係数 \(r\) の値が \(1\) に近いものとなっていることが期待されます。
# y_bar = y.mean()
y_hat_bar = y_hat.mean()
pearson_corr = np.sum((y - y_bar) * (y - y_hat_bar)) / (
np.sum(np.square(y - y_bar)) * np.sum(np.square(y_hat - y_hat_bar))
)
print(f"Correlation: {pearson_corr}.")
Correlation: 0.10678693722686951.
今回の例では(完全にランダムな予測を実行したので当然ですが)両者のずれに明確な傾向はなさそうです。
機械学習モジュールにおける評価手法の設定#
Scikit-learnの場合#
Scikit-learnでは、上記の主要な指標のうちMSE, MAE, R2の3つについてはその値を計算する関数が用意されています。
from sklearn.metrics import (
mean_squared_error, # MSE
mean_absolute_error, # MAE
r2_score, # R2
)
RMSE, MAPEについても(ややトリッキーですが)これらを利用した計算が可能です。
mse_skl = mean_squared_error(y, y_hat)
rmse_skl = np.sqrt(mse_skl)
mae_skl = mean_absolute_error(y, y_hat)
mape_skl = 100.0 * mean_absolute_error(np.ones_like(y), y_hat / y)
r2_skl = r2_score(y, y_hat)
print(f"MSE (sklearn): {mse_skl}.")
print(f"RMSE (sklearn): {rmse_skl}.")
print(f"MAE (sklearn): {mae_skl}.")
print(f"MAPE (sklearn): {mape_skl}.")
print(f"R2 (sklearn): {r2_skl}.")
MSE (sklearn): 1.4928246592804484.
RMSE (sklearn): 1.2218120392599052.
MAE (sklearn): 1.0229284487114587.
MAPE (sklearn): 11.025942391968035.
R2 (sklearn): -0.7474189803928322.
Scikit-learnに所収の回帰モデル( sklearn.base.RegressorMixIn
を継承するestimatorのクラス)では score()
メソッドで所与のデータ \(\mathcal{D} = ( (x_i, y_i) ) _{i = 1, \ldots, n}\) に対するモデルの当てはまりのよさを計算でき、この際に用いられる指標としてはデフォルトでR2が指定されています。それ以外の指標を利用する場合、上記のような関数を読み込むか、自分で定義する必要があります。
後述する交差検証を実施する場合、対象クラスの初期化時や関数の実行時、引数 scoring
に所定の文字列を与えるか、適当な関数を与えることでデフォルトの指標(回帰モデルの場合はR2)以外のものを利用できます。この引数 scoring
で指定される関数はモデルとデータがよく当てはまるときほど大きい値を返す必要があります。例えば交差検証の指標にMSEを利用したい場合は、 scoring
引数に与える文字列は負のMSEを表す 'neg_mean_absolute_error'
になります。文字列の指定で利用できるスコアについては下記のページを参照してください。
Cf. 3.3.1. The scoring parameter: defining model evaluation rules (Scikit-learn公式ドキュメント)
小括#
本稿では、回帰モデルで利用される基本的な評価指標について解説しました。回帰モデルの評価に用いる関数 \(L\) の選択にはこれ以外にもさまざまなものがあり、特にMSEやMAEの項で述べたようにデータの従う確率モデルを具体的に想定することで(その直感的な解釈性はさておき)さまざまな評価指標を構成できます。機械学習一般の文脈ではこれら評価指標の選択に絶対的な基準はなく、分析の目的と理論上の要請に合わせて適切なものを選択して利用する必要があります。
参考文献#
Kano, M., Lee, S., and Hasebe, S. (2009). Two-stage subspace identification for softsensor design and disturbance estimation. Journal of Process Control , 19 (2), 179-186.
3.3. Model evaluation: quantifying the quality of predictions. Scikit-learn User Guide. https://scikit-learn.org/stable/modules/model_evaluation.html