【scikit-learn】ラッソ回帰、リッジ回帰で過学習の改善・防止

Pythonモジュール「scikit-learn」のラッソ回帰、リッジ回帰で過学習を改善しながら回帰分析する方法についてまとめました。

【回帰】重回帰分析

まずは、何の工夫もせずにそのまま重回帰分析をしてみます。

# -*- coding: utf-8 -*-
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn import linear_model
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd

sns.set() # seabornのスタイルをセット

# 糖尿病患者のデータセットをロード
dataset = datasets.load_diabetes()

# 説明変数
X = dataset.data

# 目的変数
y = dataset.target

# 学習用、テスト用にデータを分割(1:1)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=0)

# 予測モデルを作成(重回帰)
clf = linear_model.LinearRegression()

# 学習
clf.fit(X_train, y_train)

# 回帰係数と切片の抽出
a = clf.coef_
b = clf.intercept_

# 回帰係数
print("回帰係数:", a)
print("切片:", b)
print("決定係数(学習用):", clf.score(X_train, y_train))
print("決定係数(テスト用):", clf.score(X_test, y_test))

"""
回帰係数: [ -20.41129305 -265.88594023  564.64844662  325.55650029 -692.23796104
  395.62249978   23.52910434  116.37102129  843.98257585   12.71981044]
切片: 154.3589882135515
決定係数(学習用): 0.5730746555685652
決定係数(テスト用): 0.4377492256245158
"""

結果(予測精度)は学習データで57%、テストデータでは43%となり過学習に陥っています。
過学習とは、訓練データにモデルが稼業適合(オーバーフィッティング)しすぎているため、学習データとテストデータの結果に差が大きく出て、精度が落ちてしまう現象です。
過学習を防ぐには、「訓練データの数を増やす」「正則化などで学習時に一定の制約を与える」「質の良い説明変数のみを使う」などの対策を施します。
訓練データを増やすという対策は実際には難しいので、正則化や説明変数の選択という手法をまず取ることが多いです。

【過学習防止法】Lasso回帰(L1正則化)、リッジ回帰(L2正則化)

リッジ回帰は、直線回帰に正則化項(L2ノルム)を加えて、稼業適合(オーバーフィッティング)をしにくくした回帰分析です。

# -*- coding: utf-8 -*-
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn import linear_model
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd

sns.set() # seabornのスタイルをセット

# 糖尿病患者のデータセットをロード
dataset = datasets.load_diabetes()

# 説明変数
X = dataset.data

# 目的変数
y = dataset.target

# 学習用、テスト用にデータを分割(1:1)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.7, random_state=0)

# 予測モデルを作成(リッジ回帰)
clf = linear_model.Ridge()

# 学習
clf.fit(X_train, y_train)

# 回帰係数と切片の抽出
a = clf.coef_
b = clf.intercept_

# 回帰係数
print("回帰係数:", a)
print("切片:", b)
print("決定係数(学習用):", clf.score(X_train, y_train))
print("決定係数(テスト用):", clf.score(X_test, y_test))

"""
回帰係数: [ -20.41129305 -265.88594023  564.64844662  325.55650029 -692.23796104
  395.62249978   23.52910434  116.37102129  843.98257585   12.71981044]
切片: 154.3589882135515
決定係数(学習用): 0.3983270129832158
決定係数(テスト用): 0.3345645490979842
"""

学習データとテストデータの結果の差が小さくなり、過学習が改善されています。

# -*- coding: utf-8 -*-
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn import linear_model
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd

sns.set() # seabornのスタイルをセット

# 糖尿病患者のデータセットをロード
dataset = datasets.load_diabetes()

# 説明変数
X = dataset.data

# 目的変数
y = dataset.target

# 学習用、テスト用にデータを分割(1:1)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.7, random_state=0)

# 予測モデルを作成(Lasso回帰)
clf = linear_model.Lasso()

# 学習
clf.fit(X_train, y_train)

# 回帰係数と切片の抽出
a = clf.coef_
b = clf.intercept_

# 回帰係数
print("回帰係数:", a)
print("切片:", b)
print("決定係数(学習用):", clf.score(X_train, y_train))
print("決定係数(テスト用):", clf.score(X_test, y_test))

"""
回帰係数: [  0.          -0.         397.28850539   0.           0.
   0.          -0.           0.         472.25346364   0.        ]
切片: 151.99424541715777
決定係数(学習用): 0.4765923813915492
決定係数(テスト用): 0.3743169923017488
"""

過学習が少し改善されています。また、相関値の高い変数のうち一方が排除されやすいためモデル式も簡単になります。

関連記事
2 【Scikit-learn】機械学習入門・使い方
3 【機械学習入門】アルゴリズム&プログラミング
4 【Python入門】サンプル集

コメント