-Python- 汎化,過学習

最初に多項式回帰のアルゴリズムを示します.
多項式回帰とは,入力変数  x に対して出力  y x多項式関数で表されるというモデルです.簡単のために,入力 xが1次元と仮定し,多項式の次数が  d で与えられるとします.

f:id:HidehikoMURAO:20181115104917p:plain
ここで, \epsilonはノイズを表します.このとき線形回帰のときと同様に,最小二乗法により係数を決定します. w  x が与えられたときの予測値

f:id:HidehikoMURAO:20181115104929p:plain
 x w の関数  \hat{y} ( x, w) とみなして,訓練データの特徴量  x とターゲット  y に対して下式を計算することになります.

f:id:HidehikoMURAO:20181115104941p:plain
最初の式で,  x^{i} を  x_{i} で置き換えると

f:id:HidehikoMURAO:20181115104954p:plain
と同じになります.このことから,多項式回帰の最適化問題は,与えられた訓練データの特徴量  ( x_{1}, x_{2}, \cdot, x_{n} )^{T} について各要素の0次(つまり1)から  d 次のベキまでを並べた行列

f:id:HidehikoMURAO:20181115105007p:plain
を訓練データの特徴量行列として線形回帰を計算した場合と同じになります.実際に,x_i に対する予測値を  \hat{y_{i}} とし,  \hat{y} = ( y_{i}, y_{2}, \cdot, y_{n}) とすると,以下のようになります.

これを実装すると以下のようになります.

# Import Module
import linearreg
import numpy as np
 
# Definition of Class
class PolynomialRegression: 
    def __init__(self, degree): 
        self.degree = degree
    
    def fit(self, x, y): 
        x_pow = []
        xx = x.reshape(len(x), 1)
        for i in range(1, self.degree + 1): 
            x_pow.append(xx ** i)
        mat = np.concatenate(x_pow, axis = 1)
        linreg = linearreg.LinearRegression()
        linreg.fit(mat, y)
        self.w_ = linreg.w_
    
    def predict(self, x): 
        r = 0
        for i in range(self.degree + 1): 
            r += x ** i * self.w_[i]

 

        return r
 
アルゴリズム本体の実装は上記のようになります(以下の実行スクリプトでは,上記のスクリプトを polyreg.pyとしています).行列に当たるのは15行目の mat になります.mat を計算するために入力値(ベクトル)  x を1乗,2乗, ...と繰り返し計算してリストに格納しています.
そのリストに対して,np.concatenate することで,ベクトルを横につないだ行列を作っています.
その後に,以下の線形回帰のアルゴリズムを呼び出しています.
 
# Import Module
import numpy as np
from scipy import linalg
 
# Definition of Class
class LinearRegression: 
    def __init__(self): 
        self.w_ = None
    
    def fit(self, X, t): 
        Xtil= np.c_[np.ones(X.shape[0]), X]
        A = np.dot(Xtil.T, Xtil)
        b = np.dot(Xtil.T, t)
        self.w_ = linalg.solve(A, b)
    
    def predict(self, X): 
        if X.ndim == 1
            X = X.reshape(1, -1)
        Xtil= np.c_[np.ones(X.shape[0]), X]
        return np.dot(Xtil, self.w_)
 

計算結果は,データ属性の self.w_ に格納しています.

# Import Module
import polyreg
import linearreg
import numpy as np
import matplotlib.pyplot as plt
 
# Generate data
np.random.seed(0)
 
# Definition of Function
def f(x): 
    return 1 + 2 * x
 
x = np.random.random(10) * 10
y = f(x) + np.random.randn(10)
 
# Solving problem (Polynomial regression)
model = polyreg.PolynomialRegression(10)
model.fit(x, y)
 
# Drawing Graph
plt.scatter(x, y, color = "k")
plt.ylim([y.min() - 1, y.max() + 1])
xx = np.linspace(x.min(), x.max(), 300)
yy = np.array([model.predict(u) for u in xx])
plt.plot(xx, yy, color = "k")
 
# Solving problem (Linear regression)
model = linearreg.LinearRegression()
model.fit(x, y)
b, a = model.w_
x1 = x.min() - 1
x2 = x.max() + 1
plt.plot([x1, x2], [f(x1), f(x2)], color = "k", linestyle = "dashed")
 
