LoginSignup
7
4

More than 1 year has passed since last update.

Bagging や Blending で予測の分散を考慮する

Last updated at Posted at 2022-03-28

回帰モデルで予測の分散を考慮できるモデルとして、ガウス過程回帰があります。でもあれはあれでけっこうクセがあると思ってて、他の回帰モデルでも予測の分散を考慮できたらなと思ってました。そこで、アンサンブル手法として知られる Bagging や Blending を使えば良いと思ったので試してみました。

予測したい関数

ここでは、単純のため以下のような1変数関数を用います。

import numpy as np

f = lambda x: 0.05*x+0.2*np.sin(x) + 0.3*np.cos(2.1*x) + 0.5*np.sin(0.61*x) + 0.2*np.sin(x/3.1) + 0.1*np.sin(5.1*x)

図示したらこんな感じ。

import matplotlib.pyplot as plt

x_domain = np.linspace(-30, 30, 500) # 関数の範囲
plt.plot(x_domain, f(x_domain))
plt.show()

Bagging_や_Blending_で予測の分散を考慮する_3_0.png

下記のように訓練データを取得して、それを学習させてみたいと思います。

x_train = np.linspace(-20, 20, 40) # 訓練データ

plt.scatter(x_train, f(x_train), label="training data")
plt.plot(x_domain, f(x_domain), label="true function")
plt.legend()
plt.show()

Bagging_や_Blending_で予測の分散を考慮する_5_0.png

ガウス過程回帰

GaussianProcessRegressor を用いて、予測および予測の分散を求めます。

from sklearn.gaussian_process import GaussianProcessRegressor
from sklearn.gaussian_process.kernels import RBF

kernel = 1.0 * RBF(length_scale=1.0, length_scale_bounds=(1e-1, 10.0))
model = GaussianProcessRegressor(kernel=kernel, random_state=0)
model.fit(x_train.reshape(-1, 1), f(x_train))
y_pred, y_std = model.predict(x_domain.reshape(-1, 1), return_std=True)

結果の図示

plt.scatter(x_train, f(x_train), label="training data")
plt.plot(x_domain, f(x_domain), label="true function")
plt.plot(x_domain, y_pred, label="mean prediction")
plt.fill_between(x_domain, y_pred-y_std, y_pred+y_std, alpha=0.5, label="prediction std")
plt.legend()
plt.show()

Bagging_や_Blending_で予測の分散を考慮する_9_0.png

こんな感じで、ガウス過程って、けっこう過剰適合(過学習)しがちで、そのくせ内挿は自信過剰で、外挿はテキトーすぎる印象があるんですよねー(個人の感想です)。

アンサンブル学習器から予測の分散を求める関数

scikit-learnには数多くのアンサンブル学習器が用意されていて、平素より大変お世話になっておりますが、こんな関数が用意されてるともっと嬉しい気がするんです。

def predict_std(model, X):
    y_pred = []
    for base_model in model.estimators_:
        y_pred.append(base_model.predict(X))
    
    return np.array(y_pred).std(axis=0)

Blending

機械学習界隈で「Blending」と呼ばれるアンサンブルは VotingRegressor として実装されています。それを使って、たとえば MLPRegressor をアンサンブルしてみます。

from sklearn.ensemble import VotingRegressor
from sklearn.neural_network import MLPRegressor

model = VotingRegressor(
    estimators = [(str(x), 
                   MLPRegressor(
                       hidden_layer_sizes=[100 for x in range(10)],
                       max_iter=1000,
                       #early_stopping=True
                       )
    ) for x in range(100)]
)

model.fit(x_train.reshape(-1, 1), f(x_train))
y_pred = model.predict(x_domain.reshape(-1, 1))
y_std = predict_std(model, x_domain.reshape(-1, 1))

図示すると次のようになります。うーん、まだ不十分な感じだけど、ガウス過程回帰よりは、良いんじゃないですかね。

plt.scatter(x_train, f(x_train), label="training data")
plt.plot(x_domain, f(x_domain), label="true function")
plt.plot(x_domain, y_pred, label="mean prediction")
plt.fill_between(x_domain, y_pred-y_std, y_pred+y_std, alpha=0.5, label="prediction std")
plt.legend()
plt.show()

Bagging_や_Blending_で予測の分散を考慮する_16_0.png

MLPRegressorには、過剰適合を防ぐ early_stopping=True というオプションがあるのですが、それを入れるとさらにザックリとした予測になります。

Bagging

次は Bagging です。

from sklearn.ensemble import BaggingRegressor
from sklearn.neural_network import MLPRegressor

model = BaggingRegressor(
    base_estimator=MLPRegressor(
        hidden_layer_sizes=[100 for x in range(10)],
        max_iter=1000,
        #early_stopping=True
        ),
    n_estimators=100
    )

model.fit(x_train.reshape(-1, 1), f(x_train))
y_pred = model.predict(x_domain.reshape(-1, 1))
y_std = predict_std(model, x_domain.reshape(-1, 1))

結果の図示

plt.scatter(x_train, f(x_train), label="training data")
plt.plot(x_domain, f(x_domain), label="true function")
plt.plot(x_domain, y_pred, label="mean prediction")
plt.fill_between(x_domain, y_pred-y_std, y_pred+y_std, alpha=0.5, label="prediction std")
plt.legend()
plt.show()

Bagging_や_Blending_で予測の分散を考慮する_20_0.png

うん、このくらいが一番良い気がしますね(個人の感想です)。

7
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4