yProcessingClub

すみません、許してください

残差のランダム性を確認する

はじめに

機械学習の勉強をしたいが連日の残業の疲れでしんどいため,寝ながらiPad機械学習の動画を見ていた.
すると,以下のようなスライドが出てきた.

【数学嫌いと学ぶデータサイエンス】第2章-第6回-モデル化の4つの注意点1残差確認2分散不均一 - YouTube
f:id:Yuri-Processing-Club:20211002114107j:plain

作成したモデルがデータに当てはまっているかを評価する場合に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)

数式に表すと以下のようになる.
y=0.5x^2 + \varepsilon

データの可視化
# プロット
plt.scatter(data_x, data_y)
plt.xlabel('x')
plt.ylabel('y')
plt.show()

f:id:Yuri-Processing-Club:20211002150311p:plain

単回帰分析

単回帰分析の準備
# 回帰分析
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]

f:id:Yuri-Processing-Club:20211002150641p:plain
数式に表すと以下のようになる.
\hat {y}=4.93x-6.27

単回帰分析の残差を求める
# 残差を求める
# 残差は実際のデータの値と予測した値との差
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()

f:id:Yuri-Processing-Club:20211002151239p:plain

残差はランダムとなるはずだが,上に凸の二次関数のような形になっており,規則性を持っていることが分かる.
モデルが上手く行っていない証だ.

多項式回帰分析

多項式回帰分析の準備
# 多項式回帰分析
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]
f:id:Yuri-Processing-Club:20211002152401p:plain

数式に表すと以下のようになる.
\hat {y}=0.49x^2 + 0.048x + 1.74

真の式が以下であるので,いい感じにモデル化が出来ていそう.
y=0.5x^2 + \varepsilon

多項式回帰分析の残差を求める
# 残差を求める
# 残差は実際のデータの値と予測した値との差
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()

f:id:Yuri-Processing-Club:20211002152838p:plain

残差がランダムとなっており,モデル化が上手く行っていることが分かった.

まとめ

今回は残差を可視化することでモデルを評価した.
引き続き機械学習及び統計学と和解をしていく.

なお,pythonを数週間ぶりに触ったら書き方が完全に揮発してしまっていてビビった.
毎日とは言わずとも一週間に一回くらいは触っておかないとヤバいわね.