- 技術 💻
XGBoostとは・使い方|Pythonで分類・回帰とLightGBM比較を実測
結論
XGBoostは、小さな決定木を1本ずつ足して前の木の誤差を直していく「勾配ブースティング」を、速く・過学習しにくく実装したライブラリです。表のデータ(売上・顧客・センサー値など)の分類と回帰で、いまも最初に試される手法の1つです。
この記事でわかること
- pip で入れて分類を動かすまでの最小手順と、その出力
- max_depth・learning_rate・early stopping が精度と時間をどう変えるかの実測
- LightGBM・ランダムフォレスト・線形モデルとの精度と学習時間の比較、エラー原文13件
XGBoostは「前の木が外した分を、次の木が埋める」ことを繰り返します。1本ずつの木は浅く弱いのですが、何百本も足し合わせると強いモデルになります。
flowchart TD
A[データ] --> B[最初の予測<br>全員に同じ値]
B --> C[誤差を計算<br>勾配と2階微分]
C --> D[誤差を減らす<br>小さな木を1本作る]
D --> E[学習率をかけて<br>予測に足す]
E --> F{検証データの<br>成績が伸びている?}
F -->|はい| C
F -->|いいえ 50回続いた| G[止める<br>最良の本数を使う]
よく調べられることの答えを先にまとめます。
| 知りたいこと | 答え | 詳しい節 |
|---|---|---|
| XGBoostとは | 決定木を順に足していく勾配ブースティングのライブラリ。正則化と速さが特長 | XGBoostとは(仕組み) |
| XGBoostのインストール | pip install xgboost。GPU を使わない Linux・Windows なら xgboost-cpu が軽い |
インストール |
| XGBoost Python の使い方 | XGBClassifier().fit(X, y) → predict。scikit-learn と同じ書き方 |
5分で動かす |
| どのパラメータから触るか | learning_rate と木の本数(early stopping)→ max_depth → subsample・colsample_bytree | ハイパーパラメータの影響 |
| early stopping の書き方 | 3.x はコンストラクタに early_stopping_rounds、fit に eval_set |
early stopping |
| 特徴量の重要度 | feature_importances_ は gain。相関の強い列に偏るので permutation と見比べる |
特徴量の重要度 |
| LightGBM との違い | 精度はほぼ同じ。この環境では LightGBM が少し速い。木の育て方が違う | 比較 |
| ランダムフォレストとの違い | 木を独立に作って平均(RF)か、順に誤差を直す(XGBoost)か。RF は調整が少なく済む | 比較 |
| 欠損値はそのままでよいか | NaN のまま学習できる。分岐ごとに欠損の行き先を学ぶ | 欠損値とカテゴリ変数 |
確認環境:Ubuntu 24.04.5 LTS(2 CPU・メモリ 8GB、他の処理と同居)の上で、Python 3.13.18 の venv に pip で xgboost-cpu 3.4.1(2026年10月29日時点の PyPI の最新)と LightGBM 4.7.0 を入れ、scikit-learn 1.9.1・NumPy 2.5.3・pandas 3.0.5 と組み合わせて実行しました。データは scikit-learn 同梱の breast_cancer(乳がん診断 569件)・diabetes(糖尿病の進行 442件)・iris と、make_classification・make_friedman1 で作った2万件の人工データだけで、外部からデータは取得していません。スレッド数は n_jobs=2(環境変数 OMP_NUM_THREADS=2)にそろえ、時間は3〜5回の中央値です。Python 3.11 で入らない様子は pip の dry-run で確かめました。GPU 版・Mac・Windows・conda の手順は XGBoost 公式ドキュメント(インストールガイド・Python パッケージ入門・パラメータ)と PyPI のファイル一覧で確かめた範囲です。LightGBM の木の育て方は LightGBM 公式ドキュメントで確かめました。図は mermaid 11.16.0 で描画を確かめています(確認日 2026年10月29日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「XGBoostとは・使い方|Pythonで分類・回帰とLightGBM比較を実測」
XGBoostを5分で動かす(Pythonの最小の使い方)
この節では、インストールから最初の予測までを最短で動かし、その出力を見られます。
XGBoostは scikit-learn と同じ fit・predict の形で使えます。まず動かして、仕組みは次の節で読むのが近道です。
仮想環境を作る
python3 -m venv .venv → source .venv/bin/activate(Windows は .venv\Scripts\activate)。プロジェクトごとに分けておくと、版の違いで困りません。
入れる
pip install xgboost scikit-learn。GPU を使わない Linux・Windows なら pip install xgboost-cpu scikit-learn のほうが軽く入ります。
下のコードを s1.py に保存して実行
同梱の乳がん診断データで、悪性か良性かを当てる2値分類です。ダウンロードは発生しません。
import time, xgboost as xgb, sklearn
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
print("xgboost", xgb.__version__, "scikit-learn", sklearn.__version__)
X, y = load_breast_cancer(return_X_y=True) # 569件・30列
X_tr, X_te, y_tr, y_te = train_test_split(
X, y, test_size=0.25, random_state=0, stratify=y)
t = time.perf_counter()
model = xgb.XGBClassifier(n_jobs=2, random_state=0) # 既定値のまま
model.fit(X_tr, y_tr)
print(f"train {time.perf_counter()-t:.3f}s")
pred = model.predict(X_te)
print("accuracy", round(accuracy_score(y_te, pred), 4))
print(model.predict_proba(X_te[:3]).round(4))
実行結果です。
xgboost 3.4.1 scikit-learn 1.9.1
train 0.444s
accuracy 0.951
[[3.000e-04 9.997e-01]
[9.996e-01 4.000e-04]
[9.998e-01 2.000e-04]]
predict_proba は「クラス0の確率、クラス1の確率」の順に並びます。この3件は、どれも 99.9% 以上の自信で分かれています。既定値のままでも、この程度のデータなら数行で動きます。ここから先は、精度を上げる・過学習を防ぐ・結果を説明するための節です。
XGBoostとは(勾配ブースティングの仕組み)
この節では、XGBoostが何をしているのかと、決定木・ランダムフォレストとの関係が分かります。
XGBoost(eXtreme Gradient Boosting)は、勾配ブースティング決定木(GBDT)を実装したオープンソースのライブラリです。Python・R・Java・Scala・C++ などから使え、分類・回帰・ランキングに対応します。2016年に Tianqi Chen と Carlos Guestrin が論文「XGBoost: A Scalable Tree Boosting System」(KDD 2016)で発表しました。
決定木・ランダムフォレスト・ブースティングの違い
ランダムフォレスト(バギング)
深い木を、データを少しずつ変えて独立に何百本も作る
全部の木の多数決・平均で予測する
並列に作れる。調整が少なくても安定しやすい
XGBoost(ブースティング)
浅い木を1本ずつ順番に作る
次の木は、前までの予測の誤差を減らす向きに作る
精度が出やすいが、木の本数と学習率の調整が要る
決定木1本は「年齢が40歳以上か」「血糖値が○○以上か」のような質問を枝分かれで並べたものです。機械学習の全体像や決定木・ランダムフォレストの考え方は、当社の記事「機械学習とは|種類・ディープラーニングとの違いを実行結果で解説」で扱っています。この記事は XGBoost の使い方と調整に絞ります。
「X(エクストリーム)」と呼ばれる理由
勾配ブースティング自体は、Friedman の論文「Greedy Function Approximation: A Gradient Boosting Machine」に由来する考え方です。XGBoostは、これに次の工夫を足して速く・強くしたものです。
正則化つきの目的関数
誤差に「木の複雑さ」の罰則を足して最小にする。公式チュートリアルの式は、葉の数 T と葉の値 w を使った γT + ½λΣw²。
gamma・reg_lambda・reg_alpha
2階微分まで使う
誤差の勾配に加えて2階微分(ヘッセ行列の対角)も使い、葉の値を一度で計算する。
学習が速く安定する
ヒストグラムで分岐を探す
値を最大256個の区間(max_bin)にまとめ、区切り位置の候補を減らす。3.x の既定 tree_method=auto は hist を使う。
大きなデータでも速い
欠損値を学習する
分岐ごとに「欠損ならどちらへ行くか」を学ぶ。NaN を埋めずにそのまま渡せる。
欠損値の節で実測
XGBoostが向いているデータ
XGBoostが力を出すのは、行と列でできた「表のデータ」です。画像・音声・長い文章は、ニューラルネットワーク(ディープラーニング)のほうが向いています。表のデータでも、件数が数百件で関係が直線的なら、線形回帰やロジスティック回帰に負けることがあります(回帰の節で実測します)。
XGBoostのインストール(pip・xgboost-cpu・conda・Mac・Windows)
この節では、環境に合った入れ方と、入らないときの原因が分かります。
Linux の pip install xgboost は、GPU 用の NCCL ライブラリ(nvidia-nccl-cu13)も一緒に入れます。GPU を使わないなら xgboost-cpu を選ぶと、ダウンロード量が大きく減ります。公式インストールガイドは xgboost-cpu について「ディスク使用量が大幅に小さいが、GPU のアルゴリズムは含まない」と説明しています。
pip の dry-run(実際には入れずに、入るものを表示する)で確かめた依存関係です。
$ pip install --dry-run --ignore-installed xgboost
Collecting nvidia-nccl-cu13 (from xgboost)
Would install numpy-2.5.4 nvidia-nccl-cu13-2.32.3 scipy-1.18.1 xgboost-3.4.1
PyPI に置かれている 3.4.1 の wheel(配布ファイル)の大きさを、OS ごとに並べました。
| OS・CPU | xgboost | xgboost-cpu | 選び方 |
|---|---|---|---|
| Linux x86_64 | 57.6MB+nvidia-nccl-cu13 305.1MB | 5.8MB | GPU が無ければ xgboost-cpu |
| Linux aarch64 | 57.2MB(+NCCL) | 5.4MB | 同上 |
| Windows x64 | 48.9MB | 2.2MB | GPU が無ければ xgboost-cpu |
| Mac(Apple シリコン) | 2.4MB | なし | xgboost を入れる。先に brew install libomp |
| Mac(Intel) | 2.5MB | なし | 同上 |
この環境で最初に pip install xgboost lightgbm scikit-learn pandas を素の venv に入れたところ、venv は 699MB、pip のキャッシュは 423MB になりました。--system-site-packages の venv に xgboost-cpu と lightgbm だけを入れ直すと 45MB で済みました。容量の限られた CI やコンテナでは、この差が効きます。
OS ごとの注意(公式ドキュメントで確かめた範囲)
- Mac:公式インストールガイドは、先に OpenMP ライブラリを
brew install libompで入れるよう書いています。OpenMP が無いと「CPU のコアを1つしか使わず、学習が遅くなる」とあります。 - Windows:Visual C++ 再頒布可能パッケージの DLL が要ります(Visual Studio が入っていれば不要)。
- conda:
conda install -c conda-forge py-xgboost。GPU の有無を見て版を選びます。CPU 版を明示するならpy-xgboost=*=cpu*。 - Google Colab:最初から入っていることが多く、
import xgboost; xgboost.__version__で版を確かめてから使います。Colab の使い方は関連記事「Google Colabとは|使い方・GPU・料金・制限とエラーの直し方」で扱っています。
Python 3.11 では最新版が入らない
XGBoost 3.3.0 から、条件が Requires-Python >=3.12 になりました。Python 3.11 で版を指定すると、次のように止まります。
$ python3.11 -m pip install "xgboost-cpu==3.4.1"
ERROR: Ignored the following versions that require a different python version: 3.3.0 Requires-Python >=3.12; 3.4.0 Requires-Python >=3.12; 3.4.1 Requires-Python >=3.12
ERROR: Could not find a version that satisfies the requirement xgboost-cpu==3.4.1 (from versions: 2.1.1, 2.1.2, 2.1.3, 2.1.4, 3.0.0, 3.0.1, 3.0.2, 3.0.3, 3.0.4, 3.0.5, 3.1.0rc1, 3.1.0, 3.1.1, 3.1.2, 3.1.3, 3.2.0)
ERROR: No matching distribution found for xgboost-cpu==3.4.1
版を指定しなければ、Python 3.11 では 3.2.0 が選ばれて入りました(Would install numpy-2.4.6 scipy-1.17.1 xgboost-cpu-3.2.0)。チームで版がずれる原因になるので、Python の版と XGBoost の版をそろえて requirements に書きます。仮想環境の作り方は関連記事「Python venvの使い方|作成・有効化コマンド早見表と有効化できない時の直し方」で扱っています。
XGBoostで分類する(2値分類・多クラス分類)
この節では、2値分類と多クラス分類で、XGBoostが自動で選ぶ設定と出力の形が分かります。
XGBClassifier は、ラベルの種類の数を見て目的関数を切り替えます。2種類なら binary:logistic、3種類以上なら multi:softprob です。iris(3種類のアヤメ)で確かめました。
from sklearn.datasets import load_iris
X, y = load_iris(return_X_y=True)
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.3, random_state=0, stratify=y)
m = xgb.XGBClassifier(n_jobs=2, random_state=0).fit(X_tr, y_tr)
print(m.objective, m.n_classes_)
print(m.predict_proba(X_te[:2]).round(3))
print("acc", round(accuracy_score(y_te, m.predict(X_te)), 4))
multi:softprob 3
[[0.001 0.004 0.995]
[0.001 0.011 0.988]]
acc 0.9556
objective="binary:logistic" を明示して3クラスのデータを渡しても、エラーにはならず multi:softprob に置き換わりました(get_xgb_params()["objective"] で確かめた結果)。逆に、ネイティブ API で multi:softmax を使うときは num_class が必須です(エラーの節)。
ラベルは 0 から始まる整数にする
XGBClassifier は、ラベルが 0, 1, 2, … の整数であることを求めます。1, 2, 3 や文字列のままだと止まります。scikit-learn の LabelEncoder で変換し、予測後に inverse_transform で戻します。
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
y_enc = le.fit_transform(["cat", "dog", "cat", "bird"]) # → [1 2 1 0]
# 予測後: le.inverse_transform(model.predict(X_new))
正解率以外の指標も見る
陽性が少ないデータ(不正検知・故障予測など)では、正解率だけでは判断を誤ります。XGBoostでは scale_pos_weight(陰性の数÷陽性の数が目安と公式パラメータ一覧にあります)で少数側を重く扱えます。適合率・再現率・F1 の読み方は、当社の記事「Precision(適合率)・再現率・正解率・F1の違い|陽性1%で実測」で扱っています。
XGBoostで回帰する(線形回帰に負けるデータもある)
この節では、XGBRegressor の使い方と、XGBoostを選ばないほうがよいデータの見分け方が分かります。
回帰は XGBRegressor に置き換えるだけです。目的関数の既定は reg:squarederror(二乗誤差)です。同梱の diabetes(442件・10列。1年後の病気の進行度を当てる)で、5分割の交差検証をしました。
from sklearn.datasets import load_diabetes
from sklearn.model_selection import cross_val_score, KFold
X, y = load_diabetes(return_X_y=True)
cv = KFold(5, shuffle=True, random_state=0)
m = xgb.XGBRegressor(n_jobs=2, random_state=0, max_depth=2, learning_rate=0.05, n_estimators=200)
s = -cross_val_score(m, X, y, cv=cv, scoring="neg_root_mean_squared_error")
print(f"RMSE {s.mean():.1f} ± {s.std():.1f}")
| モデル(diabetes・5分割) | RMSE(小さいほどよい) | ばらつき |
|---|---|---|
| XGBoost 既定値(深さ6・学習率0.3・100本) | 63.3 | ±3.6 |
| XGBoost 深さ2・学習率0.05・200本 | 56.3 | ±2.6 |
| LightGBM 既定値 | 57.7 | ±5.0 |
| ランダムフォレスト 既定値 | 58.2 | ±3.6 |
| 線形回帰(LinearRegression) | 54.5 | ±2.1 |
442件・10列で関係がほぼ直線的なデータでは、線形回帰がいちばんよい結果でした。XGBoostの既定値(深さ6)は木が深すぎて過学習し、深さ2に浅くするとかなり近づきました。一方、2万件の人工データ(make_friedman1。sin や2乗を含む非線形の関係)では、立場が逆転します。
| モデル(friedman1・2万件) | RMSE | 決定係数 R² |
|---|---|---|
| XGBoost 既定値 | 1.196 | 0.9420 |
| LightGBM 既定値 | 1.102 | 0.9508 |
| HistGradientBoosting | 1.119 | 0.9493 |
| ランダムフォレスト | 1.406 | 0.9199 |
| 線形回帰 | 2.649 | 0.7157 |
係数で「この列が1増えると結果がいくつ変わるか」を説明したいときは、線形回帰が向いています。線形回帰・ロジスティック回帰の読み方は、当社の記事「回帰分析とは|単回帰・重回帰・ロジスティック回帰の違いをp値・VIFで実演」で扱っています。まず線形モデルで基準の点数を出し、XGBoostで上回るかを確かめる順番にすると、無駄な調整を避けられます。
XGBoostの2つの書き方(scikit-learn APIとネイティブAPI)
この節では、XGBClassifier と xgb.train のどちらを使うか、それぞれの書き方が分かります。
同じ XGBoost でも入口が2つある
迷ったら scikit-learn API。細かい制御(独自の評価関数・学習の継続)が要るときにネイティブ API
ネイティブ API の書き方です。diabetes を学習264件・検証89件・テスト89件の3つに分けています。
dtr = xgb.DMatrix(X_tr, label=y_tr)
dva = xgb.DMatrix(X_va, label=y_va)
params = {"objective": "reg:squarederror", "max_depth": 3, "eta": 0.05,
"nthread": 2, "eval_metric": "rmse", "seed": 0}
bst = xgb.train(params, dtr, num_boost_round=1000,
evals=[(dtr, "train"), (dva, "valid")],
early_stopping_rounds=50, verbose_eval=50)
print("best_iteration", bst.best_iteration, "rounds", bst.num_boosted_rounds())
p_best = bst.predict(xgb.DMatrix(X_te), iteration_range=(0, bst.best_iteration + 1))
(264, 10) (89, 10) (89, 10)
[0] train-rmse:75.99374 valid-rmse:77.53275
[50] train-rmse:39.62929 valid-rmse:61.44042
[100] train-rmse:32.98559 valid-rmse:60.65951
[137] train-rmse:30.23668 valid-rmse:61.32080
best_iteration 87 best_score 60.452 rounds 138
test RMSE last 61.59 best 60.17
ネイティブ API の xgb.train は、early stopping で止まっても「最後の木まで入ったモデル」を返します。公式の Python パッケージ入門にもこの注意があり、最良の本数で予測するには iteration_range=(0, bst.best_iteration + 1) を渡します。この例では、検証データの成績が88本目で底を打ち、50本待って138本で止まりました。テストデータの RMSE は、全138本を使うと 61.59、最良の88本までだと 60.17 でした。scikit-learn API は、early stopping を使うと predict が自動で最良の本数を使います(次の次の節で確かめます)。
パラメータ名の対応
| 意味 | scikit-learn API | ネイティブ API | 既定値 |
|---|---|---|---|
| 学習率 | learning_rate | eta | 0.3 |
| 木の本数 | n_estimators | num_boost_round(train の引数) | 100(sklearn)/10(train) |
| スレッド数 | n_jobs | nthread | 使えるだけ使う |
| 乱数の種 | random_state | seed | 0 |
| L2・L1 正則化 | reg_lambda・reg_alpha | lambda・alpha | 1・0 |
| 木の深さ | max_depth | max_depth | 6 |
既定値は、学習したモデルの get_booster().save_config() を読んで確かめました(eta 0.3・max_depth 6・min_child_weight 1・gamma 0・subsample 1・colsample_bytree 1・lambda 1・alpha 0・max_bin 256・grow_policy depthwise)。木の本数はモデルの num_boosted_rounds() で 100 でした。
スレッド数(n_jobs)の効き方
既定では、XGBoostは使える CPU のスレッドを全部使います。2 CPU のこの環境で、1万2,800件・20列の学習時間を比べました。
| 設定 | 学習時間(5回の中央値) |
|---|---|
| n_jobs=1 | 0.51秒 |
| n_jobs=2 | 0.33秒 |
公式の scikit-learn 連携の説明は、GridSearchCV などと組み合わせるとき、scikit-learn 側の n_jobs と XGBoost 側のスレッドが取り合う「スレッドの奪い合い」に注意するよう書いています。どちらか片方だけで並列にするのが基本で、この記事では GridSearchCV を n_jobs=1、XGBoost を n_jobs=2 にしました。
XGBoostのハイパーパラメータの影響を実測(max_depth・learning_rate・subsample)
この節では、主なハイパーパラメータを動かしたとき、精度・過学習・学習時間がどう変わるかが数値で分かります。
2万件・20列の人工データ(make_classification。8列が本当に効き、4列はその組み合わせ、残りはノイズ。3% のラベルをわざと反転)を、学習 1万2,800件・検証 3,200件・テスト 4,000件に分けて比べました。logloss は予測確率のずれを表す値で、小さいほどよい指標です。
max_depth(木の深さ)
| max_depth | 学習データの logloss | 検証データの logloss | テスト正解率 | 学習時間 |
|---|---|---|---|---|
| 1 | 0.3367 | 0.3160 | 87.52% | — |
| 2 | 0.2501 | 0.2479 | 90.32% | 0.14秒 |
| 4 | 0.1296 | 0.1968 | 93.03% | — |
| 6(既定) | 0.0385 | 0.1870 | 93.50% | 0.29秒 |
| 8 | 0.0107 | 0.1808 | 94.30% | — |
| 12 | 0.0045 | 0.1943 | 94.05% | 0.95秒 |
(木は100本・学習率0.3。時間は1万5,000件で3回の中央値を測った深さだけ載せています)
深くするほど学習データの logloss は 0 に近づきますが、検証データは深さ8を底に悪化しました。学習データだけ良くなって検証データが悪くなるのが過学習です。深さ12は深さ6の約3倍の時間がかかり、精度は上がりませんでした。
learning_rate(学習率)と木の本数
学習率は「1本の木の予測をどれだけ足すか」の係数です。木の本数を100本に固定すると、次のようになりました。
| learning_rate | 学習データ logloss | 検証データ logloss | テスト正解率 |
|---|---|---|---|
| 0.01 | 0.3728 | 0.3879 | 89.28% |
| 0.05 | 0.1753 | 0.2128 | 92.27% |
| 0.1 | 0.1274 | 0.1924 | 92.83% |
| 0.3(既定) | 0.0385 | 0.1870 | 93.50% |
| 1.0 | 0.0026 | 0.2992 | 93.05% |
100本固定だと、学習率0.01は学び足りず(学習データでも誤差が大きい)、1.0は学びすぎ(学習データは 0.0026 なのに検証は悪化)です。この表だけを見て「0.3が最適」と決めるのは早計です。学習率を小さくしたぶん木を増やせば、結果は変わります。それを自動でやるのが次の節の early stopping です。
subsample・colsample_bytree(行と列の間引き)
木を1本作るたびに、使う行(subsample)や列(colsample_bytree)をランダムに一部だけにすると、木どうしが似にくくなり過学習が減ることがあります。学習率0.1・early stopping つきで比べました。
| subsample | colsample_bytree | 最良の本数 | 検証 logloss | テスト正解率 |
|---|---|---|---|---|
| 1.0 | 1.0 | 331 | 0.1778 | 93.70% |
| 0.8 | 1.0 | 187 | 0.1786 | 93.67% |
| 1.0 | 0.8 | 356 | 0.1701 | 93.90% |
| 0.8 | 0.8 | 365 | 0.1728 | 94.20% |
| 0.5 | 0.5 | 335 | 0.1823 | 93.70% |
(最良の本数は best_iteration+1。以下の表も同じ)
0.8前後で少し良くなり、0.5まで減らすと戻りました。差は 0.5 ポイント程度で、学習率と本数ほどは効きません。調整の順番は次のとおりです。
- 1learning_rate を 0.05〜0.1 にして early stopping で本数を決めるいちばん効く。n_estimators は大きめ(1000〜3000)にしておく
- 2max_depth を 3〜8 で試すデータが少ないほど浅く。min_child_weight も合わせて上げると過学習が減る
- 3subsample・colsample_bytree を 0.7〜0.9 にする効果は小さいが、外れにくい
- 4reg_lambda・reg_alpha・gamma で正則化を強めるそれでも検証の成績が学習データより大きく悪いとき
- 5最後に学習率を下げて本数を増やすわずかに伸びるが、時間は本数に比例して増える
GridSearchCV で探す
scikit-learn API なので、GridSearchCV にそのまま入ります。乳がん診断データで18通り×3分割を探したところ、6.5秒でした。
from sklearn.model_selection import GridSearchCV
g = GridSearchCV(
xgb.XGBClassifier(n_jobs=2, random_state=0, n_estimators=200),
{"max_depth": [2, 4, 6], "learning_rate": [0.05, 0.1, 0.3], "subsample": [0.8, 1.0]},
cv=3, scoring="accuracy", n_jobs=1)
g.fit(X_tr, y_tr)
print(g.best_params_, round(g.best_score_, 4))
grid 18 combos x3 folds 6.5s
{'learning_rate': 0.1, 'max_depth': 6, 'subsample': 0.8} 0.9624 test 0.951
交差検証の最良 96.24% に対し、テストデータでは 95.1% で、既定値と同じでした。小さなデータでは、探索で選んだ組み合わせがテストで伸びないことはよくあります。探索の点数とテストの点数は分けて記録しておきます。
XGBoostのearly stoppingの使い方
この節では、early stopping の書き方と、学習率ごとに最良の本数と時間がどう変わるかが分かります。
early stopping は、検証データの成績が一定回数続けて良くならなかったら学習を止める仕組みです。XGBoost 3.4.1 の scikit-learn API では、early_stopping_rounds をコンストラクタに書き、fit には eval_set を渡します。以前の版のように fit(early_stopping_rounds=…) と書くとエラーになります(エラーの節)。
m = xgb.XGBClassifier(n_jobs=2, random_state=0, learning_rate=0.1,
n_estimators=3000, early_stopping_rounds=50)
m.fit(X_tr, y_tr, eval_set=[(X_tr, y_tr), (X_va, y_va)], verbose=False)
print(m.best_iteration, m.best_score)
r = m.evals_result() # validation_0 = 学習, validation_1 = 検証
early stopping は eval_set の最後のデータで判定します(公式の説明では「複数あるときは最後を使う」)。学習データを並べるなら先に、検証データを最後に置きます。学習の途中経過を抜き出しました。
| 木の本数 | 学習データ logloss | 検証データ logloss |
|---|---|---|
| 1本目 | 0.6345 | 0.6365 |
| 51本目 | 0.1740 | 0.2132 |
| 101本目 | 0.1267 | 0.1924 |
| 201本目 | 0.0764 | 0.1835 |
| 331本目(最良) | 0.0386 | 0.1778 |
| 381本目(停止) | 0.0299 | 0.1793 |
学習データの誤差は最後まで下がり続けますが、検証データは331本目(best_iteration は0から数えるので 330)で底を打ち、そこから50本改善が無かったので381本で止まりました。モデルの中には381本の木が残っていますが、m.predict_proba の結果は、ネイティブ API で iteration_range=(0, 331) を指定した結果と一致し、全381本を使った結果とは違いました。scikit-learn API は、最良の本数で自動的に予測します。
logloss(交差エントロピー)の意味と計算は、関連記事「エントロピーとは|意味・計算・交差エントロピーをPythonで実演」で扱っています。
学習率ごとの最良の本数と時間
上限3,000本・50回改善なしで止める設定で、学習率だけを変えました。
| learning_rate | 最良の本数 | 検証 logloss | テスト正解率 | 学習時間 |
|---|---|---|---|---|
| 0.01 | 2,847 | 0.1758 | 93.73% | 9.08秒 |
| 0.05 | 597 | 0.1751 | 93.75% | 2.46秒 |
| 0.1 | 331 | 0.1778 | 93.70% | 2.12秒 |
| 0.3 | 68 | 0.1834 | 93.13% | 0.53秒 |
| 1.0 | 13 | 0.2388 | 91.85% | 0.32秒 |
10.05 と 0.01 はほぼ同じ精度
検証 logloss は 0.1751 と 0.1758。0.01 は本数が約5倍、時間が約4倍になった。
20.3 は速いが少し落ちる
既定の 0.3 は 0.53 秒で済むが、正解率は 0.6 ポイント低い。試作には向く。
31.0 は13本で頭打ち
1本ごとの修正が大きすぎて、細かい調整ができない。
試作は 0.3、仕上げは 0.05〜0.1 にして early stopping に本数を任せる、という使い分けがこの結果から言えます。
テストデータで止めない
early stopping の eval_set にテストデータを渡すと、テストデータを見て本数を選んだことになり、テストの点数が実力より良く出ます。学習・検証・テストの3つに分け、テストは最後の1回だけ使います。データが少なくて3つに分けにくいときは、xgb.cv(交差検証つきの学習)で本数を決めます。
cv = xgb.cv({"objective": "binary:logistic", "max_depth": 3, "eta": 0.1,
"nthread": 2, "eval_metric": "logloss", "seed": 0},
xgb.DMatrix(X, label=y), num_boost_round=1000, nfold=5,
stratified=True, early_stopping_rounds=30, seed=0)
print(cv.tail(1)); print("rounds", len(cv))
train-logloss-mean train-logloss-std test-logloss-mean test-logloss-std
174 0.0073 0.0003 0.0834 0.0389
rounds 175
乳がん診断データ全体で5分割した結果、175本が最良でした。この本数で全データを学習し直して使います。
XGBoostの特徴量の重要度(gain・weight・permutation・SHAP値)
この節では、重要度の種類ごとの違いと、feature_importances_ をそのまま信じると誤る例が分かります。
XGBoostの feature_importances_ は、木のモデル(gbtree)では gain(その列で分岐したときの誤差の減り方の平均)を合計1にしたものです。この環境で get_score(importance_type="gain") を合計1にした値と一致することを確かめました。
どの列が効くかを最初から分かっているデータで確かめました。make_classification を shuffle=False で作ると、先頭4列が本当に効く列(inf0〜inf3)、次の2列がその組み合わせで作った重複の列(red0・red1)、残り4列がノイズになります。
b = m.get_booster()
imp = {t: b.get_score(importance_type=t) for t in ["weight", "gain", "total_gain", "cover"]}
from sklearn.inspection import permutation_importance
pi = permutation_importance(m, X_te, y_te, n_repeats=5, random_state=0)
| 列 | weight(分岐回数) | gain(平均) | feature_importances_ | permutation |
|---|---|---|---|---|
| inf0(効く) | 343 | 10.930 | 0.151 | 0.156 |
| inf1(効く) | 514 | 9.619 | 0.133 | 0.187 |
| inf2(効く) | 293 | 7.152 | 0.099 | 0.088 |
| inf3(効く) | 406 | 8.351 | 0.115 | 0.109 |
| red0(重複) | 157 | 3.888 | 0.054 | 0.015 |
| red1(重複) | 217 | 24.972 | 0.345 | 0.141 |
| noise0〜3 | 91〜113 | 1.41〜2.29 | 0.020〜0.032 | 0.003〜0.007 |
gain では、重複の列 red1 が 0.345 で1位になりました。red1 は効く列を組み合わせて作った列なので、最初の分岐で一度に大きく誤差を減らせます。そのぶん gain が大きく出ます。テストデータの列を1つずつ並べ替えて正解率の落ち方を見る permutation importance では、inf1 が1位、red1 は4位でした。ノイズ列はどの指標でも下位で、その点はどれも正しく見分けています。
列どうしの相関を整理する方法の1つに主成分分析があります。考え方は関連記事「主成分分析(PCA)とは|手順・寄与率・負荷量の読み方をPythonで実演」で扱っています。
1件ごとの理由を出す(pred_contribs)
「なぜこの人は陽性と予測されたのか」を1件ずつ説明したいときは、predict(..., pred_contribs=True) が使えます。shap ライブラリを入れなくても、XGBoost自身が各列の寄与(SHAP 値)を計算します。
c = b.predict(xgb.DMatrix(X_te.iloc[:1]), pred_contribs=True)
print(dict(zip(cols + ["bias"], c[0].round(3))), "sum", c[0].sum().round(4))
print("margin", b.predict(xgb.DMatrix(X_te.iloc[:1]), output_margin=True).round(4))
contribs row0: {'inf0': -1.21, 'inf1': -0.998, 'inf2': -0.103, 'inf3': -0.66, 'red0': -0.304, 'red1': -0.538, 'noise0': -0.021, 'noise1': -0.04, 'noise2': -0.089, 'noise3': -0.03, 'bias': -0.009} sum -4.0022 margin [-4.0022]
寄与の合計(-4.0022)が、確率に変換する前の予測値(margin)と一致しています。この件は inf0 と inf1 が強く「陰性側」に押したことが分かります。
XGBoostの欠損値とカテゴリ変数の扱い
この節では、NaN と文字列の列をXGBoostに渡したときに何が起きるかが分かります。
欠損値(NaN)はそのまま渡せる
上の10列のデータで、学習・テストとも全セルの20%をランダムに NaN にして学習しました。
| モデル | NaN 20% のデータで |
|---|---|
| XGBoost | そのまま学習。テスト正解率 81.6% |
| ランダムフォレスト(scikit-learn 1.9.1) | そのまま学習。テスト正解率 82.4% |
| ロジスティック回帰 | ValueError: Input X contains NaN. |
XGBoostは、分岐ごとに「欠損ならどちらへ進むか(default direction)」を学習します。get_booster().trees_to_dataframe() で木の中身を表にすると、Missing の列に欠損時の行き先が入っているのが見えます。
Tree Target Node ID Feature Split Yes No Missing Gain Cover
0 0 0 0 0-0 f23 888.3 0-1 0-2 0-2 385.68848 133.0123
1 0 0 1 0-1 f27 0.1607 0-3 0-4 0-4 61.058113 90.23331
ただし、NaN と違って inf(無限大)はエラーになります。0 や -999 で欠損を表しているデータは、そのままだと「0という値」として扱われるので、missing=-999 を指定するか、NaN に置き換えてから渡します。
カテゴリ変数は pandas の category 型で渡す
pandas の DataFrame に文字列(object・str 型)の列があると、XGBoostは学習を止めます。astype("category") にすると、そのまま学習できました。XGBoost 3.4.1 の scikit-learn API では enable_categorical の既定値が True になっていることを get_params() で確かめました(公式の API 説明には「3.1.0 で変更」とあります)。
df["color"] = df["color"].astype("category")
m = xgb.XGBClassifier(n_jobs=2).fit(df, y) # 3.4.1 はこのまま通る
m = xgb.XGBClassifier(n_jobs=2, enable_categorical=True).fit(df, y) # 以前の版でも通る書き方
カテゴリの種類が多い列(郵便番号・商品 ID など)は、木が細かく分かれて過学習しやすくなります。種類を減らす・出現回数で置き換えるなどの前処理を先に検討します。pandas の型変換や集計は、関連記事「pandasの使い方 逆引き81選|pandas 3.0の実行結果つき」で扱っています。
XGBoost・LightGBM・ランダムフォレストの比較(精度と学習時間)
この節では、よく比べられる手法と同じデータ・同じ条件で並べた結果と、どれを選ぶかの判断表が分かります。
2万件・20列の分類(学習1万5,000件・テスト5,000件)で、どれも既定値・n_jobs=2 で比べました。時間は5回の中央値です。
| 手法(既定値) | テスト正解率 | AUC | 学習時間 |
|---|---|---|---|
| XGBoost 3.4.1 | 93.76% | 0.9732 | 0.37秒 |
| LightGBM 4.7.0 | 93.42% | 0.9736 | 0.28秒 |
| HistGradientBoosting(scikit-learn) | 92.92% | 0.9727 | 0.32秒 |
| ランダムフォレスト(100本) | 93.02% | 0.9716 | 2.97秒 |
| GradientBoosting(scikit-learn・旧来型) | 90.58% | 0.9600 | 約21秒(3回) |
| ロジスティック回帰 | 86.44% | 0.9277 | 0.03秒 |
XGBoost・LightGBM・HistGradientBoosting の3つは、精度も時間もほぼ横並びでした。AUC の差は 0.001 以下で、データの分け方を変えれば順位は入れ替わる程度です。回帰(friedman1・2万件)では LightGBM 0.17秒・XGBoost 0.23秒・HistGradientBoosting 0.38秒・ランダムフォレスト 6.08秒でした。小さな同梱データ(乳がん診断・5分割)では、XGBoost 97.36%・LightGBM 97.19%・ランダムフォレスト 96.49%・標準化したロジスティック回帰 97.89% で、ここでも線形モデルが健闘しました。
なお、時間は他の処理と同居した2 CPU での値です。最初の測定では、同居の負荷が高い時間帯に XGBoost が 4.25秒・HistGradientBoosting が 19.82秒かかったこともありました。学習時間を比べるときは、同じ時間帯に繰り返して中央値を取ります。
LightGBM との違い
LightGBM の公式ドキュメントは、LightGBM が木を「葉ごと(leaf-wise・best-first)」に育て、誤差が最も減る葉から分けると説明しています。XGBoostの既定は grow_policy=depthwise(深さごとに均等に育てる)で、この環境の設定でも確かめました。LightGBM の公式は「leaf-wise はデータが少ないと過学習することがある」とも書いています。XGBoostでも grow_policy="lossguide" と max_leaves で葉ごとに近い育て方ができます。
判断表:どれを使うか
| 状況 | まず試すもの | 理由 |
|---|---|---|
| 表データ・数千件以上・非線形 | XGBoost か LightGBM | 精度と速さの釣り合いがよい。資料と事例が多い |
| 数百件・関係がほぼ直線的 | 線形回帰・ロジスティック回帰 | diabetes・乳がん診断で XGBoost と同等以上だった |
| 調整に時間をかけられない | ランダムフォレスト | 既定値で大きく外しにくい。ただし学習は遅め |
| 依存ライブラリを増やしたくない | HistGradientBoosting | scikit-learn だけで済み、精度・時間とも近かった |
| 数百万件以上・メモリが厳しい | LightGBM(XGBoost の外部メモリ・GPU も候補) | この環境では LightGBM がいちばん速かった |
| 係数で説明したい | 線形モデル | XGBoost は寄与(SHAP 値)で説明する形になる |
| 画像・音声・長い文章 | ニューラルネットワーク | 木のモデルは生の画素や文字列を扱うのに向かない |
XGBoostのモデルの保存と読み込み
この節では、学習したモデルを保存する形式と、それぞれの大きさが分かります。
公式が勧める保存方法は save_model で、形式は JSON か UBJSON(拡張子 .ubj)です。200本・深さ4のモデルで大きさを比べました。
m.save_model("model.json") # 人が読める
m.save_model("model.ubj") # バイナリ。少し小さい
m2 = xgb.XGBClassifier()
m2.load_model("model.json")
print(np.array_equal(m.predict_proba(X_te), m2.predict_proba(X_te))) # True
| 形式 | 大きさ | 向いている場面 |
|---|---|---|
| JSON(.json) | 365,021バイト | 中身を確かめたい・別の言語の XGBoost で読む |
| UBJSON(.ubj) | 299,199バイト | 大きなモデルを小さく保存したい |
| pickle(.pkl) | 309,340バイト | Pipeline ごと保存したいとき。同じ版の Python・ライブラリで読む前提 |
JSON の最上位は learner と version で、learner の下に feature_names・gradient_booster(木の本体)・objective などが入っていました。読み込んだモデルの予測は、元のモデルと完全に一致しました。pickle は前処理を含めた Pipeline ごと保存できて便利ですが、信頼できない人から受け取った pickle は読み込みません(読み込むだけで任意のコードが動く形式のため)。
XGBoostのよくあるエラーと直し方
この節では、XGBoostで実際に出たエラー・警告の原文と、その原因と直し方が分かります。
すべて XGBoost 3.4.1 で実際に起こしたものです。長いスタックトレースは先頭だけ載せています。
| エラー・警告の原文 | 原因 | 直し方 |
|---|---|---|
ValueError: Invalid classes inferred from unique values of `y`. Expected: [0 1 2], got [1 2 3] |
ラベルが 0 始まりでない。文字列でも同じ(got ['a' 'b' 'c']) | LabelEncoder で 0〜n-1 に変換 |
TypeError: XGBClassifier.fit() got an unexpected keyword argument 'early_stopping_rounds' |
以前の版の書き方(fit に渡す形) | コンストラクタに early_stopping_rounds を書く |
ValueError: Must have at least 1 validation dataset for early stopping. |
early_stopping_rounds があるのに eval_set が無い | fit(..., eval_set=[(X_va, y_va)]) |
ValueError: DataFrame.dtypes for data must be int, float, bool or category. … Invalid columns:color: str |
文字列の列が残っている | astype("category") にするか数値に変換 |
ValueError: feature_names mismatch: ['sl', 'sw', 'pl', 'pw'] ['sw', 'sl', 'pl', 'pw'] |
予測時の列の順番・名前が学習時と違う | X_new[model.feature_names_in_] で並べ直す |
ValueError: Feature shape mismatch, expected: 4, got 3 |
NumPy 配列の列数が違う | 学習時と同じ前処理を通す(Pipeline にまとめる) |
XGBoostError: … Check failed: valid: Input data contains `inf` or a value too large, while `missing` is not set to `inf` |
データに無限大(0での割り算など) | np.isinf で探して NaN に置き換える |
XGBoostError: … Check failed: valid: Label contains NaN, infinity or a value too large. |
目的変数(ラベル)に NaN | ラベルが欠けた行を除く |
XGBoostError: Invalid Input: 'gpu_hist', valid values are: {'approx', 'auto', 'exact', 'hist'} |
2.0 で非推奨になった書き方。3.4.1 では受け付けない | tree_method="hist", device="cuda" |
WARNING: … Device is changed from GPU to CPU as we couldn't find any available GPU on the system. |
GPU の無い環境で device="cuda" | CPU で動く。GPU を使うなら GPU と CUDA を用意 |
WARNING: … Parameters: { "use_label_encoder" } are not used. |
廃止されたパラメータ。綴り間違い(max_deph)も同じ警告 |
パラメータを消す・綴りを直す。警告なので学習は進む点に注意 |
XGBoostError: value 0 for Parameter num_class should be greater equal to 1 |
ネイティブ API の multi:softmax に num_class が無い | "num_class": 3 を足す |
AttributeError: 'XGBRegressor' object has no attribute 'predict_proba' |
回帰モデルで確率を求めた | 分類なら XGBClassifier を使う |
いちばん見落としやすいのは、綴りを間違えたパラメータが「警告だけで無視される」ことです。max_deph=3 と書いても学習は既定の深さ6で進み、エラーになりません。ログの Parameters: { … } are not used. は必ず読みます。
Python 3.11 で最新版が入らないエラーは、インストールの節に原文があります。
XGBoostのよくある質問
この節では、XGBoostについてよく検索される疑問に短く答えます。
Q. XGBoostは何の略ですか。
eXtreme Gradient Boosting の略です。勾配ブースティングを、速く・大規模に動くよう工夫したライブラリという意味で、XGB と略されることもあります。
Q. XGBoostは無料で使えますか。
オープンソース(Apache License 2.0)で、商用でも無料で使えます。ライセンスの詳細は公式リポジトリで確かめます。
Q. XGBoostとLightGBMはどちらがよいですか。
この記事の比較では精度はほぼ同じで、LightGBM が少し速い結果でした。チームで使い慣れているほう、または既存のコードがあるほうを選び、両方試して検証データで決めるのが確実です。
Q. XGBoostとランダムフォレストの違いは何ですか。
ランダムフォレストは木を独立に作って平均し、XGBoostは前の木の誤差を次の木が直すように順に作ります。この記事のデータでは XGBoost が精度で少し上、学習時間は約8分の1でした。ランダムフォレストは調整が少なくても安定しやすい利点があります。
Q. XGBoostに標準化(スケーリング)は要りますか。
要りません。木は「ある値より大きいか」で分けるだけなので、列の単位や大きさは結果に影響しません。線形モデルやニューラルネットワークと組み合わせるときだけ標準化します。
Q. 何件くらいのデータから使えますか。
数百件でも動きますが、diabetes(442件)では線形回帰に負けました。数千件以上で、列どうしの関係が複雑なデータほど強みが出ます。少ないときは max_depth を2〜3に下げます。
Q. GPU は要りますか。
要りません。この記事の実験はすべて CPU 2つで、1回の学習は1秒未満〜数秒でした。数百万件以上のデータや大量の探索をするときに GPU(device="cuda")が効きます。
Q. 学習のたびに結果が変わります。random_state(ネイティブ API は seed)を固定します。subsample・colsample_bytree を1未満にしているときは、乱数で使う行や列が変わるため、固定しないと結果がぶれます。
Q. 予測が確率ではなく0と1で返ってきます。predict はクラスを返します。確率は predict_proba を使います。しきい値(既定0.5)を変えたいときは、確率を取り出して自分で比べます。
Q. Kaggle でよく使われるのはなぜですか。
表のデータで精度が出やすく、欠損値を前処理せずに扱え、学習が速いため、試行錯誤の回数を増やせるからです。上位の解法では、XGBoost・LightGBM・CatBoost などを組み合わせることもよくあります。
まとめ
この節では、XGBoostを使うときに押さえる点を5つにまとめます。
- XGBoostは、浅い決定木を1本ずつ足して誤差を直す勾配ブースティングのライブラリで、表のデータの分類・回帰に強い。
- 入れるのは
pip install xgboost。GPU を使わない Linux・Windows ならxgboost-cpuでダウンロードが大幅に小さくなる。最新版は Python 3.12 以上。 - 調整は learning_rate と early stopping から。0.05〜0.1 にして本数を任せると、0.01 とほぼ同じ精度を約4分の1の時間で得られた。
- feature_importances_ は gain で、相関の強い列に偏る。permutation importance や pred_contribs と見比べる。
- LightGBM・HistGradientBoosting とは精度・速さとも横並び。小さく直線的なデータでは線形モデルが勝つので、まず線形モデルで基準を作ってから比べる。
参考・出典
この節では、この記事で確かめた公式の情報源をまとめます(確認日 2026年10月29日)。
- XGBoost 公式ドキュメント「Installation Guide」:https://xgboost.readthedocs.io/en/stable/install.html
- XGBoost 公式ドキュメント「Python Package Introduction」(early stopping・保存形式):https://xgboost.readthedocs.io/en/latest/python/python_intro.html
- XGBoost 公式ドキュメント「Using the Scikit-Learn Estimator Interface」:https://xgboost.readthedocs.io/en/stable/python/sklearn_estimator.html
- XGBoost 公式ドキュメント「Introduction to Boosted Trees」(正則化の式):https://xgboost.readthedocs.io/en/stable/tutorials/model.html
- XGBoost 公式ドキュメント「Python API Reference」:https://xgboost.readthedocs.io/en/stable/python/python_api.html
- PyPI「xgboost」「xgboost-cpu」(版・wheel の大きさ・Requires-Python):https://pypi.org/project/xgboost/ ・ https://pypi.org/project/xgboost-cpu/
- LightGBM 公式ドキュメント「Features」(leaf-wise の木の育て方):https://lightgbm.readthedocs.io/en/stable/Features.html
- Tianqi Chen, Carlos Guestrin「XGBoost: A Scalable Tree Boosting System」KDD 2016:https://arxiv.org/abs/1603.02754
- scikit-learn 公式ドキュメント「Toy datasets」(breast_cancer・diabetes・iris):https://scikit-learn.org/stable/datasets/toy_dataset.html
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「XGBoostとは・使い方|Pythonで分類・回帰とLightGBM比較を実測」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。