データ解析ならPythonが最高!第9回

Lab研究員 北山

重回帰分析とRMSE

今回は、重回帰分析とRMSEの話です。
後半以降で機械学習ライブラリ scikit-learn による重回帰分析を少し紹介します。

重回帰分析

単回帰分析では、白菜の個数という1変量で総重量を予測しました。
今回は、白菜の個数と大根の本数という2変量で総重量を予測します。

木箱の中に白菜と大根が混在しています。

Vol7-1.png

重回帰分析では、予測重量を白菜の個数と大根の本数の和(線形結合)で表します。

Vol7-12.png

ここで w は回帰係数です。式 (1) を重回帰式といいます。

この例では重回帰式が

予測重量 = 白菜1個の重さ×白菜の個数 + 大根1本の重さ×大根の本数 + 木箱の重さ

となることを期待しています。回帰係数 w は白菜や大根の1個あたりの重さです。
白菜や大根の1個あたりの重さが分かれば、白菜の個数と大根の本数から総重量を予測できます。

重回帰分析は、単回帰分析と同様に次の残差平方和を最小とする回帰係数を推定します。

Vol7-3.png

スカラから行列へ

重回帰式を幾何学的なイメージで表現すると次のようになります。切片は仮にゼロとしています。

Vol7-24.png

白菜と大根の標本ベクトルをそれぞれ x, z とすると、xz が平行でなければ、xz が張る
平面上の任意の点を xz の線形結合で表すことができます。このとき、重回帰分析は、
総重量 y を近似(残差平方和を最小化)する線形結合の回帰係数 w1 と w2 を推定します。

重回帰分析では複数の変量を取り扱うため、行列を導入します。

Vol7-14.png

とすると、各標本の予測重量

Vol7-15.png

を、次のように行列を用いて表すことができます。

Vol7-16.png

ここで

Vol7-17.png

とすると、式(1) の重回帰式を次のように表すことができます。

Vol7-9.png

このとき、正規方程式より、残差平方和を最小とする回帰係数 w を次式で求めることができます。

Vol7-10.png

では 、Pythonで計算してみましょう。ここで np.linalg.inv() は逆行列を求める関数です。

import numpy as np
# 白菜、大根の数量、定数項
X=np.array([
[ 6., 3., 1.],
[ 2., 5., 1.],
[ 1., 4., 1.],
])
# 総重量
y=np.array([[23.], [13.], [9.]])
# 回帰係数
w = np.linalg.inv(X.T.dot(X)).dot(X.T.dot(y))
print(u'回帰係数')
print(w)
print(u'予測重量')
print(X.dot(w))

(実行結果)

回帰係数
[[ 3.]
[ 1.]
[ 2.]]
予測重量
[[ 23.]
[ 13.]
[ 9.]]

結果

Vol7-11.png

求めた回帰係数より、この予測モデルは、次のようになります。

Vol7-12.png

つまり、白菜一個の重さが 3kg、大根一本の重さは 1kg、木箱の重さは 2kg ということです。

検証

ここまで、回帰係数を求めて予測モデルを構築しました。
予測モデルの構築に使ったデータをここでは学習データと呼びます。

構築した予測モデルを使って、学習データとは別の検証データで予測してみます。
検証データで予測するときは、学習データから求めた回帰係数をそのまま使います。

検証データ
Vol7-13.png

さっそくPythonで予測してみます。

import numpy as np
# 白菜、大根、定数項
X2=np.array([
[ 6., 7., 1.],
[ 4., 4., 1.],
[ 2., 2., 1.],
])
# 総重量
y2=np.array([[28.], [13.], [11.]])
# 予測
yhat = X2.dot(w)
print(u'予測重量')
print(yhat)

(実行結果)


予測重量
[[ 27.]
[ 18.]
[ 10.]]

予測結果
Vol7-14.png

そこそこ近い値を予測できています。
「そこそこ」といった予測誤差の大きさを定量的に示す指標として、次のRMSEが使われます。

RMSE(Root Mean Squared Error)

RMSEは、予測値と実測値の予測誤差の大きさを示す指標です。 値が大きいほど予測誤差が大きく、
ゼロに近いほど予測誤差が小さいことを意味します。

Vol7-15.png

では、学習データでのRMSEと検証データでのRMSEを求めます。

(前述のコードの続きです)

# RMSEを計算する関数
def RMSE(y, yhat):
    e = y-yhat
    n = e.shape[0]
    return np.sqrt(np.sum(e*e)/n)

# 学習データでの予測値
yhat = X.dot(w)
print(u'RMSE(学習データ) : %.1f' % RMSE(y, yhat))

# 検証データでの予測値
yhat = X2.dot(w)
print(u'RMSE(検証データ) : %.1f' % RMSE(y2, yhat))

(実行結果)

RMSE(学習データ) : 0.0
RMSE(検証データ) : 3.0

相関係数最大化

散布図の横軸に実測値、縦軸に予測値をとると、予測誤差を可視化することができます。
予測誤差が小さければ、実測値と予測値の相関係数が高くなり、プロットは対角線上に並びます。
予測誤差が大きければ、実測値と予測値の相関係数が低くなり、プロットは対角線からのバラツキが
大きくなります。

Vol7-16.png

重回帰分析は、実測値と予測値の差の平方和である残差平方和を最小とする回帰係数を求めました。
残差平方和を最小とするということは、次図のように実測値の偏差ベクトルと予測値の偏差ベクトルの
成す角を最小化するということ、つまり、実測値と予測値の相関係数を最大化するということです。

Vol7-28.png

Vol7-99.png

重回帰分析は、実測値と予測値の相関係数を最大化する手法と考えることができます。

scikit-learn で重回帰分析

NumPy 関数や機械学習ライブラリ scikit-learn の LinearRegression でも回帰係数を求めることができます。

import numpy as np
from sklearn.linear_model import LinearRegression
# 総重量
y=np.array([[23.], [13.], [9.]])

### NumPy
# 学習データ(定数項が必要)
X=np.array([
[ 6., 3., 1.],
[ 2., 5., 1.],
[ 1., 4., 1.],
])
w = np.linalg.lstsq(X,y)[0]
print('=== NumPy ===')
print('回帰係数')
print(w)

### scikit-learn
# 学習データ(定数項は不要)
X=np.array([
[ 6., 3.],
[ 2., 5.],
[ 1., 4.],
])
# 検証データ(定数項は不要)
X2=np.array([
[ 6., 7.],
[ 4., 4.],
[ 2., 2.],
])
# モデル構築
clf = LinearRegression()
clf.fit(X, y)
print('\n=== scikit-learn ===')
print(u'傾き', clf.coef_)
print(u'切片', clf.intercept_)
print(u'予測重量(学習データ)')
print(clf.predict(X))
print(u'予測重量(検証データ)')
print(clf.predict(X2))

(実行結果)


=== NumPy ===
回帰係数
[[ 3.]
[ 1.]
[ 2.]]
=== scikit-learn ===
傾き [[ 3. 1.]]
切片 [ 2.]
予測重量(学習データ)
[[ 23.]
[ 13.]
[ 9.]]
予測重量(検証データ)
[[ 27.]
[ 18.]
[ 10.]]

今回はここまでです。次回は多重共線性とL1正則化を予定しています。

  • LINE
  • Mail