02.4.2
スタッキング
StackingClassifier(estimators, final_estimator) がこの手順を内部で行います。このページでは深さ 3〜6 の決定木 4 本を重ねた例で、似たモデルばかりでは ROC-AUC がランダムフォレストの 0.86 に対して 0.74 と伸びないことを確かめ、「異なる種類のモデルを混ぜる」というスタッキングの要点を図で示します。スタッキングは Out-of-Fold 予測を使うので、交差検証 の「Fold を 1 つ外して学習し、外した Fold を予測する」流れを先に押さえてください。あわせて、ロジスティック回帰・決定木・SVM など複数の分類器の基本的な性質の違いを知っていると、どのモデルを 1 段目に並べるべきかが読めるようになります。
直感 #
病院で、内科・外科・放射線科の 3 人の医師がそれぞれ診断を出し、最後に総合診療医がその 3 つの診断を見て結論を出す。スタッキングはこの「診断の診断」です。1 段目の 3 人がベース学習器、総合診療医がメタ学習器で、メタ学習器は「放射線科の意見が外科と食い違うときは放射線科を信じる」といった重み付けをデータから学びます。ここで 1 つ落とし穴があります。総合診療医の訓練に「3 人が答えを知っている患者の診断」を使うと、3 人は正解を丸写しできるので、総合診療医は「全員の意見を信じればよい」と間違って学んでしまいます。そこで 1 段目のモデルには自分が学習に使っていないデータだけを予測させ(Out-of-Fold 予測)、その予測で 2 段目を訓練します。
式で見ると 2 段目は何を学ぶか #
2層アーキテクチャ #
スタッキングは 2 層のモデル構造です。1 段目は上の例の 3 人の医師、2 段目が総合診療医に当たります:
Level-0(ベース学習器): $K$ 個の多様なモデル $h_1, h_2, \dots, h_K$ を訓練データで学習する。
Level-1(メタ学習器): ベース学習器の予測を特徴量として受け取り、最終予測を行うモデル $g$ を学習する。
$$\hat{y} = g\!\left(h_1(x),\; h_2(x),\; \dots,\; h_K(x)\right)$$Out-of-Fold 予測(リーク防止) #
メタ学習器の訓練データを作る際、ベース学習器が自身の訓練データをそのまま予測するとリーク(情報漏洩)が起きます。深さ 6 の決定木なら訓練データの正解率は 90% を超えるので、メタ学習器は「この木を信じればよい」と学び、テストデータで裏切られます。これを防ぐために Out-of-Fold (OOF) 予測を使います。まず訓練データを $J$ 個の Fold に分割します。次に Fold $j$ を除いた残りでベース学習器 $h_k$ を学習し、除いた Fold $j$ のデータを予測してメタ特徴 $z_{ij}^{(k)}$ とします。これを $j = 1, \dots, J$ で繰り返し、最後に全 Fold の予測を結合してメタ特徴行列 $Z \in \mathbb{R}^{N \times K}$ を構成します。$N$ 件のどのサンプルも、自分を学習に使っていないモデルで予測されている点が要です。
$$Z = \begin{pmatrix} z_{11} & z_{12} & \cdots & z_{1K} \\ z_{21} & z_{22} & \cdots & z_{2K} \\ \vdots & \vdots & \ddots & \vdots \\ z_{N1} & z_{N2} & \cdots & z_{NK} \end{pmatrix}$$メタ学習器はこの $Z$ と元のラベル $y$ を使って学習します: $g: Z \to y$。$Z$ の各行は「$K$ 個のモデルがこのサンプルをどう予測したか」で、下のコードでは $K = 4$ 本の決定木の予測ラベルが 4 列になります。scikit-learn の StackingClassifier は既定で cv=5 の 5-Fold でこの $Z$ を作り、その後ベース学習器を全訓練データで学習し直して予測時に使います。
Python で確かめる #
以下では 20 特徴・2500 サンプルの人工データで、まず深さ 5 の木 50 本のランダムフォレストを基準にし、次に深さ 3〜6 の決定木 4 本を StackingClassifier で重ねて ROC-AUC を比べます。その後メタ学習器の木と重要度を描き、「似たモデルを重ねても 1 本の強いモデルに頼るだけになる」ことを目で確認します。
| |
実験用のデータを作成 #
20 特徴のうち 10 個だけがラベルに関係し、各クラスが 4 つの塊に分かれる 2500 件のデータを作り、3 分の 1 をテスト用に分けます。
| |
データを複数の特徴に関してプロットしてみる #
20 特徴のうち 2 つずつを 4 組選んで散布図にし、1 本の直線や単純なルールでは 2 クラスを分けられないデータであることを確認します。
| |

4 枚どれも 2 色の点が重なり合っていて、1 本の直線で分けられる組はありません。各クラスが 4 つの塊に分かれているので、2 次元の切り口だけでは塊の境目が見えないためです。
スタッキングとランダムフォレストの比較 #
ランダムフォレストで分類してみた場合 #
比較の基準として、深さ 5 の木 50 本のランダムフォレストでテストデータの ROC-AUC を出します。
| |
ROC-AUC = 0.855797033310609
複数の木でスタッキングした場合 #
1 段目に深さ 3、4、5、6 の決定木を 4 本並べ、2 段目にも深さ 3 の決定木を置いた StackingClassifier を学習します。DecisionTreeClassifier だけを重ねた場合、ランダムフォレストの 0.86 に対してどこまで届くかを見ます。
| |
ROC-AUC
決定木のスタッキング=0.7359716965608031, ランダムフォレスト=0.855797033310609
スタッキングは 0.74 で、ランダムフォレストの 0.86 に大きく負けています。1 段目の 4 本が「同じデータ・同じ乱数で深さだけ違う木」なので予測がほぼ同じになり、メタ学習器に新しい情報が渡らないためです。次の 2 つの図でその中身を確認します。
スタッキングに使用した木を可視化してみる #
メタ学習器(2 段目の決定木)を Graphviz で描き、4 本のベース学習器のうちどの予測で分岐しているかを見ます。
| |

スタッキングで使用した木の特徴重要度を見る #
メタ学習器の feature_importances_ を見ると、4 本のベース学習器のうちどれの予測が最終判断に使われたかが分かります。結果は 4 番目の木 dt4 に集中し、他の 3 本はほとんど使われていません。
| |

スタッキング前段の各木の性能を確認する #
最後に 1 段目の 4 本をテストデータに 1 本ずつ当て、どの木が最も強かったかを ROC-AUC で確かめます。
| |
====
DecisionTreeClassifier(max_depth=3, random_state=777)
0.7660117774277722
====
DecisionTreeClassifier(max_depth=4, random_state=777)
0.7744128916993818
====
DecisionTreeClassifier(max_depth=5, random_state=777)
0.8000158677919086
====
DecisionTreeClassifier(max_depth=6, random_state=777)
0.8084639977432473

4 本の ROC-AUC は深さの順に 0.77、0.77、0.80、0.81 で、最も深い dt4 が最も強い木でした。メタ学習器は OOF 予測の上で「dt4 を信じる」と学びました。それでもテストでは dt4 単体(0.81)より低い 0.74 に落ちています。4 本の予測がほぼ同じ情報しか持たないため、2 段目の木は雑音に合わせた分岐を作っただけだった、というのがこの実験の結論です。
使いどころと落とし穴 #
スタッキングが効くのは、1 段目に性質の異なるモデルを並べたときです。たとえばロジスティック回帰(線形の境界)、k 近傍法(局所的な境界)、勾配ブースティング(軸に平行な分割の重ね合わせ)のように、間違え方が違うモデルを混ぜると、メタ学習器が「このモデルはこの領域で当たる」という補完関係を学べます。同じ決定木を深さだけ変えて 4 本並べた上の実験は、その逆の例です。2 段目には過学習しにくいロジスティック回帰を置くのが定番で、StackingClassifier(..., final_estimator=LogisticRegression()) と書けます。学習コストはベース学習器の数 × Fold 数(既定 5)になるので、4 本なら 20 回の学習が走ることも覚えておいてください。
まとめ #
スタッキングは、$K$ 個のベース学習器の予測 $h_1(x), \dots, h_K(x)$ を特徴量にして、メタ学習器 $g$ が最終予測を学ぶ 2 層の手法です。要はリーク対策です。メタ学習器の訓練には、各サンプルを「自分を学習に使っていない Fold のモデル」で予測した Out-of-Fold 予測を使い、StackingClassifier は cv=5 でこれを自動で行います。深さ 3〜6 の決定木 4 本を重ねた実験では、予測が似すぎていてメタ学習器が dt4 だけに頼り、ROC-AUC は 0.74 とランダムフォレストの 0.86 に届きませんでした。効かせる条件は「間違え方の違うモデルを 1 段目に並べる」ことです。同種のモデルを並列に平均したいだけなら、バギング や ランダムフォレスト のほうが簡単で強いです。