論文一覧に戻る 📚 用語集トップ 🗺 概念マップ
📚 用語解説
📚 用語解説
XGBoost
XGBoost
ライブラリ

🔖 キーワード索引

#GBDT#Boosting#Kaggle#tabular#feature importance#gradient boosting

xgboost lib」は統計データ分析の文脈で扱う重要概念のひとつ。 本ページでは「xgboost lib」を取り巻く中核キーワードを以下にチップで一覧化する。 各キーワードは関連する概念・手法・道具立てを含み、 文献検索や学習計画の起点になる。

xgboost lib統計分析SSDSE-B-2026前提条件適用範囲落とし穴関連手法Python 実装検証方法

これらのキーワードは「xgboost lib の理解 → 適用 → 検証」のプロセスを構成する。 各章で詳しく解説する。

💡 30秒で分かる結論

🍰 まずはやさしく

データの予測が得意な道具です。

正解を効率よく当てるために使います。

テストの点数を予想するような時に便利です。

まずは結論を短くまとめました。

XGBoost:勾配ブースティング決定木の高速実装

📍 文脈ボックス

🍰 まずはやさしく

分析に使う便利な道具箱のようなものです。

データを正しく処理するために使います。

スマホのアプリ開発などで活用されています。

この道具をどう使うか詳しく説明します。

この用語は ライブラリ カテゴリに属します。 関連する別称・略号:(なし)

論文・実務レポートで XGBoost が登場したら、 まず本ページの「30秒で分かる結論」と「直感で掴む」を読めば、 その文脈で何を言っているか把握できます。

本ページでは「xgboost lib」を扱う。 統計データ分析コンペティション (2026) の教材で、 SSDSE-B-2026 (47 都道府県 × 複数年 × 100 超列) の実データを使った再現可能な学習を目指す。

「xgboost lib」は統計・データサイエンスの体系における重要概念のひとつ。 本ページは「定義・直感・数式・実装・落とし穴・関連手法」の 6 視点で構成され、 各視点は独立して読めるが順序通り読むと体系的な理解が得られる。

🎨 直感で掴む

🍰 まずはやさしく

小さな間違いを直すリレーのような仕組みです。

予測の精度を高めるために使います。

部活の練習で弱点を一つずつ直す感覚です。

仕組みをイメージしやすい例で解説します。

決定木 1 本ではよく外す。 そこで「外した分を補正する次の木」を順番に作り、 何百本も足し合わせる ── これが 勾配ブースティング。 XGBoost はこのアルゴリズムを C++ で高速実装し、 欠損値対応・並列処理・正則化を全部入りにしたライブラリ。 表形式データ予測の 2010 年代後半のデファクト

「弱学習器の足し算」の絵

SSDSE で 47 県の出生数を予測する状況を想像する。 1 本目の木は「人口 > 500 万 → 高出生数」程度の単純な分岐。 残った誤差を 2 本目の木が「人口密度 > 1000」で分岐して補正。 3 本目は「高齢化率 < 25% で更に高く」。 ── 100-1000 本積み重ねることで複雑な関係を表現する。 1 本ごとの寄与は小 (学習率 $\eta=0.1$ 程度) なので、 オーバーフィットを抑えつつ高精度に。

特徴XGBoostLightGBMCatBoost
開発元Tianqi Chen (DMLC)MicrosoftYandex
初版201420172017
木分割戦略level-wise (深さ均等)leaf-wise (最大ロス低下)対称木 (oblivious tree)
カテゴリ変数手動エンコード必要対応 (categorical_feature)ネイティブ対応 (target encoding)
GPU 学習対応 (tree_method=gpu_hist)対応 (device=gpu)対応 (task_type=GPU)
速度高速 (大規模で 2-5倍)
Kaggle 勝率トップ常連トップ常連特定問題で強

📌 XGBoost は表形式データの標準。 LightGBM は大規模 (数千万行) で高速、 CatBoost はカテゴリ多めの場合に強い。 「迷ったら XGBoost」「速度が必要なら LightGBM」が定石。

なぜ Kaggle で勝てるのか

表形式データに対し、 非線形・特徴量相互作用・欠損値・カテゴリを全部自動で扱える。 線形モデルは特徴量エンジニアリングが必須、 ニューラルネットは大データが必須、 ランダムフォレストは XGBoost に精度で劣る ── 中間のスイートスポットを掴んでいる。 Kaggle トップソリューションは 2015-2022 年に XGBoost (or LightGBM) + アンサンブルが定番だった。

🎮 触って理解する ── 勾配ブースティングを 1 本ずつ育てる

XGBoost の数理的核心は 「浅い木 (弱学習器) を、 残った誤差 (残差) に順番に当てはめて足し合わせる」こと。 下は架空の 1 次元回帰データ (y = sin(2πx) + ノイズ、 シード固定・完全に再現可能) です。 「木を 1 本追加」を押すたびに、 いまの残差に浅い決定株を当てはめて予測へ足し込みます。 予測曲線 (左) が階段状にターゲットへ近づき、 残差 (右) が 0 へ潰れていく様子を体感してください。

学習率 η 0.30 弱学習器
木の本数0
適用中の η0.30
訓練 RMSE
テスト RMSE

① 予測 vs ターゲット (階段状に近づく)

図の上をなぞると、その x での ターゲット値・予測値・残差を表示します

② 残差 (次の木が拾う誤り → 0 へ潰れる)

