はじめに
機械学習の勉強をしたいが連日の残業の疲れでしんどいため,寝ながらiPadで機械学習の動画を見ていた.
すると,以下のようなスライドが出てきた.
作成したモデルがデータに当てはまっているかを評価する場合にMSEなどの誤差関数を用いることは知っていたが,残差のランダム性からも評価が行えるのだ.
上図のように,データが二次関数の場合に一次関数でモデル化しようとすると残差に規則性が出て上手くモデル化出来ていないことが分かるという点が面白く感じた.
今回はpythonの練習も兼ねて,この例を手元の環境で再現してみたいと思う.
流れは以下のような感じ.
二次関数+ランダム誤差のあるデータ列を作成
↓
一次関数で回帰分析
↓
残差をプロットして規則性があることを確認
↓
二次関数で回帰分析
↓
残差をプロットして規則性がないことを確認
実装
データの準備
データの準備
import numpy as np import matplotlib.pyplot as plt import pandas as pd # データの準備 x = np.linspace(0, 10) data_x = pd.DataFrame(x, columns=['x']) # 正解データの作成 A = 1/2 np.random.seed(seed=0) n = 3 * np.random.rand(len(data_x)) # data_x['x']に基づいて計算されるためSeries形式になる y = A * np.square(data_x['x']) + n y.name = 'y' # DataFrameに変換 data_y = pd.DataFrame(y)
数式に表すと以下のようになる.
単回帰分析
単回帰分析の準備
# 回帰分析 from sklearn.linear_model import LinearRegression # モデルの学習 lr = LinearRegression() lr.fit(data_x, data_y)
単回帰分析の可視化
# 可視化 plt.scatter(data_x, data_y, label="data") print(f'coef:{lr.coef_}') print(f'intercept_:{lr.intercept_}') plt.plot(data_x, lr.predict(data_x), label="pred", color=(1,0,0)) plt.xlabel('x') plt.ylabel('y') plt.legend() plt.show()
coef:[4.93765207]
intercept_:[-6.23763032]
数式に表すと以下のようになる.
単回帰分析の残差を求める
# 残差を求める # 残差は実際のデータの値と予測した値との差 e = lr.predict(data_x) - data_y plt.scatter(data_x, e) # 水平線 plt.hlines([0], 0, 10, linestyles="dashed", colors=["black"]) # x軸・y軸の範囲 plt.xlim(0, 10) plt.xlabel('x') plt.ylabel('resid') plt.show()
残差はランダムとなるはずだが,上に凸の二次関数のような形になっており,規則性を持っていることが分かる.
モデルが上手く行っていない証だ.
多項式回帰分析
多項式回帰分析の準備
# 多項式回帰分析 from sklearn.preprocessing import PolynomialFeatures model = PolynomialFeatures(degree = 2) data_x_poly = model.fit_transform(data_x) # モデルの学習 lr2 = LinearRegression() lr2.fit(data_x_poly, data_y)
多項式回帰分析の可視化
# 可視化 plt.scatter(data_x, data_y, label="data") print(f'coef:{lr2.coef_}') print(f'intercept_:{lr2.intercept_}') plt.plot(data_x, lr2.predict(data_x_poly), label="pred", color=(1,0,0)) plt.xlabel('x') plt.ylabel('y') plt.legend() plt.show()
coef:[0. 0.04846555 0.48891865]
intercept_:[1.74471503]
数式に表すと以下のようになる.
真の式が以下であるので,いい感じにモデル化が出来ていそう.
多項式回帰分析の残差を求める
# 残差を求める # 残差は実際のデータの値と予測した値との差 e = lr2.predict(data_x_poly) - data_y plt.scatter(data_x, e) # 水平線・垂直線 plt.hlines([0], 0, 10, linestyles="dashed", colors=["black"]) # x軸・y軸の範囲 plt.xlim(0, 10) plt.xlabel('x') plt.ylabel('resid') plt.show()
残差がランダムとなっており,モデル化が上手く行っていることが分かった.