SEワンタンの独学備忘録

IT関連の独学した内容や資格試験に対する取り組みの備忘録

【機械学習】入門⑦ モデルを生成してみる Pythonで学ぶ「教師あり学習」 回帰編

回帰編の基本は今回で完了する予定です。

モデルを考えてみる

データセットに対する最適なグラフの形は?

前回のデータセットでは交差検証法により以下のようなモデルを生成しました。

f:id:wantanBlog:20200225003848p:plain

元々このデータは横軸は人口 1 人当たりの犯罪発生数、縦軸が所有者が占有している家屋の$ 1000単位の中央値だったので縦軸は一定の値に収束することが予測できます。
なので、上記のモデルのように途中から上がることは考えにくく、一定の値以降は収束するような以下のモデルになるのではないかと常識的な知識で予測できます。

f:id:wantanBlog:20200307011247p:plain


ここでモデルに適切そうな関数モデルを考えてみます。

・関数モデルの選定

# ライブラリのインポート
import numpy as npy
import matplotlib.pyplot as plt
# Jupiter Notebookで結果を表示するためのおまじない
%matplotlib inline
# 関数の定義
def f1(x):
    return npy.exp(x)

def f2(x):
    return npy.exp(-x)

def f3(x):
    return -npy.exp(x)

def f4(x):
    return -npy.exp(x)

# X軸に0から9までの配列
xline = npy.linspace(-5,5,50)
yline1 = f1(xline)
yline2 = f2(xline)
yline3 = f3(xline)
yline4 = f4(xline)

# pltに要素を設定する
plt.plot(xline, yline1, color ='black', label='$w=1$')
plt.plot(xline, yline2, color ='red', label='$w=2$')
plt.plot(xline, yline3, color ='blue', label='$w=3$')
plt.plot(xline, yline4, color ='green', label='$w=4$')

# 凡例を表示する
plt.legend(loc="upper left")
# y軸の表示範囲を設定する
plt. ylim(- 50, 50)
# タイトルを表示する
plt.title('$SampleGraph$')
# X軸に名前を付ける
plt.xlabel('$x$')
# Y軸に名前を付ける
plt.ylabel('$y$')
# グリッドを表示する
plt.grid(True)

# グラフを描写する
plt.show()

・出力結果

f:id:wantanBlog:20200307012641p:plain


グラフの形としては二つ目の指数関数のグラフと形が近いことが分かり、このグラフに切片を加えることで想定したモデルに近づきます。

・想定モデル

# ライブラリのインポート
import numpy as npy
import matplotlib.pyplot as plt
# Jupiter Notebookで結果を表示するためのおまじない
%matplotlib inline
# 関数の定義

def f2(x):
    return 1 + 5*npy.exp(-x)


# X軸に0から9までの配列
xline = npy.linspace(0,5,50)
yline2 = f2(xline)

# pltに要素を設定する
plt.plot(xline, yline2, color ='red', label='$w=2$')


# 凡例を表示する
plt.legend(loc="upper left")
# y軸の表示範囲を設定する
plt. ylim(0, 10)
# タイトルを表示する
plt.title('$SampleGraph$')
# X軸に名前を付ける
plt.xlabel('$x$')
# Y軸に名前を付ける
plt.ylabel('$y$')
# グリッドを表示する
plt.grid(True)

# グラフを描写する
plt.show()

・出力結果

f:id:wantanBlog:20200307014338p:plain

このような関数を適用するとそれらしいモデルの形が設定できそうです。

オリジナルモデルの作成

オリジナルモデルの実装

まずは実装を行います。モデルは以下を適用します。

f:id:wantanBlog:20200307020614p:plain


・モデル実装

# オリジナルモデル
import numpy as npy
import matplotlib.pyplot as plt
from scipy.optimize import minimize
%matplotlib inline

#ボストン住宅価格データセットの読み込み
from sklearn.datasets import load_boston

# モデル関数
def model_func(x, w):
    y = w[0] + w[1] * npy.exp(-w[2]*x)
    return y

# モデルのグラフ表示
def show_model_func(w):
    xb = npy.linspace(X_min, X_max, 100)
    y = model_func(xb, w)
    plt.plot(xb, y, c=[.5, .5, .5],lw=4)

# MSEの導出
def mse_model_func(w, x, t):
    y = model_func(x, w)
    mse = npy.mean((y - t)**2)
    return mse

# 最適化パラメータの導出
def fit_model_func(w_init, x, t):
    result = minimize(mse_model_func, w_init, args=(x,t),method="powell")
    return result['x']

boston = load_boston()
#説明変数
X_array = boston.data
#目的変数
y_array = boston.target

X = npy.array([X_array[:,0][0:100]])
Y = y_array[0:100]
xline = X[0]
yline = Y

X_min = min(xline)
X_max = max(xline)

plt.figure(figsize=(4,4))
W_init=[10, 1 ,0]
W = fit_model_func(W_init, xline, yline)
print("w0={0:.1f}, w1={1:.1f},w2={2:.1f}".format(W[0],W[1],W[2]))

show_model_func(W)
plt.plot(xline,yline,marker='o',linestyle='None',markeredgecolor='black',color='cornflowerblue')
plt.grid(True)
mse = mse_model_func(W, xline, yline)
print("SD={0:.2f}cm".format(npy.sqrt(mse)))
plt.show()

・出力結果

w0=16.4, w1=12.0,w2=5.6
SD=4.62cm

f:id:wantanBlog:20200307020221p:plain

ライブラリscipy.optinize

今回は最適パラメータwを求めるためにライブラリを活用しました。

Pythonのscipy.optinizeminimize関数により求めています。

    result = minimize(mse_model_func, w_init, args=(x,t),method="powell")

第一引数にモデル関数のmse_model_func。
第二引数にデータセット。
第三引数に最適化手法をそれぞれ設定します。

ここでの最適化手法のpowell法は最適化手法の一つです。

非線形連立方程式の解、あるいは連続最適化問題の関数の極大・極小解を見つけるためのアルゴリズムである

引用元:準ニュートン法 - Wikipedia

モデル関数

グラフの形を決める関数です。

# モデル関数
def model_func(x, w):
    y = w[0] + w[1] * npy.exp(-w[2]*x)
    return y
モデルのグラフ表示

モデル関数のグラフ描写用の関数です。

# モデルのグラフ表示
def show_model_func(w):
    xb = npy.linspace(X_min, X_max, 100)
    y = model_func(xb, w)
    plt.plot(xb, y, c=[.5, .5, .5],lw=4)
MSEの導出

当該関数のMSE(誤差)を導出するための関数です。

# MSEの導出
def mse_model_func(w, x, t):
    y = model_func(x, w)
    mse = npy.mean((y - t)**2)
    return mse
最適化パラメータの導出

先ほどのライブラリを用いたパラメータの導出関数です。

# 最適化パラメータの導出
def fit_model_func(w_init, x, t):
    result = minimize(mse_model_func, w_init, args=(x,t),method="powell")
    return result['x']
結果としては

出力結果を再掲します。

w0=16.4, w1=12.0,w2=5.6
SD=4.62cm

f:id:wantanBlog:20200307020221p:plain

グラフの形としてはかなりそれらしい形になりました。
SDは4.62cmで、前回のガウス関数を用いたモデルよりは値は大きくなっているので、今回のデータセットとしては前回のモデルの方が優れていると判断できるようです。

このようにデータの散布図からのモデルの概形が予測できる場合には自身で関数を考えて適用してみるような手法もあるようです。


また、自身で考えたモデルに対しても前回のガウス関数のモデルのように検証を行うのは有効です。


さて、長らく続きましたが回帰編は一旦これで終了とします。
まぁもちろん全然深くまではやり切れていないですが、基本的な流れは少しは分かったかなと思います。
次回以降は教師あり学習の中の「分類」を扱う予定です。

・今回のソース
python_dev/Supervised_learning7.ipynb at master · wantanblog/python_dev · GitHub