Day 090 — Gradient Boostingとは何か — 勾配ブースティングの直感

2026-07-10 青 / Phase 4 理論 Boosting / 残差 / 弱学習器 / 学習率

📚 背景知識(読んでから問題へ)

🔵
Phase 4(青帯)の初日です。今日から GBDT(Gradient Boosted Decision Trees) の世界に入ります。XGBoost・LightGBM・CatBoost はすべてこの考え方の実装であり、Tabular(表形式)データの Kaggle コンペで最も勝率が高い手法です。

Phase 2 で学んだ「ランダムフォレスト」との違いを軸に理解していきます。ランダムフォレストは バギング(Bagging):たくさんの木を独立に・並行して作り多数決を取る方式でした。勾配ブースティングは ブースティング(Boosting):木を順番に・直列に作り、前の木が間違えた部分を次の木が補強する方式です。

たとえるなら、バギングは「複数人が独立にテストを解いて多数決を取る」方式。ブースティングは「1人目の答案を先生が採点し、間違えた問題だけを2人目に重点的に解かせ、その答案をまた採点して3人目に…」を繰り返す方式です。

💡
「勾配(Gradient)」の正体: 数式を怖がる必要はありません。各ステップで「今のモデルの予測」と「正解」の残差(ズレ)を計算し、次の木はその残差を予測するように学習します。1本1本は単純で弱くても、積み重ねることで強力なモデルになるのがブースティングのアイデアです。
用語直感的な意味
弱学習器(weak learner)単体では精度の低い浅い決定木。これを大量に積み重ねる
残差(residual)予測値と正解値のズレ。次の木が学習するターゲット
学習率(learning rate)各木の補正をどれだけ強く反映するかの調整弁
アンサンブル(ensemble)複数の弱いモデルを組み合わせて1つの強いモデルにする総称

🔀 バギング(並行)vs ブースティング(直列)

木の作られ方が根本的に違う。この一言をまず覚える。

🌲 バギング(ランダムフォレスト) — 並行・独立 木1(独立) 木2(独立) 木3(独立) 多数決 / 平均 🚀 ブースティング(GBDT) — 直列・依存 木1 残差 木2 残差 木3 最終予測(積み上げ) 各木は「前の木までの予測のズレ(残差)」を埋めるように学習する → 順番が絶対に必要

🎯 問題

⚠️
以下の3つの問いに答えてください(理論問題・コードは不要です)。

問1: バギング vs ブースティングの違い

1
木の作り方(並行 or 直列)
2
各木が学習する対象(何を学習するか)
3
過学習への挙動の違い(木を増やしたときに何が起こりやすいか)

問2: 「残差を学習する」を具体例で説明する

ステップ内容
目的変数正解の家賃 = [10万円, 20万円, 30万円]
Step 0(初期予測)全データの平均で予測 → [20万円, 20万円, 20万円]
Step 1残差(正解 − 予測)を計算する → [?, ?, ?]
Step 2木1がこの残差を予測 → 仮に [-8万円, 1万円, 9万円]。学習率 0.5 で予測を更新すると?
1
Step 1 の残差を計算する
2
学習率 0.5 を使った場合の更新後の予測値を計算する
3
なぜ学習率を 1.0 ではなく 0.5 のような小さい値にするのか、直感的に説明する

問3: なぜGBDTはTabularデータで強いのか

🏆
GBDT(XGBoost/LightGBM/CatBoost)が Kaggle の表形式データコンペで深層学習より好んで使われる理由を 2つ 挙げてください。

📊 残差が縮まっていく様子を可視化する

正解 30万円のデータ1件が、木を積み重ねるたびに予測へ近づく例。

予測値の推移(正解 = 30万円)

Step 0(平均予測)
誤差 10万円
20万円
Step 1(木1反映後)
誤差 5.5万円
24.5万円
Step 5(木5本反映後・イメージ)
誤差 2万円
28万円
正解
誤差 0
30万円
📐
木を1本追加するごとに「学習率 × 木の予測」ぶんだけ正解に近づく。一気に正解へ飛びつかず、少しずつ・何度も補正するのがブースティングの強さの源泉。

💡 ヒント

ヒント1方向性

