ファイナンス機械学習:アンサンブル法 機械学習モデルのエラーの要因とバギング

機械学習モデルのエラーの原因は、アンダーフィットを引き起こすバイアスと、オーバーフィッティングとなるバリアンス、最後に観測値に入ってくる雑音が主な三つである。
 バイアスでは、仮定が非現実であることから、アルゴリズムが入力変数の特徴と出力変数結果の関係を見つけ出せない。
 バリアンスは、アルゴリズムの感度が高すぎて、入力の訓練データの微細な変化に反応しているので、テストデータで全く違う結果を示してしまう。アルゴリズムは、入力訓練データのノイズをシグナルと誤認している場合が多い。
 雑音は観測データに入ってくる予測不可能な変化や、測定法による誤差でありモデルによって説明できないものである。
 観測値からなる訓練データセット$${\{x_i\},i=1,\dots,N}$$を変数とする、結果$${\{y_i\},1,\dots,N}$$が、ある関数$${f[x]}$$で関連づけられるとすれば、これはホワイトノイズ$${\epsilon: \epsilon_i=N(0,\sigma_{\epsilon_i}^2)}$$を使い、
$${y=f[x]+\epsilon}$$
と書ける。
 $${f[x]}$$に最も近い$${\hat{f}[x]}$$を推定するのが目的な場合は、推定誤差のバリアンス$${E[(y_i -\hat{f}[x_i])^2]}$$を最小にするべきである。
ある統計量$${z}$$に対して$${E[z]=\bar z}$$とおけば、
$${Var[z]=E[(z-\bar z)^2]=E[z^2] -2E[z]E[\bar z] + E[\bar z^2]=E[z^2]-2\bar z^2 + \bar z^2=E[z^2]-E^2[z] }$$。
これを用いて、推定誤差をバイアス-バリアンス-ノイズ分解する。
$${E[(y_i -\hat{f}[x_i])^2]=\displaystyle{E[y_i^2 - 2y_i\hat f[x_i] + \hat f^2[x_i]]}}$$
$${\displaystyle{=E[y_i^2]-2E[y_i]E[\hat f[x_i]] +E[\hat f[x_i]]}}$$
$${\displaystyle{ = E^2[y_i] + Var[y_i] -2E[y_i]E[\hat f[x_i]] + E^2[f[x_i]] + Var[\hat f[x_i]]}}$$
$${\displaystyle{ =(E[y_i] - E[\hat f[x_i]])^2 + Var[\hat f[x_i]] + \sigma_\epsilon^2}}$$
ここで、$${E[y_i]-E[\hat{f}[x_i]]}$$はバイアス、$${V[\hat{f}[x_i]]}$$はバリアンスである。
 アンサンブル法は、弱学習器の集合を組み合わせることで、バイアスとバリアンスの両方、または片方を減少させることができると期待されている。

バギング

 ブーストラップ抽出により、N個の推定器に与える訓練データセットを作成し訓練する。このN個の訓練は独立に行われ、並列化できるのが利点である。結果はN個の予測器の結果は重みなしの平均、もしくは多数決で与えられる。
 このバギングは、バリアンスを下げることができる。
 各推定器予想結果$${\phi_i[c]}$$であれば、単純平均のバギングの推定結果は$${\displaystyle{\frac{1}{N}\sum^N_{i=1}\phi_i[c]}}$$で与えられる。
このバリアンス$${\displaystyle{Var[\frac{1}{N}\sum^N_{i=1}\phi_i[c]]}}$$は、バギングの推定器の数$${N}$$、各予測の分散の平均値$${\bar\sigma^2=\displaystyle{\frac{1}{N}\sum^N_{i=1}\sigma_i^2}}$$、各推定器結果の相関係数の平均$${\bar{\rho}}$$で与えられる。
 
$${\displaystyle{\sum^N_{i=1}\sigma_i^2=\sum^N_{i=1}\bar\sigma^2=N\bar\sigma^2}}$$
$${\displaystyle{\sum^N_i\sum^N_{j\ne i }\bar\sigma^2\bar\rho = \sum^N_i\sum^N_{j \ne i}\sigma_i \sigma_j \rho_{i,j} }}$$より、
$${\displaystyle{ \bar\rho=\frac{\sum^N_i\sum^N_{j\ne i }\sigma_i\sigma_j\rho_{i,j}}{\bar\sigma^2N(N-1)}}}$$
を使い、
$${\displaystyle{Var[\frac{1}{N}\sum^N_{i=1}\phi_i[c]] = \frac{1}{N^2}\sum^N_{i=1}\sum^N_{j\ne i }\sigma_{ij} = \frac{1}{N^2}\sum^N_{i=1}(\sigma_i^2 + \sum^N_{j \ne i}\sigma_i\sigma_j\rho_{ij})}}$$
$${\displaystyle{=\frac{1}{N^2}\sum^N_{i=1}(\bar\sigma^2 + \sum^N_{j \ne i}\bar\sigma^2\bar\rho) = \frac{\bar\sigma^2 + (N-1)\bar\sigma^2\bar\rho}{N}}}$$
$${\displaystyle{=\bar\sigma^2\{(1-\frac{1}{N})\bar\rho + \frac{1}{N}\}}}$$
ここで、$${\rho\rightarrow 1}$$にすると、
$${\displaystyle{Var[\frac{1}{N}\sum^N_{i=1}\phi_i[c]] \rightarrow \bar\sigma^2 }}$$で、結果のバリアンスは何も向上されない。
よって、$${\bar\rho<1}$$の時のみ、バギングは有効である。
 同時発生のあるイベントサンプルを扱うときに、逐次ブーストスラップを導入し、独立性のあるサンプルを増やしたのは、この$${\bar\rho}$$を減らすためである。
 この関係をカラーマップで表すと、以下のようになる。
 ここで、$${\bar\sigma=0.2, 5\le N \le 30, 0.0 \le \bar\rho < 1.0}$$としている。

sig=0.2
NN=list(range(5,30))
rr=list(np.linspace(0.0,1.0,20))
var = pd.DataFrame(index=NN,columns=rr, dtype=float)
val=lambda N, rho,sig: sig*sig*(rho+(1.-rho)/N)
for N in NN:
    v=[]
    for rho in rr:
        v.append(val(N,rho,sig))
    var.loc[N]=v
fig, ax = plt.subplots(figsize=(11, 7))
cvar = ax.matshow(var, origin='lower',interpolation='nearest')
xlabels = ['.0','.25','.5','.75']
ylabels =['5','10','15','20','25']
ax.set_xticklabels(['']+xlabels)
ax.set_yticklabels(['']+ylabels)
ax.set_xlabel('rho')
ax.set_ylabel('N')
ax.tick_params(axis="x", bottom=True,labelbottom=True,labeltop=False)
fig.colorbar(cvar)
 
バギングのバリアンス変化

N器の独立した分類器の多数決で、k個のクラス分け予測をするバギング分類器の予測結果を$${0,1}$$とラベル付けをする。$${1}$$とラベル付けをするのは正しい予測である。
 分類器の正確度は、ラベルが$${1}$$と付けられる確率平均$${p}$$であり、各分類器でラベル$${1}$$と正確に予測できる確率は$${Np}$$で、分散は$${N(N-1)p}$$となる。
 10個の分類器で、$${k=3}$$のクラス[A,B,C]に分類し、正解はAとおけば、結果は多数決で与えられ
$${[A,B,C]=[4,3,3] \Rightarrow A :label=[1111000000] }$$
$${[A,B,C]=[4,1,5] \Rightarrow C :label=[1111000000] }$$
となる。ラベルの合計は同じだが、後者の場合は、5個の分類器でCの予想を出しているのでAは選ばれない。
 ラベルの合計を$${X}$$とすると、十分条件$${\displaystyle{X>\frac{N}{2}}}$$、必要条件$${\displaystyle{X>\frac{N}{k}}}$$が多数決で正しく予測が勝ち抜くために必要となる。
 この必要条件が満たされる確率$${\displaystyle{P[X>\frac{N}{k}]}}$$は、N個の分類器のうちi個がラベル1、残りが0のラベルとなる確率が$${{}n C_i(1-p)^{n-i}p^i}$$となるから、
$${\displaystyle{P[X>\frac{N}{k}] = 1 - P[X\le\frac{N}{k}]=1-\sum^{i\le\frac{N}{k}}_{i=0}{}nC_i(1-p)^{N-i}p^i}}$$
$${\displaystyle{=1-\sum^{i\le\frac{N}{k}}_{i=0}\frac{\Pi^{i-1}_{l=0}(N-l)}{i!}p^i(1-p)^{N-i}}}$$
 これを、$${k=2, 1\le N \le 100, 0.2\le p \le 0.8}$$で、$${N=\displaystyle{\frac{p}{(p-\frac{1}{k})^2}}}$$曲線とともに、カラーマップを使い、視覚化したのが以下の図である。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline

pp=list(np.linspace(0.2,0.8,120))
NN=list(range(1,101))
acc = pd.DataFrame(index=NN,columns=pp, dtype=float)
for N in NN:
    rho=[]
    for p in pp:
        val=getBgAcc(N,p,k=2.)
        rho.append(val)
    acc.loc[N]=rho
    
Nv=lambda p, k: p/(p-1./k)**2   
Np=[]
for p in pp:
    Np.append(Nv(p,k))

fig, ax = plt.subplots(figsize=(11, 7))
cacc = ax.matshow(acc, origin='lower',interpolation='nearest')
labels = ['.2','.3','.4','.5','.6','.7','.8']
plt.plot(Np)
plt.ylim(0,100)
ax.set_xticklabels(['']+labels)
ax.set_xlabel('p')
ax.set_ylabel('N')
ax.tick_params(axis="x", bottom=True,labelbottom=True,labeltop=False)
fig.colorbar(cacc)
バギングの正解率

これより、$${N>\displaystyle{\frac{p}{(p-\frac{1}{k})^2}}, p>\frac{1}{k}}$$で、正解率が向上していることがわかる。
 ただし、バギングは、ブースティングと違い、個々の学習器の正解率を変えない。よって、$${p<\frac{1}{k}}$$の時は、いくらNを増やしてもパフォーマンスは低いままである。

OOBスコアは、抽出されなかったデータを使ったN個全ての推定器の平均で与えられる。訓練用に抽出されないデータの集まりであるから、テストでのスコアの推定に使えるとされている。しかし、これも冗長性の高いデータな場合、相関も高いので、この値もまた本来の値よりも高く出やすい。

この記事が気に入ったらサポートをしてみませんか?