plt.show()
 

実行時には,以下のような,行列の状態が良くないので,計算誤差が大きくなるという警告が出ますが,ここでは無視します.

Ill-conditioned matrix detected. Result is not guaranteed to be accurate.
Reciprocal condition number1.300313e-30
  self.w_ = linalg.solve(A, b)
objc[2384]: Class FIFinderSyncExtensionHost is implemented in both /System/Library/PrivateFrameworks/FinderKit.framework/Versions/A/FinderKit (0x7fff96079c90) and /System/Library/PrivateFrameworks/FileProvider.framework/OverrideBundles/FinderSyncCollaborationFileProviderOverride.bundle/Contents/MacOS/FinderSyncCollaborationFileProviderOverride (0x115488cd8). One of the two will be used. Which one is undefined.


実行結果は,以下のようになります.

f:id:HidehikoMURAO:20181113134210p:plain

上記のスクリプトでは,  y = 1 + 2 x + \epsilon (  \epsilon は乱数)に従う点を10個生成して訓練データとしています.それらを使用して多項式回帰と線形回帰のグラフを示しています.グラフにおいて,実線が多項式回帰で,破線が線形回帰です.このグラフでは,多項式回帰の結果は,与えられた点の全てを通過していますが,性能は別問題となります.例えば,多項式回帰では  x = 8 の時の予測値は上に大きくずれた値を示しますが,正解とはかけ離れた値です.

与えらえた訓練データを完璧に予想できるように学習したモデルが最適とは限らないということがわかります.機械学習システムの目的は,未知のデータに対して予測が可能になることです.このように未知のデータをどれくらい正しく予測できるのかという性能のことを汎化性能と呼びます.

上記のスクリプトでは, y = 1 + 2 x + \varepsilon ( \varepsilon は乱数)に従う点を10個生成して訓練データとしています.それらを使用して多項式回帰と線形回帰のグラフを示しています.グラフにおいて,実線が多項式回帰で,破線が線形回帰です.このグラフでは,多項式回帰の結果は,与えられた点の全てを通過していますが,性能は別問題となります.例えば,多項式回帰では  x = 8 の時の予測値は上に大きくずれた値を示しますが,正解とはかけ離れた値です.

与えらえた訓練データを完璧に予想できるように学習したモデルが最適とは限らないということがわかります.機械学習システムの目的は,未知のデータに対して予測が可能になることです.このように未知のデータをどれくらい正しく予測できるのかという性能のことを汎化性能と呼びます.

真の値  f(x) に対して,データD を使って予測した値を[\TeX: \hat{f}_D (x) ] で表すとします.データの集合Dが与えられたときに2乗誤差の平均は以下のようになります.

ここで E_D は考えられる入力データD全てについての平均ということです.左辺第一項はバイアスと呼ばれるもので,全てのデータについての予測値の平均と真の値との差の2乗になっています.すなわち,真の値が変わらない前提で観測データが変化したときに,xにおける予測値の平均を取ったものと,真の値の差がどのくらいあるかを意味します.第二項はバリアンスで,Dが変化したときの予測値 \hat{f} (x)の分散になっています.

予測誤差の平均 = バイアス + バリアンス

という関係が成り立っています.バイアスは観測データが変わったときに平均的にどのくらい予想できるかという値で,バリアンスはデータが変わったときにどのくらい予測値がばらつくかという値です.

上記の式のように予測誤差はバイアスとバリアンスの和になるので,バイアスだけを見てもモデルの良さを正しく判定することはできません.このことを示すために,以下のような関数が与えられたとして,この値を線形回帰と多項式回帰を使って予測することを試みてみます.

バイアスを理論的に求める代わりに,近似値を算出します.流れは以下のようになります.
0 ≦ x ≦ 5 の範囲に5点をランダムに取って,それらについて  f(x) = 1 / (1 + x) を計算する.
上記のデータを用いて線形回帰と多項式回帰をそれぞれ学習する.
0 から 5 まで 0.01 刻みに予測値を,線形回帰と多項式回帰のそれぞれについて計算する.
上記の1. 〜3. を10万回繰り返し,最後に0 から5 まで0.01 刻みに予測値の平均を,線形回帰と多項式回帰のそれぞれについて計算し図示する.