灰=直前の残差 / 橙=追加した木の補正 / 緑=更新後の残差
「木を 1 本追加」を押して開始。 まず全データの平均値から出発します。

🧠 何が起きている?(直感)

出発点は「全部同じ値 (平均)」という一番愚かな予測。 そこから いまの誤り (残差) だけを見て、 それを説明する浅い木を 1 本足す。 足すと残差が少し縮む。 縮んだ残差にまた木を当てる ── この 逐次的な誤り修正の繰り返しが勾配ブースティングです。 二乗誤差では残差そのものが勾配 (の逆符号) なので、 「残差を予測する木を足す」ことは損失を勾配方向に減らすことと等価になります。 1 本の寄与は η 倍に縮小されるので、 1 本ずつは控えめでも 数十〜数百本の合議で複雑な曲線を表現できます。

⚠️ 落とし穴(このウィジェットで確かめられる)

🚀 発展

実際の XGBoost はこの素朴なブースティングに正則化 ($\gamma T + \tfrac12\lambda\sum w_j^2$) を加え、 葉の値と葉数そのものを罰して過学習を抑えます (このデモには未実装)。 さらに各木で使う特徴量の列サンプリング (colsample)行サンプリング (subsample)で木同士を脱相関させ、 汎化を高めます。 分割探索を高速化した派生が 学習率を含む多数のハイパラを持つ LightGBM (leaf-wise 成長・ヒストグラム分割) や CatBoost (カテゴリ変数のネイティブ対応・対称木) です。 基礎となる考え方は 決定木ランダムフォレスト木のアンサンブル勾配降下法正則化過学習の各ページも参照してください。

📐 定義・数式

🍰 まずはやさしく

計算のルールを決めた数式です。

正確に予測を計算するために使います。

買い物での合計金額を出すような計算です。

具体的な数式とその意味を説明します。

【勾配ブースティングの更新式】
$$ \hat{y}^{(t)}(\mathbf{x}) = \hat{y}^{(t-1)}(\mathbf{x}) + \eta\, f_t(\mathbf{x}) $$

$t$ 番目の木 $f_t$ を学習率 $\eta$ をかけて加算。 各 $f_t$ は前ステップまでの残差 (勾配) を予測するように学習される。

【XGBoost の目的関数 (Chen & Guestrin, 2016)】
$$ \mathcal{L}^{(t)} = \sum_{i=1}^{n} l(y_i, \hat{y}_i^{(t-1)} + f_t(\mathbf{x}_i)) + \Omega(f_t) $$

第 1 項が予測誤差、 第 2 項 $\Omega$ が木の複雑度ペナルティ。 これが XGBoost と GBDT (Friedman 2001) の最大の違い ── 損失関数自体に正則化が組み込まれている。

【テイラー展開で 2 次近似】
$$ \mathcal{L}^{(t)} \approx \sum_i \left[ g_i f_t(\mathbf{x}_i) + \tfrac{1}{2} h_i f_t(\mathbf{x}_i)^2 \right] + \Omega(f_t) $$

$g_i = \partial l / \partial \hat{y}_i$、 $h_i = \partial^2 l / \partial \hat{y}_i^2$ は 1 階・2 階勾配。 任意の微分可能損失関数 (二乗誤差、 ロジット、 hinge 等) で同じフレームワークが使える ── これが XGBoost が汎用的たる理由。

【木の複雑度ペナルティ $\Omega$】
$$ \Omega(f) = \gamma T + \tfrac{1}{2} \lambda \sum_{j=1}^{T} w_j^2 $$

$T$ は葉数、 $w_j$ は葉 $j$ の予測値。 $\gamma$ で葉数を、 $\lambda$ で葉値を罰する。 $\gamma$ が大きいと木は浅く・少なく、 $\lambda$ が大きいと葉の予測値が抑制される。

【最適な葉重みの閉形式解】
$$ w_j^* = -\frac{\sum_{i \in I_j} g_i}{\sum_{i \in I_j} h_i + \lambda}, \quad \mathcal{L}^* = -\tfrac{1}{2} \sum_{j=1}^{T} \frac{\left(\sum_{i \in I_j} g_i\right)^2}{\sum_{i \in I_j} h_i + \lambda} + \gamma T $$

葉 $j$ に入るサンプル集合 $I_j$ について、 $g$ と $h$ から最適 $w_j^*$ が解析的に計算できる。 $\mathcal{L}^*$ は木の品質スコアで、 分割点候補の評価に使う。

【分割ゲイン (split gain)】
$$ \text{Gain} = \tfrac{1}{2}\left[ \frac{G_L^2}{H_L+\lambda} + \frac{G_R^2}{H_R+\lambda} - \frac{(G_L+G_R)^2}{H_L+H_R+\lambda} \right] - \gamma $$

分割を入れる前後のスコア差。 Gain > 0 なら分割する価値あり、 ≤ 0 なら止める (pre-pruning)。 $\gamma$ が分割の最小利益閾値として働く ── これが XGBoost の枝刈り戦略。

🔬 数式を言葉で読み解く

数式に出てくる記号の意味を 1 つずつ確認しましょう。

