-Python- 過学習

過学習は学習データに適応しすぎて,未知のデータへの当てはまりが悪くなる(汎化性能が上がらない)状態です.機械学習において,過学習を抑えて汎化性能を確保することは重要な課題です.

まずは,過学習に関する例を示します.
     y = 4 x^3 - 3 x^2 + 2 x - 1
にバラつきを与えた学習データを30個,テストデータを70個(計 100個)用意します.

# import modules

import matplotlib.pyplot as plt
import numpy as np
 
# data of y = 4 * x**3 - 3 * x**2 + 2 * x - 1
x = np.random.rand(100, 1)          # Make 100 random numbers up to 0-1
x = x * 2 - 1                       # Change the value range to -2 - 2
 
y = 4 * x**3 - 3 * x**2 + 2 * x - 1
 
# Add a random number with standard normal distribution \
#                        (average 0, standard deviation 1)
y += np.random.randn(100, 1)
 
# Learning data
x_train = x[:30]
y_train = y[:30]
 
# Test data
x_test = x[30:]
y_test = y[30:]
 
# Graph
plt.subplot(2, 2, 1)
plt.scatter(x, y, marker='+')
plt.title('all')
 
plt.subplot(2, 2, 2)
plt.scatter(x_train, y_train, marker='o')
plt.title('train')
 
plt.subplot(2, 2, 3)
plt.scatter(x_test, y_test, marker='x')
plt.title('test')
 
plt.tight_layout()
 
plt.show()
 
実行結果は以下のようになります.

f:id:HidehikoMURAO:20181014164023p:plain

 
表示された学習データ(train)で学習を行い,テストデータ(test)で検証を行うことを考えてみます.
 
上記のスクリプトを下記のように書き換えます.
 
実行結果は以下のようになります.
[[  33.12748576   67.83281725  -67.37731498 -128.89164356   41.04562681
    76.0640166    -4.31257678  -18.44875657    2.7899172 ]]
[-0.13015289]
0.9381600076256997

f:id:HidehikoMURAO:20181014164138p:plain

R^2決定係数は0.9381600076256997となり,かなり良い数値です.これをテストデータでも実行するには,以下のように追記します.
 
# import modules
import matplotlib.pyplot as plt
import numpy as np
from sklearn import linear_model
 
# data of y = 4 * x**3 - 3 * x**2 + 2 * x - 1
x = np.random.rand(100, 1)          # Make 100 random numbers up to 0-1
x = x * 2 - 1                       # Change the value range to -2 - 2
 
y = 4 * x**3 - 3 * x**2 + 2 * x - 1
 
# Add a random number with standard normal distribution \
#                        (average 0, standard deviation 1)
y += np.random.randn(100, 1)
 
# Make learning data
x_train = x[:30]
y_train = y[:30]
 
# Make Test data
x_test = x[30:]
y_test = y[30:]
 
# Learning
X_Train = np.c_[x_train**9, x_train**8, x_train**7,
                x_train**6, x_train**5, x_train**4,
                x_train**3, x_train**2, x_train]
 
model = linear_model.LinearRegression()
model.fit(X_Train, y_train)
 
# Verification
X_TEST = np.c_[x_test**9, x_test**8, x_test**7,
                x_test**6, x_test**5, x_test**4,
                x_test**3, x_test**2, x_test]
 
# Graph
print(model.coef_)
print(model.intercept_)
print(model.score(X_TEST, y_test))
 
plt.scatter(x_test, y_test, marker='+')
plt.scatter(x_test, model.predict(X_TEST))
 
plt.show()
 
実行結果その1
[[ 118.0867761   -47.6245528  -229.96293273   76.30701546  147.25359427
   -39.73343818  -28.7156535     4.15097503    3.83876708]]
[-1.21608296]
0.768352666952984

f:id:HidehikoMURAO:20181014164210p:plain

実行結果その2
[[ 233.39190604   27.12584341 -388.02570466  -19.39094383  209.8618352
   -10.3033822   -40.0906553     2.59187198    4.75046926]]
[-0.93698258]
0.21683664842035388

f:id:HidehikoMURAO:20181014164223p:plain

予測式のデータを保存していないので,毎回違う結果が得られますが,実行結果その1ではR^2決定係数が0.768352666952984となり,若干の低下が生じています.実行結果その2では,0.21683664842035388となっており,全く上手く予測ができておらず,過学習の状態となっています.
 
一般的に過学習が発生するのは,学習データに対してモデルが複雑すぎる(表現力がありすぎる)ことが原因です.今回の場合は,元のしきが4次式のところを9次式で回帰したので,このような結果となりました.
対処方法としては,データを増やす,モデルの複雑度を削減するといった対応が考えられますが,試行錯誤が必要でなかなか大変です.そこで,アルゴリズムで対処する方法も開発されており,次回の投稿で罰則付き回帰を示します.