問1は「複数の職人が独立に作品を作って良いものを選ぶ(バギング)」と「1人の職人が下書き→添削→修正を繰り返して1つの作品を仕上げる(ブースティング)」の違いをイメージする。過学習の挙動は、バギングは木を増やしても比較的安定するが、ブースティングは増やしすぎると訓練データに寄りすぎる、という非対称性がポイント。

ヒント2アプローチ
  • 問2: 残差 = 正解 - 予測 を素直に引き算するだけ
  • 問2: 更新式は 予測 = 元の予測 + 学習率 × 木の予測
  • 問3: 「特徴量の型(数値・カテゴリ混在、スケールがバラバラ)」と「データ量」の2軸で考える
ヒント3コード骨格
y_true = [10, 20, 30]          # 万円
y_pred_step0 = [20, 20, 20]    # 初期予測(平均)

residual = [t - p for t, p in zip(y_true, y_pred_step0)]
print("残差:", residual)

tree1_pred = [-8, 1, 9]        # 木1が予測した残差
learning_rate = 0.5
y_pred_step1 = [p0 + learning_rate * t1 for p0, t1 in zip(y_pred_step0, tree1_pred)]
print("Step1後の予測:", y_pred_step1)

模範解答

問1: バギング vs ブースティングの違い

観点バギング(ランダムフォレスト)ブースティング(GBDT)
木の作り方並行。各木は独立にランダムサンプリングされたデータで作られる直列。前の木の結果(残差)を見てから次の木を作る
各木が学習する対象元の目的変数そのもの(同じ問題を別々の角度から解く)前の木までの予測の残差(ズレ)。1本ごとに解くべき問題が変わる
過学習への挙動木を増やしても分散が下がり比較的安定(過学習しにくい)木を増やしすぎると訓練データのノイズまで拾い過学習しやすい(early stopping が重要)

問2: 「残差を学習する」の計算

1. Step 1 の残差:

残差 = 正解 - 予測
     = [10-20, 20-20, 30-20]
     = [-10万円, 0万円, +10万円]

2. Step 2 の更新後の予測(学習率0.5):

新しい予測 = 元の予測 + 学習率 × 木1の予測
         1件目 = 20 + 0.5 × (-8) = 16万円
         2件目 = 20 + 0.5 ×  1  = 20.5万円
         3件目 = 20 + 0.5 ×  9  = 24.5万円

→ 更新後の予測 = [16万円, 20.5万円, 24.5万円]
(正解 [10, 20, 30] に少しずつ近づいている)
💡
3. なぜ学習率を小さくするか: 学習率1.0で残差をそのまま反映すると、1本目の木だけで訓練データに完璧にフィットし、その木が持つノイズごと丸暗記してしまう。学習率を0.5や0.1のように小さくすることで「一歩ずつ慎重に近づく」ことになり、後続の多数の木で少しずつ補正しながら汎化性能の高いモデルに育てられる。一気に正解を覚えるのではなく、少しずつ・何度も復習して定着させる学習法に似ている。

問3: なぜGBDTはTabularデータで強いのか

#理由説明
1特徴量の前処理がほぼ不要 決定木は「値の大小で分岐する」だけなので、数値のスケール差を気にせず、正規化も不要。カテゴリ変数もLightGBM/CatBoostならほぼそのまま扱える
2中規模データでも強く、学習が高速 ニューラルネットは大量データと長い学習時間で真価を発揮するが、GBDTは数千〜数百万行でも少ない試行回数で高精度が出やすく、限られた時間内の試行錯誤に向く

(補足: 特徴量同士の非線形な組み合わせや、欠損値・外れ値への頑健性も理由に挙げられる)

🪜 Step-by-Step 解説

1バギングとブースティングを対比で覚える

ランダムフォレストは「並列・独立」、GBDTは「直列・依存」。この一言をまず暗記する。

バギング:    木1 ─┐
             木2 ─┼─ 多数決/平均 → 最終予測
             木3 ─┘
             (3本は互いに無関係。同時に作れる)

ブースティング: 木1 → 残差計算 → 木2 → 残差計算 → 木3 → ... → 最終予測
             (木2は木1の結果を知っている。順番が絶対に必要)
🔑
なぜこうするか: この構造の違いが、後々学ぶ「なぜGBDTは学習が遅いか(並列化しづらい)」「なぜearly stoppingが必要か(過学習しやすい)」に直結する。