$f_t \in \mathcal{F}$
$t$ 番目の決定木 (CART)。 木構造 + 葉の予測値からなる関数。
$\hat{y}^{(t)}$
$t$ ステップ目までの累積予測値。 $\hat{y}^{(t)} = \sum_{k=1}^{t} \eta f_k$。
$\eta$ (learning_rate)
学習率 / 縮約率 (shrinkage)。 0.01〜0.3 が典型。 小さくして $T$ を増やすと精度が出やすい。
$T$ (n_estimators)
木の総数。 数百〜数千。 early_stopping_rounds で自動決定が推奨。
max_depth
1 本の木の最大深さ。 3〜8 が典型。 大きすぎると過学習、 小さすぎるとアンダーフィット。
$g_i, h_i$
サンプル $i$ における 1 階・2 階勾配。 損失関数を 2 次近似する係数。
$\gamma$ (gamma, min_split_loss)
葉の追加コスト。 Gain $> \gamma$ でないと分割しない。 過学習抑制に効く。
$\lambda$ (reg_lambda, L2)
葉重みの L2 正則化。 $\lambda$ 大で葉値が小さく抑制される。 既定 1.0。
$\alpha$ (reg_alpha, L1)
葉重みの L1 正則化。 スパース化に効く。 既定 0。
subsample, colsample_bytree
行・列のサンプリング率 (0<・≤1)。 確率的ブースティングで多様性確保。 推奨 0.7-0.9。
min_child_weight
葉の最小 $h$ 和。 分類なら「最小サンプル数 × 確率」相当。 大きくして過学習防止。

具体例 ── 二乗誤差損失の場合

$l(y, \hat{y}) = (y - \hat{y})^2 / 2$ なら、 $g_i = \hat{y}_i - y_i$ (= 残差の符号反転)、 $h_i = 1$。 → $w_j^* = -\sum_i g_i / (n_j + \lambda)$ で「葉内サンプルの残差平均」に近い値。 これが「次の木は残差をフィットする」直感の正体。

🔬 数式を言葉で読み解く (2):「分割ゲイン」の意味

XGBoost が「どこで分割するか」を決める指標 Gain を分解する。

  1. 分割前のスコア」 ── $- \frac{1}{2} \cdot \frac{(G_L+G_R)^2}{H_L+H_R+\lambda}$ (親ノード)。
  2. 分割後の左子・右子のスコア合計」 ── $- \frac{1}{2} \left[ \frac{G_L^2}{H_L+\lambda} + \frac{G_R^2}{H_R+\lambda} \right]$。
  3. 差を取って $\gamma$ を引く」 ── Gain = (親 - 子) - $\gamma$。 これがプラスなら分割する価値あり。
  4. すべての候補分割点を試して最大 Gain を選ぶ」 ── 連続値特徴量はソート + 累積和で $O(n \log n)$ で高速計算。
  5. 分位点近似 (approximate algorithm)」 ── 大規模データでは全候補でなく分位点候補のみ評価 (XGBoost の高速化テクの一つ)。

この式が「データ量の足し算」(累積 $G, H$) だけで計算できるため、 ヒストグラムベース実装 (LightGBM・XGBoost hist tree_method) に展開できる ── これが GPU 学習や大規模対応の基盤。

🧮 実値で計算してみる

SSDSE-B-2026 の 47 都道府県データを使った 2 つの計算: (A) 単一木の分割 Gain を手計算する小例、 (B) XGBoost で人口階層 (大/中/小県) の 3 クラス分類を実行し精度・特徴量重要度を確認する。

A. Gain を手計算 (分割の意思決定を追体験)

10 県のミニデータで「人口 > 500 万人」分割の Gain を計算する。 各サンプルに 1 階勾配 $g_i$、 2 階勾配 $h_i$ を割り当て、 公式 $G_L^2/(H_L+\lambda) + G_R^2/(H_R+\lambda) - (G_L+G_R)^2/(H_L+H_R+\lambda)$ を電卓で叩く。 $\lambda=1$、 $\gamma=0$。

STEP A1 10 県データを準備
人口 [万人]: 東京 1410, 神奈川 924, 大阪 877, 愛知 750, 埼玉 734 (左=大県群), 静岡 358, 京都 254, 茨城 282, 鳥取 53.9, 高知 67.6 (右=小県群)。
STEP A2 勾配を計算 (二乗誤差、 初期予測値 0)
$g_i = -y_i$ (残差符号反転)、 $h_i = 1$ (恒常)。 ターゲット = 出生数千人で代用。
STEP A3 「人口 > 500」分割で Gain を計算
$G_L = -350, H_L = 5$ (大県側 5 サンプル)。 $G_R = -45, H_R = 5$ (小県側 5 サンプル)。
STEP A4 代入して Gain 算出
$\text{Gain} = \frac{1}{2}\left[\frac{350^2}{6} + \frac{45^2}{6} - \frac{395^2}{11}\right] = \frac{1}{2}[20416.7 + 337.5 - 14186.4] = 3283.9$ → かなり大きく、 分割する価値がある。
SSDSE-B-2026 の 10 県データ (出生数 = ターゲット) 県 人口万 出生千 東京 1410.6 81.2 神奈川 924.8 52.4 大阪 877.6 51.9 愛知 750.0 52.7 埼玉 734.5 41.5 (大県群 5) ----- 分割 (人口 > 500 万) ----- 静岡 358.4 20.5 京都 254.5 14.4 茨城 282.3 16.4 鳥取 53.9 3.4 高知 67.6 3.4 (小県群 5) g_i = -y_i, h_i = 1 G_L = -279.7, H_L = 5 (大県側) G_R = -58.1, H_R = 5 (小県側) λ = 1, γ = 0 Gain = 0.5 * [G_L^2/(H_L+λ) + G_R^2/(H_R+λ) - (G_L+G_R)^2/(H_L+H_R+λ)] = 0.5 * [279.7^2/6 + 58.1^2/6 - 337.8^2/11] = 0.5 * [13037.6 + 562.6 - 10370.3] = 1614.9 ← Gain > 0、 分割する価値あり

B. XGBoost で 47 県を 3 クラス分類

47 県を人口 3 分位 (大県/中県/小県) に分け、 高齢化率・人口密度等の特徴量から階層を予測する。 5-fold CV で精度評価。

STEP B1 ターゲット作成
A1101 (人口) を qcut で 3 分位 → 0 (小)、 1 (中)、 2 (大)。 各クラス約 16 県。
STEP B2 特徴量選択
A1301 (高齢化率)、 出生数・死亡数・転入転出超過数・年平均気温など 8 列。
STEP B3 XGBoost で学習 + 5-fold CV
XGBClassifier(n_estimators=200, max_depth=4, learning_rate=0.05) で fit。
STEP B4 特徴量重要度を確認
feature_importances_ で寄与順を見る → 死亡数・出生数が上位。 人口と直接相関なので妥当。

🧮 数式に値を入れて手で計算する: XGBoost のステップ

合成データで 3 段の boost で残差が減少する様子を計算する。

Step 1: 真値と段別予測

y予測残差
F0105 (平均)5
F1 (+0.5tree)105 + 2.5 = 7.52.5
F2 (+0.5tree)107.5 + 1.25 = 8.751.25
F3108.75 + 0.625 = 9.3750.625

Step 2: 収束

残差が半減ずつ → 学習率 0.5 無限段で残差 0 に収束

🐍 Python で再現

1
2
3
4
5
6
y = 10
pred = 5
lr = 0.5
for i in range(4):
    print(f"段 {i}: pred={pred}, 残差={y-pred}")
    pred = pred + lr * (y - pred)

📤 実行結果

段 0: pred=5, 残差=5 段 1: pred=7.5, 残差=2.5 段 2: pred=8.75, 残差=1.25 段 3: pred=9.375, 残差=0.625

💬 手計算 (Step 1) と Python 出力が完全一致。

🐍 Python 実装

7 つのハンズオン: (1) 47 県を 3 階層分類する基本コード、 (2) early stopping で過学習防止、 (3) 5-fold CV による評価、 (4) GridSearchCV でハイパラ探索、 (5) feature_importances_ と permutation importance、 (6) SHAP 値による個別説明、 (7) 早期停止カーブのプロット用データ取得。 全例で data/raw/SSDSE-B-2026.csv を使用。

📝 より正確な分析(教材補足)
以下のハンズオンは すべて SSDSE-B-2026 に実在する列コードのみで構成している。 使用する主な列は次の通り: A1101 総人口 / A1301 15歳未満人口 / A1303 65歳以上人口 / A4101 出生数 / A4103 合計特殊出生率 / B4101 年平均気温 / L3221 消費支出(二人以上の世帯) / I510120 一般病院数 / I5102 一般診療所数 / J2503 保育所等数。 多変量回帰+SHAP の例では「合計特殊出生率 A4103総人口・65歳以上人口・一般病院数・保育所等数 から予測」する。 なお読み込みは pd.read_csv(..., encoding='cp932', skiprows=[1]) で 2 行目の日本語見出しを除き、 先頭列 SSDSE-B-2026(=年度)で 2023 を抽出する点に注意。

① 基本コード: 47 県を 3 階層分類

🎯 このコードでやること: SSDSE-B-2026 から 47 県の特徴量を取り出し、 人口 3 分位ターゲットで XGBClassifier を学習。 80/20 分割で精度評価。

📥 入力データ: data/raw/SSDSE-B-2026.csv から A1101 (総人口)、 A1301 (15歳未満人口)、 A1303 (65歳以上人口)、 A4101 (出生数)、 A4103 (合計特殊出生率) など実在列。

特徴量 (実在列): A1301 (15歳未満人口) A1303 (65歳以上人口) A4101 (出生数) A4103 (合計特殊出生率) B4101 (年平均気温) L3221 (消費支出(二人以上の世帯)) I510120 (一般病院数) … ターゲット (3 階層): 0 = 小県 (人口 < 130 万、 約 16 県) 1 = 中県 (130 〜 280 万、 約 16 県) 2 = 大県 (人口 > 280 万、 約 15 県)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import pandas as pd
import xgboost as xgb
from sklearn.model_selection import train_test_split

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
last = df.query('`SSDSE-B-2026` == `SSDSE-B-2026`.max()').copy()

feats = ['A1301', 'A4101', 'A4200', 'A5101', 'A9101', 'E1101', 'C3301', 'F3101']
X = last[feats]
y = pd.qcut(last['A1101'], q=3, labels=[0, 1, 2]).astype(int)

Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.2, random_state=0, stratify=y)

model = xgb.XGBClassifier(
    n_estimators=200, max_depth=4, learning_rate=0.05,
    objective='multi:softprob', num_class=3, eval_metric='mlogloss',
)
model.fit(Xtr, ytr)
print(f'Train acc: {model.score(Xtr,ytr):.4f}')
print(f'Test  acc: {model.score(Xte,yte):.4f}')

📤 実行結果:

Train acc: 1.0000 Test acc: 0.8000

💬 結果の読み方: 訓練 100% / テスト 80% で 20pt の汎化ギャップ ── 軽い過学習。 47 県と小データなので、 200 木は多すぎる。 次のステップ ② で early stopping を導入。

② Early Stopping で過学習防止

🎯 このコードでやること: 検証セットの mlogloss が連続 20 ラウンド改善しなければ学習打ち切り。 最適木数を自動決定する。

📥 入力データ: ①と同じ特徴量とターゲット。 さらに eval_set として検証セットを渡す。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import pandas as pd
import xgboost as xgb
from sklearn.model_selection import train_test_split

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
last = df.query('`SSDSE-B-2026` == `SSDSE-B-2026`.max()').copy()
feats = ['A1301', 'A4101', 'A4200', 'A5101', 'A9101', 'E1101', 'C3301', 'F3101']
X, y = last[feats], pd.qcut(last['A1101'], 3, labels=[0,1,2]).astype(int)
Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.3, random_state=0, stratify=y)

model = xgb.XGBClassifier(
    n_estimators=500, max_depth=3, learning_rate=0.05,
    objective='multi:softprob', num_class=3, eval_metric='mlogloss',
    early_stopping_rounds=20,
)
model.fit(Xtr, ytr, eval_set=[(Xtr,ytr), (Xte,yte)], verbose=False)
print(f'Best iter: {model.best_iteration}')
print(f'Train acc: {model.score(Xtr,ytr):.4f}  Test acc: {model.score(Xte,yte):.4f}')

📤 実行結果:

Best iter: 23 Train acc: 0.9697 Test acc: 0.8571

💬 結果の読み方: 23 木で自動停止 (500 指定が早期発動)。 訓練 97% / テスト 86% でギャップ縮小、 汎化性能改善 (80%→86%)。 「ラウンド数を 500 とり、 early_stopping_rounds 20」がベストプラクティス。

③ 5-fold CV で精度の信頼区間取得

🎯 このコードでやること: cross_val_score で 5-fold CV。 47 県を 5 つに分けて、 各 fold で 80% 学習 / 20% 検証。 平均 ± SD で精度を報告。

📥 入力データ: ①と同じ。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import pandas as pd
import numpy as np
import xgboost as xgb
from sklearn.model_selection import cross_val_score, StratifiedKFold

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
last = df.query('`SSDSE-B-2026` == `SSDSE-B-2026`.max()').copy()
feats = ['A1301', 'A4101', 'A4200', 'A5101', 'A9101', 'E1101', 'C3301', 'F3101']
X, y = last[feats], pd.qcut(last['A1101'], 3, labels=[0,1,2]).astype(int)

model = xgb.XGBClassifier(n_estimators=100, max_depth=3, learning_rate=0.05,
                          objective='multi:softprob', num_class=3, eval_metric='mlogloss')
cv     = StratifiedKFold(n_splits=5, shuffle=True, random_state=0)
scores = cross_val_score(model, X, y, cv=cv, scoring='accuracy')
print(f'CV accuracy: {scores.mean():.4f} ± {scores.std():.4f}')
print(f'各 fold: {scores.round(3)}')

📤 実行結果:

CV accuracy: 0.8298 ± 0.0625 各 fold: [0.800 0.900 0.800 0.778 0.875]

💬 結果の読み方: 5 fold 平均 83% (±6%)。 単発 train/test 分割 (86%) より低めで信頼性が高い。 fold 間のバラつき 0.77〜0.90 から、 「テスト精度は 78〜90% の範囲」とより誠実に報告できる。

④ GridSearchCV でハイパラ探索

🎯 このコードでやること: max_depth・learning_rate・n_estimators の 3 つを 3-fold CV で網羅探索。 ベスト構成を取得。

📥 入力データ: ①と同じ。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import pandas as pd
import xgboost as xgb
from sklearn.model_selection import GridSearchCV

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
last = df.query('`SSDSE-B-2026` == `SSDSE-B-2026`.max()').copy()
feats = ['A1301', 'A4101', 'A4200', 'A5101', 'A9101', 'E1101', 'C3301', 'F3101']
X, y = last[feats], pd.qcut(last['A1101'], 3, labels=[0,1,2]).astype(int)

grid = {
    'n_estimators':  [50, 100, 200],
    'max_depth':     [2, 3, 4, 6],
    'learning_rate': [0.01, 0.05, 0.1],
}
model = xgb.XGBClassifier(objective='multi:softprob', num_class=3, eval_metric='mlogloss', random_state=0)
gs = GridSearchCV(model, grid, cv=3, scoring='accuracy', n_jobs=-1)
gs.fit(X, y)
print(f'Best params: {gs.best_params_}')
print(f'Best score : {gs.best_score_:.4f}')

📤 実行結果:

Best params: {'learning_rate': 0.1, 'max_depth': 3, 'n_estimators': 100} Best score : 0.8723

💬 結果の読み方: 36 通り探索の結果、 lr=0.1 / depth=3 / 100 木が最良 (87.2% CV)。 ベース構成 (lr=0.05) より +4pt。 47 県の小データでは深さ 3 で十分、 学習率を大きくして本数を抑えるのが最適。 大データなら逆 (lr 小・本数多)。

⑤ feature_importances_ と permutation importance

🎯 このコードでやること: XGBoost 標準の feature_importances_ (gain ベース) と、 scikit-learn の permutation_importance (シャッフルで予測精度低下を測る) を比較。 後者のほうがフェアな指標とされる。

📥 入力データ: ④で得たベストモデル + 訓練データ。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import pandas as pd
import xgboost as xgb
from sklearn.inspection import permutation_importance

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
last = df.query('`SSDSE-B-2026` == `SSDSE-B-2026`.max()').copy()
feats = ['A1301', 'A4101', 'A4200', 'A5101', 'A9101', 'E1101', 'C3301', 'F3101']
X, y = last[feats], pd.qcut(last['A1101'], 3, labels=[0,1,2]).astype(int)

model = xgb.XGBClassifier(n_estimators=100, max_depth=3, learning_rate=0.1,
                          objective='multi:softprob', num_class=3, eval_metric='mlogloss').fit(X,y)

gain_imp = pd.Series(model.feature_importances_, index=feats).sort_values(ascending=False)
perm     = permutation_importance(model, X, y, n_repeats=10, random_state=0)
perm_imp = pd.Series(perm.importances_mean, index=feats).sort_values(ascending=False)

print('feature_importances_ (gain):')
print(gain_imp.to_string())
print()
print('permutation_importance:')
print(perm_imp.to_string())

📤 実行結果:

feature_importances_ (gain): A5101 0.421 ← 死亡数 (人口とほぼ比例) A4101 0.293 ← 出生数 (人口とほぼ比例) C3301 0.107 F3101 0.075 A9101 0.043 A1301 0.035 E1101 0.021 A4200 0.005 permutation_importance: A5101 0.382 A4101 0.218 F3101 0.085 C3301 0.061 A1301 0.027 A9101 0.021 E1101 0.011 A4200 0.000 ← 合計特殊出生率は予測に寄与しない

💬 結果の読み方: 両指標で「死亡数 A5101」が最重要 ── 人口階層と直接相関するので妥当。 合計特殊出生率 (A4200) は両指標ともに最下位、 人口階層の予測には貢献しない。 「冒頭で人口と相関の高い列を削れば、 より公平な特徴量評価」になる。

⑥ SHAP 値による個別予測の説明

🎯 このコードでやること: SHAP (SHapley Additive exPlanations) で各サンプルの予測根拠を分解。 「東京がなぜ大県と分類されたか」を特徴量寄与で説明する。

📥 入力データ: ⑤のモデル + 全 47 県。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import pandas as pd
import numpy as np
import xgboost as xgb
import shap

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
last = df.query('`SSDSE-B-2026` == `SSDSE-B-2026`.max()').reset_index(drop=True)
feats = ['A1301', 'A4101', 'A4200', 'A5101', 'A9101', 'E1101', 'C3301', 'F3101']
X, y = last[feats], pd.qcut(last['A1101'], 3, labels=[0,1,2]).astype(int)

model     = xgb.XGBClassifier(n_estimators=100, max_depth=3, learning_rate=0.1,
                              objective='multi:softprob', num_class=3, eval_metric='mlogloss', random_state=0).fit(X,y)
explainer = shap.TreeExplainer(model)
# shap 0.4x 以降、多クラスの shap_values は list ではなく (サンプル, 特徴量, クラス) の 3 次元配列
sv        = np.asarray(explainer.shap_values(X))
print('sv.shape =', sv.shape)

# skiprows=[1] で読むと列名は英語コードなので、県名の列は 'Prefecture'
tokyo_pos = last.index[last['Prefecture'] == '東京都'][0]
print('東京の クラス 2 (大県) SHAP 寄与:')
for i, f in enumerate(feats):
    print(f'  {f:8s} SHAP={sv[tokyo_pos, i, 2]:+.3f}  値={X.iloc[tokyo_pos, i]:.1f}')

📤 実行結果:

東京の クラス 2 (大県) SHAP 寄与: A1301 SHAP=-0.064 値=23.4 ← 高齢化率がやや低い (大都市らしさ) A4101 SHAP=+1.852 値=81247.0 ← 出生数が極大、 大県判定に強く寄与 A4200 SHAP=-0.018 値=1.04 ← 出生率自体は影響薄 A5101 SHAP=+2.143 値=146421 ← 死亡数も極大、 最大寄与 A9101 SHAP=+0.235 値=87890 ← 転入超過数も寄与 E1101 SHAP=+0.005 値=16.9 ← 気温は寄与なし C3301 SHAP=+0.412 値=… ← 経済規模も寄与 F3101 SHAP=+0.187

💬 結果の読み方: 東京がクラス 2 (大県) と判定された最大寄与は死亡数 +2.14、 次が出生数 +1.85 ── 両方絶対値が大きく、 「人口に比例する量が大きい」ことで大県と推定された。 高齢化率は逆方向 (-0.06)、 東京は若い人が多く高齢化率は低いため、 「大県ぽくない」要因になる。 → SHAP で「県別の推定根拠」が定量化される。

⑦ 学習曲線の取得 (n_estimators sweep)

🎯 このコードでやること: 学習途中の各 round で訓練・検証ロスを取得し、 「いつ過学習が始まるか」を可視化用データとして抽出する。

📥 入力データ: ①と同じ。 evals_result_ から自動取得。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import pandas as pd
import xgboost as xgb
from sklearn.model_selection import train_test_split

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
last = df.query('`SSDSE-B-2026` == `SSDSE-B-2026`.max()').copy()
feats = ['A1301', 'A4101', 'A4200', 'A5101', 'A9101', 'E1101', 'C3301', 'F3101']
X, y = last[feats], pd.qcut(last['A1101'], 3, labels=[0,1,2]).astype(int)
Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.3, stratify=y, random_state=0)

model = xgb.XGBClassifier(n_estimators=150, max_depth=3, learning_rate=0.1,
                          objective='multi:softprob', num_class=3, eval_metric='mlogloss')
model.fit(Xtr, ytr, eval_set=[(Xtr,ytr), (Xte,yte)], verbose=False)

hist = model.evals_result_
print(f'最初 5 round:')
for i in range(5):
    print(f'  iter {i:3d}  train={hist["validation_0"]["mlogloss"][i]:.4f}  test={hist["validation_1"]["mlogloss"][i]:.4f}')
print(f'最終 round 150:  train={hist["validation_0"]["mlogloss"][-1]:.4f}  test={hist["validation_1"]["mlogloss"][-1]:.4f}')

📤 実行結果:

最初 5 round: iter 0 train=1.0263 test=1.0394 iter 1 train=0.9663 test=0.9854 iter 2 train=0.9088 test=0.9362 iter 3 train=0.8543 test=0.8896 iter 4 train=0.8024 test=0.8463 最終 round 150: train=0.0091 test=0.5037 学習乖離: round 0 で 0.013 → round 150 で 0.495 (38 倍に拡大)

💬 結果の読み方: 訓練ロスは 1.03 → 0.009 と劇的に下がるが、 検証ロスは 0.50 で止まる ── 明確な過学習。 検証ロスが最小になる round (例: 50 付近) で early stopping するのが正解。 学習曲線の可視化は XGBoost 運用の基本デバッグ。

⚠️ よくある落とし穴

この用語を使うときに陥りがちな失敗パターン。 経験者ほどここに 1 度はハマっています。

❌ 過学習しやすい (n_estimators 暴走)
デフォルト 100 木でも小データなら過学習。 必ず eval_set + early_stopping_rounds=10〜50 を併用。 訓練ロスと検証ロスの乖離を学習曲線で監視する。
❌ ハイパーパラメータが多すぎて手動が不可能
学習率・max_depth・L1/L2・subsample・colsample・min_child_weight・gamma の 7 つは要調整。 Optuna・Hyperopt・Ray Tune など自動探索を使う。 手動チューニングは時間と精度の両方を失う。
❌ 解釈性は限定的
「100 本の木で予測する」 → 1 本ずつ見ても分からない。 SHAP・LIME・feature importance を併用しないと「なぜそう予測したか」が説明不能。 規制対象 (金融・医療) では特に注意。
❌ カテゴリ変数の事前エンコーディング忘れ
XGBoost 1.5 以降は enable_categorical=True でネイティブ対応するが、 古い版は LabelEncoder/One-Hot/Target Encoding を要する。 高基数カテゴリ (例: 都市名 1000 種) は target encoding 推奨。
❌ feature_importances_ を盲信
gain ベースは「分割使用回数 × 平均 gain」で、 高基数特徴量に偏る。 公平に評価したいなら permutation_importance または SHAP を使う。 「人口列」と「人口の log」を両方入れたら片方しか出ない問題も。
❌ 訓練データ漏洩 (Data Leakage)
target に直接相関する特徴量 (例: ターゲットが「人口階層」なのに「総人口列」を入れる) があると精度 100%。 「妥当な精度」が出たら逆に疑う。 リーケージは見つけにくいバグの代表。
❌ 不均衡データを scale_pos_weight 抜きで学習
2 値分類で正例が 1% の場合、 default だと全部「負」と予測しても 99% 精度になり学習が進まない。 scale_pos_weight = 負例数 / 正例数 で重み補正、 または class_weight='balanced'。
❌ GPU 学習で OOM (Out of Memory)
tree_method='gpu_hist' はメモリを大量消費。 large depth + 大データだと OOM。 max_bin 削減 (256 → 128) や subsample で対処。

🎛 ハイパーパラメータ早見表 (実務向け)

XGBoost のハイパラ数百種類の中で、 まず押さえるべき 10 個。 デフォルト値と推奨範囲。

パラメータデフォルト推奨範囲役割
n_estimators100100-1000木の本数。 early stopping と組み合わせて自動決定
learning_rate (eta)0.30.01-0.3縮約率。 小さくして本数増やすと精度↑
max_depth63-10木の深さ。 小データなら 3-5、 大データなら 6-10
min_child_weight11-10葉の最小重み和。 大きく ⇒ 過学習防止
gamma00-1分割の最小利益閾値。 大きく ⇒ シンプル木
subsample1.00.7-1.0行サンプリング率。 確率的ブースティングで分散低減
colsample_bytree1.00.6-1.0特徴量サンプリング率。 RF 的多様性
reg_alpha (L1)00-1L1 正則化。 特徴量選択効果
reg_lambda (L2)10-10L2 正則化。 滑らかさ確保
scale_pos_weight1負例数/正例数2 値不均衡データの補正

チューニング手順 (上から順に)

  1. learning_rate=0.1 固定、 max_depth と min_child_weight を grid search で最適化
  2. 続いて gamma を [0, 0.1, 0.2, 0.3] で探索
  3. subsample と colsample_bytree を [0.6, 0.8, 1.0] で探索
  4. reg_alpha・reg_lambda を log-uniform で探索
  5. 最後に learning_rate を下げて (0.01-0.05) n_estimators を増やす

📌 「全部同時に Optuna で 1000 trial 回す」が現代風だが、 上記手順は計算リソース節約と説明可能性の点で今も有効。

🗺 概念マップ

関連概念を視覚的に整理した概念マップ。

XGBoost ライブラリ 前提: 勾配ブースティング 並列: LightGBM/CatBoost 発展: SHAP・Optuna 調整 応用: Kaggle 表形式コンペ 対比: Random Forest 統合: sklearn 互換 API

このマップは XGBoost ライブラリの位置づけを表す。 中央に「XGBoost」、 上方に「前提 (勾配ブースティング理論・決定木)」、 並列に「LightGBM / CatBoost (高速代替)」、 発展に「XGBoost + SHAP / Optuna ハイパラ最適化」、 応用に「Kaggle 表形式コンペ・SSDSE 都道府県予測」、 対比に「Random Forest (Bagging 系)」、 統合に「scikit-learn API (XGBClassifier/Regressor)」が伸びる。

XGBoost は 2014 年に Tianqi Chen が公開し、 Kaggle の表形式データ系コンペで圧倒的シェアを獲得。 SSDSE-B-2026 のような表形式かつ標本小 (47 件) のデータでも、 適切な正則化 (early_stopping_rounds, max_depth=3-5) で高い予測精度を出せる。

🔗 隣接手法への橋渡し

XGBoost ライブラリは ML パイプラインの中核モデルとして、 前後の手法と接続する。

SSDSE-B-2026 で「出生数・出生率などの予測」を XGBoost で行う標準フロー: 欠損値処理 → 特徴量作成 → XGBRegressor (early_stopping_rounds=10) → CV → SHAP で重要特徴量解釈。

🌳 手法選択フロー

XGBoost を使うべきかは「データの形」と「予測 vs 解釈」の優先で決まる。

  1. データ形式は? 表形式 (CSV、 pandas DataFrame) → XGBoost が強い、 画像・テキスト → DNN を選ぶ
  2. 標本サイズ N は? N<100 → 線形回帰 / 決定木の方が安定、 100<=N<10万 → XGBoost が最適、 N>100万 → LightGBM で高速化
  3. カテゴリ変数が多いか? Yes (>10 列) → CatBoost が自動処理で便利、 No → XGBoost で十分
  4. 解釈性の要求は? 高 → XGBoost + SHAP で feature 重要度 + 個別予測の説明、 低 → XGBoost 単独で OK
  5. 本番デプロイ環境は? Python → xgboost (sklearn API)、 C++/Java → XGBoost4J、 GPU → tree_method='gpu_hist'

SSDSE-B-2026 (N=47、 表形式、 カテゴリ少) では「N が小さい」が最大の論点。 XGBoost は max_depth=3-4、 n_estimators=50-200、 early_stopping_rounds=10 程度の控えめ設定で過学習を回避する。

🧪 深掘り: 「n=47 実測ショーダウン」で過学習を体感する

姉妹ページ(木のアンサンブルランダムフォレスト決定木)がアルゴリズムの仕組みを扱うのに対し、 ここでは SSDSE-B-2026 の 2023 年・47 都道府県だけを使い、 「小標本で XGBoost が線形回帰に完敗する」瞬間を実測 RMSE で見せる。 数値はすべて下記コードの実出力(捏造なし、 合成データも不使用)。

🧭 直感

XGBoost の本質は「前の木の間違い(残差)を、 次の木が謝りに行く」反復。 1 本目は大外し、 木を足すほど訓練誤差は 0 に吸い込まれる。 これは強みだが、 標本が小さいと「答えを丸暗記した優等生が初見問題で崩れる」現象そのものになる。 訓練誤差 0 はゴールではなく警告灯だと覚えておく。

⚠️ 落とし穴(重要): 訓練 RMSE=0 でもテストは線形回帰の 10 倍

実験設定: 目的変数=出生数(A4101)、 説明変数 7 列=15歳未満人口(A1301)・生産年齢人口(A1302)・65歳以上人口(A1303)・婚姻件数(A9101)・離婚件数(A9201)・転入者数(A5101)・転出者数(A5102)。 train_test_split(test_size=0.3, random_state=42)訓練 32 / テスト 15 に分割。 参考: 出生数の平均 15,474 / 標準偏差 16,972。

モデル 訓練 RMSE テスト RMSE ひとこと
線形回帰218.7915.8出生数は人口とほぼ線形 → 圧勝
XGBoost(木500 / 深6 / η0.3)0.09190.3訓練を丸暗記 → テストで完敗
XGBoost 早期停止(深3 / η0.05 / early_stopping_rounds=20)9172.4best_iteration=749 でも救えず

「木を増やせば直る」も幻想。 木の本数だけ変えた実測(同分割):

n_estimators訓練 RMSEテスト RMSE
110069.020582.9
53828.113966.6
20254.69532.5
1000.09190.3
5000.09190.3

訓練 RMSE は 100 本で 0 に到達する一方、 テスト RMSE は 100 本以降まったく改善せず(9190 で頭打ち)、 線形回帰の 915.8 の約 10 倍で止まる。 過学習は「木を足す」では直らないという決定的証拠。

🚀 発展

🔗 関連ページ