2残差計算を手を動かして確認する

Step 0(平均で予測)→ Step 1(残差計算)→ Step 2(木で残差を予測し反映)の3ステップを、実際に電卓で計算してみることが重要。

y_true = [10, 20, 30]
y_pred_step0 = [sum(y_true) / len(y_true)] * 3  # [20, 20, 20]
residual = [t - p for t, p in zip(y_true, y_pred_step0)]  # [-10, 0, 10]
🔑
なぜこうするか: XGBoost等のライブラリはこの計算を内部で自動的に、しかも「勾配」という一般化された形(回帰ならこの残差、分類なら別の式)で何百回も繰り返している。仕組みを1回手計算しておくと、後でパラメータ(n_estimators, learning_rate)の意味が直感的に分かる。

3学習率と木の本数はトレードオフ

学習率 大(例: 1.0) → 少ない木の本数で収束するが、過学習しやすい
学習率 小(例: 0.01) → 収束に多くの木が必要だが、慎重で汎化しやすい
💡
なぜこうするか: 実務では「学習率を下げて、木の本数を増やす」のが定石。後日 XGBoost/LightGBM 実装回で learning_raten_estimators のセット調整として学ぶ。

🧮 数学・統計の補足(文系向け)

📐
「勾配(Gradient)」を怖がる必要はない。ここでは単に「予測を正解に近づけるために、どちら方向にどれだけ修正すべきか」という修正の指示書だと思ってよい。回帰の場合、その指示書の中身は単純な引き算(残差)。

身近な例: ダーツの狙い直し

1投目が的の中心から左に10cmずれた。2投目は「右に少し」狙いを調整する。3投目はさらに微調整する…。これを何十投も繰り返すと、平均してほぼ中心に当たるようになる。GBDTの「木を1本ずつ追加する」プロセスは、まさにこの投げるたびに狙いを補正していく動き。

もし数式を見たら

Fm(x) = Fm-1(x) + η · hm(x)

「m本目までの予測 = (m-1本目までの予測) + (学習率 η) × (m本目の木が予測した補正量)」を数学的に書いたもの。問2でやった計算そのもの。

🏆 Kaggleでの実践的な使い方

よく使われるコンペカテゴリ: ☑ 表形式データ(Tabular) / ☐ 自然言語処理(NLP) / ☐ 画像認識(CV) / ☑ 時系列(Time Series)

Kaggleの Tabular Playground Series や House Prices、多くの Featured コンペで、上位解法の大半が XGBoost / LightGBM / CatBoost のアンサンブルを核にしている。特に「特徴量エンジニアリングの効果を素早く検証したい」場面では、ニューラルネットより学習が速いGBDTが実験サイクルを回しやすく、Kagglerの主力ツールになっている。Phase 4 ではこの3ライブラリを順番に実装しながら、パラメータチューニング(Optuna)・アンサンブルへと発展させる。

⚠️ よくある誤解・ミス

誤解・ミスなぜ起こるか正しい理解
ランダムフォレストとGBDTを同じものと思うどちらも「決定木の集まり」に見える木の作り方(並行 vs 直列)と学習対象(元データ vs 残差)が根本的に異なる
木の本数を増やせば増やすほど良いと思うバギングの感覚を持ち込むGBDTは増やしすぎると過学習。early stoppingやCVでの本数決定が必須
学習率は小さいほど無条件に良いと思う「慎重=正義」という直感学習率を下げるほど必要な木の本数が増え、学習時間が伸びるトレードオフがある
勾配ブースティングは分類にしか使えないと思うロジスティック回帰との連想回帰・分類どちらにも使える。損失関数を変えるだけで両対応

🚀 次のステップ

  • 発展: 問2の残差計算を Step 3・Step 4 まで手動で続けてみて、予測値がどのように正解へ収束していくかを観察する
  • 次回予告: Day 091「XGBoost① 実装」 — 今日学んだ直感を、実際に xgboost ライブラリでコードとして動かす
🎉
Phase 4(青帯)スタート! GBDT・アンサンブル・Optunaへと続く、Kaggle Expert への本丸が始まりました。

📝 自己評価(解いた後に記入)

自分の回答・気づき・メモ: