The Story That Explains XGBoostवह कहानी जो XGBoost समझाती है一个解释 XGBoost 的故事
This is gradient boosting, the idea behind XGBoost. Each model is not independent: each one corrects the leftover errors of the ones before it. XGBoost (eXtreme Gradient Boosting) is the engineering that makes this fast, regularised against overfitting, and very accurate.
यही gradient boosting है, XGBoost के पीछे का विचार। हर model independent नहीं है: हर एक अपने से पहले वालों की बची हुई errors ठीक करता है। XGBoost (eXtreme Gradient Boosting) वह engineering है जो इसे तेज़, overfitting के ख़िलाफ़ regularised, और बहुत सटीक बनाती है।
这就是 XGBoost 背后的思想:梯度提升。每个 model 都不是独立的,每一个都在修正前面所有 model 留下的误差。XGBoost(eXtreme Gradient Boosting)是让这个过程变得快速、带正则化防止过拟合、并且非常准确的工程实现。
XGBoost was created by Tianqi Chen in 2014 and led Kaggle leaderboards for years. It is still one of the strongest tools for tabular data. It combines gradient boosting with regularisation, missing-value handling and fast parallel computation.
XGBoost को Tianqi Chen ने 2014 में बनाया और यह सालों तक Kaggle leaderboards पर आगे रहा। Tabular data के लिए यह अब भी सबसे मज़बूत tools में से एक है। यह gradient boosting को regularisation, missing values संभालने और तेज़ parallel computation के साथ जोड़ता है।
XGBoost 由陈天奇于 2014 年创建,多年来一直领跑 Kaggle 排行榜,至今仍是处理表格数据最强的工具之一。它把梯度提升与正则化、缺失值处理和快速的并行计算结合在一起。
XGBoost builds decision trees one after another. Each new tree fits the negative gradient of the loss left by all the earlier trees, and adds a small correction to the prediction.
XGBoost decision trees एक के बाद एक बनाता है। हर नया tree पिछले सभी trees के बाद बचे loss के negative gradient को fit करता है, और prediction में एक छोटा सुधार जोड़ता है।
XGBoost 一棵接一棵地构建决策树。每棵新树拟合前面所有树留下的 loss 负梯度,并给预测加上一个小小的修正。
XGBoost in Pictures — Understand It Before the Mathsतस्वीरों में XGBoost — गणित से पहले समझें图解 XGBoost — 先理解,再学数学
Before any formula, here is the whole idea in four pictures. If you understand these, the rest of the page is just details.
किसी भी formula से पहले, पूरा विचार चार तस्वीरों में। अगर ये समझ आ गईं, तो बाकी page सिर्फ़ details है।
在任何公式之前,先用四张图讲清楚整个思想。看懂了这些,页面其余部分只是细节。
A single tree gives a rough answer. XGBoost starts from the average and adds many small trees. Each new tree only tries to fix what is still wrong.
एक अकेला tree मोटा जवाब देता है। XGBoost average से शुरू करके बहुत सारे छोटे trees जोड़ता है। हर नया tree सिर्फ़ वह ठीक करने की कोशिश करता है जो अभी भी गलत है।
单独一棵树只能给出粗略的答案。XGBoost 从平均值出发,加上很多小树。每棵新树只负责修正仍然错误的部分。
Top: the data (green dots) and the current prediction (blue line). Bottom: the mistakes that are still left (red bars). Each new tree looks only at the red bars, fits a small staircase to them (orange), and adds a fraction of it to the blue line.
ऊपर: data (हरे dots) और मौजूदा prediction (नीली line)। नीचे: अभी बची गलतियाँ (लाल bars)। हर नया tree सिर्फ़ लाल bars देखता है, उन पर एक छोटी सीढ़ी fit करता है (नारंगी), और उसका एक हिस्सा नीली line में जोड़ता है।
上方:数据(绿点)和当前预测(蓝线)。下方:仍然存在的错误(红柱)。每棵新树只看红柱,给它们拟合一个小阶梯(橙色),再把其中一部分加到蓝线上。
Try learning_rate 0.1: each tree fixes only 10% of the mistake, so you need many more trees. Try max_depth 3: each tree asks more questions and fixes more at once.
learning_rate 0.1 आज़माएँ: हर tree गलती का सिर्फ़ 10% ठीक करता है, इसलिए बहुत ज़्यादा trees चाहिए। max_depth 3 आज़माएँ: हर tree ज़्यादा सवाल पूछता है और एक बार में ज़्यादा ठीक करता है।
试试 learning_rate 0.1:每棵树只修正 10% 的错误,所以需要多得多的树。试试 max_depth 3:每棵树问更多问题,一次修正更多。
The red bars are the "gradient" in gradient boosting. For the usual squared-error loss they are simply actual − predicted. For other losses (like log-loss for yes/no problems) the formula changes, but the idea is the same: the gradient tells each new tree which way, and how much, to push every prediction. XGBoost also uses the second derivative (the Hessian) to choose a good step size for every leaf.
लाल bars ही gradient boosting का "gradient" हैं। आम squared-error loss में ये बस असली − अनुमान हैं। दूसरे losses (जैसे हाँ/ना problems के लिए log-loss) में formula बदलता है, पर विचार वही है: gradient हर नए tree को बताता है कि हर prediction को किस तरफ़ और कितना धकेलना है। XGBoost दूसरा derivative (Hessian) भी इस्तेमाल करता है ताकि हर leaf के लिए अच्छा step size चुने।
红柱就是梯度提升中的"梯度"。对常用的平方误差 loss,它就是真实值 − 预测值。对其他 loss(比如是/否问题的 log-loss),公式会变,但思想一样:梯度告诉每棵新树把每个预测往哪个方向推、推多少。XGBoost 还使用二阶导数(Hessian)为每个叶子选择合适的步长。
Picture 3 — The Knobs (Hyperparameters) in Everyday Wordsतस्वीर 3 — Knobs (Hyperparameters) रोज़ की भाषा में图 3 — 用日常语言解释旋钮(超参数)
n_estimatorslearning_ratemax_depthsubsample · colsample_bytreereg_lambda · reg_alpha · gammaearly_stopping_roundsTurn the knobs and watch the blue model curve. Green dots = training data the model sees. Orange rings = new validation data it never sees. A good model follows the dashed true pattern, not every dot.
Knobs घुमाएँ और नीला model curve देखें। हरे dots = training data जो model देखता है। नारंगी छल्ले = नया validation data जो वह कभी नहीं देखता। अच्छा model dashed असली pattern के साथ चलता है, हर dot के पीछे नहीं।
转动旋钮,观察蓝色的 model 曲线。绿点 = model 看到的训练数据;橙色圆圈 = 它从没见过的新验证数据。好的 model 跟随虚线表示的真实规律,而不是每一个点。
The noise in this data has variance 0.30, so no model can get validation error much below 0.3. The best settings here reach about 0.36.
इस data के noise का variance 0.30 है, इसलिए कोई भी model validation error को 0.3 से बहुत नीचे नहीं ला सकता। यहाँ सबसे अच्छी settings लगभग 0.36 तक पहुँचती हैं।
这份数据的噪声方差是 0.30,所以任何 model 的验证误差都不可能比 0.3 低太多。这里最好的参数大约能达到 0.36。
Tuning is just this loop: try some knob settings, measure them honestly with cross-validation, remember the score, and try again.
Tuning बस यह loop है: कुछ knob settings आज़माएँ, cross-validation से ईमानदारी से मापें, score याद रखें, और फिर आज़माएँ।
调参就是这个循环:试一组旋钮设置,用交叉验证诚实地打分,记下分数,然后再试。
Grid search makes every combination from a fixed list: 5 × 5 × 5 = 125 cups (almost 21 hours!).
Random search makes 30 cups with random amounts. It covers more different values of each ingredient for far less work.
Optuna / Bayesian tastes each cup and thinks: "the last two good cups had less sugar; let me try around there." It finds a great cup in fewer tries.
XGBoost tuning is the same: each "cup" is one model trained with cross-validation, and the "taste" is the validation score.
Grid search तय list की हर combination बनाता है: 5 × 5 × 5 = 125 कप (लगभग 21 घंटे!)।
Random search random मात्राओं के साथ 30 कप बनाता है। बहुत कम मेहनत में यह हर ingredient की ज़्यादा अलग-अलग values आज़मा लेता है।
Optuna / Bayesian हर कप चखकर सोचता है: "पिछले दो अच्छे कपों में चीनी कम थी; उसके आसपास आज़माता हूँ।" यह कम कोशिशों में बढ़िया कप खोज लेता है।
XGBoost tuning भी ऐसा ही है: हर "कप" cross-validation से train हुआ एक model है, और "स्वाद" validation score है।
网格搜索把固定列表里的每种组合都做一遍:5 × 5 × 5 = 125 杯(将近 21 小时!)。
随机搜索用随机的用量做 30 杯,花的功夫少得多,却能试到每种原料更多不同的取值。
Optuna / 贝叶斯每喝一杯都会想:"上两杯好喝的糖都比较少,我在那附近再试试。"它用更少的次数找到一杯好茶。
XGBoost 调参也是一样:每"一杯"是用交叉验证训练出的一个 model,"味道"就是验证分数。
How Gradient Boosting Works — Step by StepGradient Boosting कैसे काम करता है — Step by Step梯度提升如何工作 — 逐步讲解
Before XGBoost's engineering, you need its mathematical heart: gradient boosting. Each tree is built to lower a loss function, using its gradient (the direction of fastest improvement).
XGBoost की engineering से पहले उसका गणितीय दिल समझें: gradient boosting. हर tree एक loss function को घटाने के लिए बनता है, उसके gradient (सबसे तेज़ सुधार की दिशा) की मदद से।
在了解 XGBoost 的工程实现之前,先要理解它的数学核心:梯度提升。每棵树都借助损失函数的梯度(改进最快的方向)来降低损失。
Classic gradient boosting uses only the first derivative (the gradient). XGBoost uses a second-order Taylor expansion: the gradient and the Hessian (curvature). This gives each leaf a well-sized weight straight away. It also adds an explicit regularisation term Ω to the objective, which penalises complex trees from the start.
Classic gradient boosting सिर्फ़ पहला derivative (gradient) इस्तेमाल करता है। XGBoost second-order Taylor expansion इस्तेमाल करता है: gradient और Hessian (curvature)। इससे हर leaf को तुरंत सही आकार का weight मिलता है। यह objective में एक साफ़ regularisation term Ω भी जोड़ता है, जो शुरू से complex trees पर penalty लगाता है।
经典梯度提升只用一阶导数(梯度)。XGBoost 使用二阶泰勒展开:梯度和 Hessian(曲率),让每个叶子一开始就得到合适的权重。它还在目标函数中加入了显式的正则项 Ω,从一开始就惩罚复杂的树。
The XGBoost Objective Function — Math Explained SimplyXGBoost Objective Function — आसान गणितXGBoost 目标函数 — 简单讲数学
At each boosting round, XGBoost minimises this objective:
हर boosting round में XGBoost यह objective कम करता है:
每一轮提升中,XGBoost 最小化以下目标:
objective.objective से चुनें।objective 选择。Each leaf weight has a closed-form answer, w* = −G/(H+λ), so no inner optimisation is needed. λ sits in the denominator and pulls weights toward zero, which prevents extreme predictions. γ removes splits that do not pay for themselves. Try both in the calculator below.
हर leaf weight का सीधा formula है, w* = −G/(H+λ), इसलिए अंदर कोई optimisation नहीं चाहिए। λ denominator में है और weights को zero की ओर खींचता है, जिससे बहुत बड़े predictions रुकते हैं। γ उन splits को हटाता है जो अपनी कीमत नहीं चुकाते। नीचे calculator में दोनों आज़माएँ।
每个叶子权重都有闭式解 w* = −G/(H+λ),不需要内部优化。λ 在分母中,把权重拉向零,避免极端预测。γ 会去掉"不值得"的分裂。在下面的计算器里试试这两个参数。
10 houses sorted by size. Bars = residuals the next tree must fix (for MSE, g = −residual and h = 1). Move the split, change λ and γ. Thick lines = leaf weights w*. The small bars below show the gain of every possible split.
10 घर size के क्रम में। Bars = residuals जिन्हें अगले tree को ठीक करना है (MSE में g = −residual और h = 1)। Split खिसकाएँ, λ और γ बदलें। मोटी lines = leaf weights w*. नीचे की छोटी bars हर संभव split का gain दिखाती हैं।
10 套房子按面积排序。柱子 = 下一棵树要修正的残差(MSE 下 g = −残差,h = 1)。移动分裂点,调整 λ 和 γ。粗线 = 叶子权重 w*。下方小柱子显示每个可能分裂的增益。
Try λ = 10: every leaf weight shrinks toward 0. Raise γ until even the best split turns red: the tree stops growing.
λ = 10 आज़माएँ: हर leaf weight 0 की ओर सिकुड़ता है। γ को तब तक बढ़ाएँ जब तक सबसे अच्छा split भी लाल न हो जाए: tree बढ़ना बंद कर देता है।
试试 λ = 10:每个叶子权重都向 0 收缩。把 γ 调大,直到连最佳分裂也变红:树就不再生长。
Every number follows from the formulas above. The right-hand split has Gain = −0.16 after subtracting γ, so XGBoost prunes it and keeps one leaf.
हर number ऊपर के formulas से आता है। दाईं ओर के split का Gain, γ घटाने के बाद −0.16 है, इसलिए XGBoost उसे prune करके एक leaf रखता है।
每个数字都由上面的公式算出。右侧分裂减去 γ 后的 Gain = −0.16,所以 XGBoost 把它剪掉,只保留一个叶子。
What Makes XGBoost Special — Six Engineering IdeasXGBoost को क्या ख़ास बनाता है — छह Engineering IdeasXGBoost 的特别之处 — 六个工程创新
device='cuda').device='cuda')।device='cuda')。Python Implementation — Classification & RegressionPython Implementation — Classification और RegressionPython 实现 — 分类与回归
InstallationInstallation安装
pip install xgboost scikit-learn pandas numpy
Classification — Predicting Customer ChurnClassification — Customer Churn Predict करना分类 — 预测客户流失
import xgboost as xgb
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report
# Simulated churn dataset: 8,000 customers, 20 features
X, y = make_classification(
n_samples=8000, n_features=20,
n_informative=12, n_redundant=4,
random_state=42
)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# XGBoost classifier with sensible starting values
model = xgb.XGBClassifier(
n_estimators=300, # number of boosting rounds
learning_rate=0.05, # eta: shrinkage per round
max_depth=6, # maximum tree depth
subsample=0.8, # row sampling per tree
colsample_bytree=0.8, # feature sampling per tree
gamma=0, # minimum split gain
reg_alpha=0, # L1 regularisation
reg_lambda=1, # L2 regularisation
eval_metric='logloss',
random_state=42
)
# Note: do NOT pass use_label_encoder — it was removed in XGBoost 2.0.
model.fit(
X_train, y_train,
eval_set=[(X_test, y_test)], # only to watch the loss; no early stopping here
verbose=100
)
y_pred = model.predict(X_test)
print(f"\nAccuracy: {accuracy_score(y_test, y_pred):.4f}\n")
print(classification_report(y_test, y_pred))
Many older examples pass use_label_encoder=False. It was deprecated in XGBoost 1.6 and removed in 2.0; today it only produces a warning that the parameter is not used. Delete it from your code. Also note: passing the test set to eval_set is fine for watching the loss, but never use it for early stopping or tuning.
कई पुराने examples use_label_encoder=False देते हैं। यह XGBoost 1.6 में deprecated हुआ और 2.0 में हटा दिया गया; आज यह बस warning देता है कि parameter इस्तेमाल नहीं हुआ। इसे अपने code से हटा दें। यह भी ध्यान दें: loss देखने के लिए test set को eval_set में देना ठीक है, पर early stopping या tuning के लिए कभी नहीं।
很多旧示例会传入 use_label_encoder=False。它在 XGBoost 1.6 中被弃用,2.0 中被移除,现在只会产生"参数未使用"的警告,请从代码中删除。另外注意:把测试集放进 eval_set 来观察 loss 没问题,但绝不能用它做 early stopping 或调参。
Regression — California Housing PricesRegression — California के घरों की कीमतें回归 — 加州房价
import xgboost as xgb
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.metrics import r2_score, mean_absolute_error
housing = fetch_california_housing()
X_h, y_h = housing.data, housing.target # y = median house value in $100,000
Xh_train, Xh_test, yh_train, yh_test = train_test_split(
X_h, y_h, test_size=0.2, random_state=42
)
reg = xgb.XGBRegressor(
n_estimators=500,
learning_rate=0.03,
max_depth=5,
subsample=0.75,
colsample_bytree=0.75,
reg_lambda=1.5,
random_state=42
)
reg.fit(Xh_train, yh_train)
y_pred = reg.predict(Xh_test)
print(f"R² Score: {r2_score(yh_test, y_pred):.4f}")
print(f"MAE: ${mean_absolute_error(yh_test, y_pred) * 100_000:,.0f}")
Key Hyperparameters — Complete Referenceमुख्य Hyperparameters — पूरा Reference关键超参数 — 完整参考
XGBoost's hyperparameters fall into four groups. Defaults are for XGBoost 2.x/3.x.
XGBoost के hyperparameters चार groups में आते हैं। Defaults XGBoost 2.x/3.x के हैं।
XGBoost 的超参数分为四组。默认值适用于 XGBoost 2.x/3.x。
Group 1 — Boosting ControlGroup 1 — Boosting नियंत्रण第 1 组 — 提升控制
| Parameter | Default | RangeRange范围 | Effectअसर作用 | Tuning priorityTuning priority调参优先级 |
|---|---|---|---|---|
n_estimators | 100 | 50–3000 | Number of boosting rounds (trees)Boosting rounds (trees) की संख्या提升轮数(树的数量) | High: set it with early stoppingज़्यादा: early stopping से तय करें高:用 early stopping 确定 |
learning_rate (eta) | 0.3 | 0.01–0.3 | Shrinkage per round. Lower usually generalises better but needs more treesहर round का shrinkage. कम आमतौर पर बेहतर generalise करता है पर ज़्यादा trees चाहिए每轮的缩放。越低通常泛化越好,但需要更多树 | Critical: start at 0.05–0.1बहुत ज़रूरी: 0.05–0.1 से शुरू करें关键:从 0.05–0.1 开始 |
booster | 'gbtree' | gbtree / gblinear / dart | Type of base learner. gbtree is almost always best for tabular dataBase learner का प्रकार। Tabular data के लिए gbtree लगभग हमेशा best基学习器类型。表格数据几乎总是 gbtree 最好 | Rarely changedशायद ही बदलें很少改动 |
Group 2 — Tree StructureGroup 2 — Tree का ढाँचा第 2 组 — 树结构
| Parameter | Default | RangeRange范围 | Effectअसर作用 | Tuning priorityTuning priority调参优先级 |
|---|---|---|---|---|
max_depth | 6 | 3–10 | Maximum depth. Deeper = more complex patterns, more overfitting riskअधिकतम depth. ज़्यादा = ज़्यादा complex patterns, overfitting का ज़्यादा ख़तरा最大深度。越深模式越复杂,过拟合风险越高 | Critical: tune firstबहुत ज़रूरी: पहले tune करें关键:最先调 |
min_child_weight | 1 | 1–10 | Minimum Hessian sum in a leaf. Higher = more careful splitsLeaf में न्यूनतम Hessian जोड़। ज़्यादा = ज़्यादा सावधान splits叶子中 Hessian 和的最小值。越高分裂越保守 | Highज़्यादा高 |
gamma | 0 | 0–5 | Minimum gain for a split. Higher = more pruningSplit के लिए न्यूनतम gain. ज़्यादा = ज़्यादा pruning分裂的最小增益。越高剪枝越多 | Highज़्यादा高 |
max_leaves | 0 (no limit) | 0–64 | Limits leaves instead of depth; mainly with grow_policy='lossguide'Depth के बजाय leaves सीमित करता है; मुख्यतः grow_policy='lossguide' के साथ限制叶子数而非深度;主要配合 grow_policy='lossguide' | Optionalवैकल्पिक可选 |
tree_method | 'hist' | hist / exact / approx | How splits are searched. hist is fast and the default since 2.0Splits कैसे खोजे जाते हैं। hist तेज़ है और 2.0 से default如何搜索分裂点。hist 快速,2.0 起为默认 | Keep histhist रखें保持 hist |
Group 3 — Sampling (Stochastic Boosting)Group 3 — Sampling (Stochastic Boosting)第 3 组 — 抽样(随机提升)
| Parameter | Default | RangeRange范围 | Effectअसर作用 | Tuning priorityTuning priority调参优先级 |
|---|---|---|---|---|
subsample | 1.0 | 0.5–1.0 | Share of rows sampled per tree. Below 1.0 adds randomnessहर tree के लिए rows का हिस्सा। 1.0 से कम randomness जोड़ता है每棵树抽样的行比例。小于 1.0 会增加随机性 | Highज़्यादा高 |
colsample_bytree | 1.0 | 0.3–1.0 | Share of features per treeहर tree के लिए features का हिस्सा每棵树的特征比例 | Highज़्यादा高 |
colsample_bylevel | 1.0 | 0.3–1.0 | Share of features per depth levelहर depth level के लिए features का हिस्सा每一层的特征比例 | Mediumमध्यम中 |
colsample_bynode | 1.0 | 0.3–1.0 | Share of features per splitहर split के लिए features का हिस्सा每次分裂的特征比例 | Mediumमध्यम中 |
Group 4 — RegularisationGroup 4 — Regularisation第 4 组 — 正则化
| Parameter | Default | RangeRange范围 | Effectअसर作用 | Tuning priorityTuning priority调参优先级 |
|---|---|---|---|---|
reg_alpha (alpha) | 0 | 0–10 | L1 on leaf weights. Can push some weights to exactly zeroLeaf weights पर L1. कुछ weights को बिल्कुल zero कर सकता है叶子权重的 L1,可以把一些权重压到 0 | Higher for many featuresकई features हों तो ज़्यादा特征多时更重要 |
reg_lambda (lambda) | 1 | 0–10 | L2 on leaf weights. Shrinks all weights toward zeroLeaf weights पर L2. सभी weights को zero की ओर सिकोड़ता है叶子权重的 L2,把所有权重向 0 收缩 | Highज़्यादा高 |
scale_pos_weight | 1 | ratioratio比值 | For imbalanced data: sum(negatives) / sum(positives)Imbalanced data के लिए: sum(negatives) / sum(positives)用于不平衡数据:sum(负类) / sum(正类) | Critical when classes are imbalancedClasses imbalanced हों तो बहुत ज़रूरी类别不平衡时很关键 |
1. Fix learning_rate=0.05 and find the number of trees with early stopping. 2. Tune max_depth and min_child_weight together. 3. Tune subsample and colsample_bytree. 4. Tune gamma, reg_alpha, reg_lambda. 5. Lower learning_rate and let early stopping find the new number of trees.
1. learning_rate=0.05 तय करें और early stopping से trees की संख्या खोजें। 2. max_depth और min_child_weight साथ tune करें। 3. subsample और colsample_bytree tune करें। 4. gamma, reg_alpha, reg_lambda tune करें। 5. learning_rate घटाएँ और early stopping को trees की नई संख्या खोजने दें।
1. 固定 learning_rate=0.05,用 early stopping 找出树的数量。2. 一起调 max_depth 和 min_child_weight。3. 调 subsample 和 colsample_bytree。4. 调 gamma、reg_alpha、reg_lambda。5. 降低 learning_rate,让 early stopping 找出新的树数量。
Early Stopping — Finding the Right Number of TreesEarly Stopping — Trees की सही संख्या खोजनाEarly Stopping — 找到合适的树数量
Early stopping does exactly this. It checks the validation loss after every boosting round and stops when there has been no improvement for
early_stopping_rounds rounds in a row. The model keeps the trees up to the best round, not the last one.Early stopping ठीक यही करता है। यह हर boosting round के बाद validation loss जाँचता है और जब लगातार
early_stopping_rounds rounds तक सुधार नहीं होता तो रुक जाता है। Model सबसे अच्छे round तक के trees रखता है, आख़िरी वाले तक नहीं।Early stopping 做的正是这件事。它在每一轮提升后检查验证 loss,如果连续
early_stopping_rounds 轮都没有改善就停止。model 保留到最佳轮次为止的树,而不是最后一轮。import xgboost as xgb
from sklearn.model_selection import train_test_split
# Split a validation set off the TRAINING data (never use the test set here)
X_tr, X_val, y_tr, y_val = train_test_split(
X_train, y_train, test_size=0.15, random_state=42
)
model = xgb.XGBClassifier(
n_estimators=2000, # set high: early stopping finds the real number
learning_rate=0.05,
max_depth=6,
subsample=0.8,
colsample_bytree=0.8,
eval_metric='logloss',
early_stopping_rounds=50, # stop after 50 rounds with no improvement
random_state=42
)
model.fit(X_tr, y_tr, eval_set=[(X_val, y_val)], verbose=False)
print(f"Best round: {model.best_iteration}")
print(f"Best val logloss: {model.best_score:.5f}")
print(f"Trees built: {model.get_booster().num_boosted_rounds()} of 2000")
# For a final model, use best_iteration + 1 trees (best_iteration counts from 0)
Orange = validation loss, purple = training loss. The red zone counts rounds since the last improvement. When it reaches the patience value, training stops, and the model rolls back to the green best round.
नारंगी = validation loss, बैंगनी = training loss. लाल क्षेत्र पिछले सुधार के बाद के rounds गिनता है। जब यह patience value तक पहुँचता है, training रुक जाती है, और model हरे best round पर लौट आता है।
橙色 = 验证 loss,紫色 = 训练 loss。红色区域统计自上次改善以来的轮数。当它达到耐心值时训练停止,model 回退到绿色的最佳轮次。
The Four Tuning Strategies — Overviewचार Tuning Strategies — एक नज़र四种调参策略 — 概览
Hyperparameter tuning means finding the combination of settings that gives the best model. There are four main strategies. They trade off speed, coverage and compute cost very differently.
Hyperparameter tuning का मतलब है settings का वह मेल खोजना जो सबसे अच्छा model दे। चार मुख्य strategies हैं। ये speed, coverage और compute cost के बीच बहुत अलग-अलग संतुलन बनाती हैं।
超参数调优就是找到能得到最佳 model 的参数组合。主要有四种策略,它们在速度、覆盖面和计算成本之间的取舍非常不同。
Strategies 3 and 4 are both Bayesian optimisation: both use past results to choose the next trial. They differ in the model they build. TPE models "what do good settings look like vs bad ones?" A Gaussian process models the score surface itself, with uncertainty.
Strategies 3 और 4 दोनों Bayesian optimisation हैं: दोनों अगला trial चुनने के लिए पिछले results इस्तेमाल करते हैं। फ़र्क़ उनके बनाए model में है। TPE model करता है "अच्छी settings बुरी settings से कैसे अलग दिखती हैं?" Gaussian process खुद score surface को, uncertainty के साथ, model करता है।
策略 3 和 4 都属于贝叶斯优化:都利用过去的结果来选择下一次试验。区别在于它们构建的模型。TPE 建模的是"好的参数和差的参数分别长什么样";高斯过程则直接建模分数曲面本身,并带有不确定性。
A rule of thumb, not a law. The key questions: how many parameters, how long one fit takes, and whether you want pruning and diagnostic plots.
यह एक अनुमान का नियम है, क़ानून नहीं। मुख्य सवाल: कितने parameters, एक fit में कितना समय, और क्या आपको pruning और diagnostic plots चाहिए।
这是经验法则,不是定律。关键问题:有多少参数、一次训练要多久、是否需要剪枝和诊断图。
Strategy 1 — Grid SearchStrategy 1 — Grid Search策略 1 — 网格搜索
Grid Search trains a model for every combination of the values you list. 3 parameters with 5 values each = 5³ = 125 models. 6 parameters = 5⁶ = 15,625 models, and with 5-fold CV that is 78,125 training runs.
Grid Search आपकी दी हुई values की हर combination के लिए एक model train करता है। 5-5 values वाले 3 parameters = 5³ = 125 models. 6 parameters = 5⁶ = 15,625 models, और 5-fold CV के साथ यह 78,125 training runs है।
网格搜索会为你列出的值的每一种组合训练一个 model。3 个参数各 5 个值 = 5³ = 125 个 model。6 个参数 = 5⁶ = 15,625 个 model,加上 5 折交叉验证就是 78,125 次训练。
Use Grid Search only for 2–3 hyperparameters and a fast model. With XGBoost's 10+ parameters, it is rarely the right choice. Its best use is fine-tuning a small range after Random Search or Optuna has found a good region.
Grid Search सिर्फ़ 2–3 hyperparameters और तेज़ model के लिए इस्तेमाल करें। XGBoost के 10+ parameters के साथ यह शायद ही सही विकल्प है। इसका सबसे अच्छा उपयोग Random Search या Optuna के अच्छा क्षेत्र खोजने के बाद छोटी range की बारीक tuning है।
只在 2–3 个超参数且 model 训练很快时使用网格搜索。面对 XGBoost 的 10 多个参数,它很少是正确选择。它最适合在随机搜索或 Optuna 找到好区域之后,在小范围内做精细调参。
import time
import pandas as pd
import xgboost as xgb
from sklearn.model_selection import GridSearchCV
# Keep the grid SMALL: 3 params x 3 values = 27 combos x 5 folds = 135 fits
param_grid = {
'max_depth': [3, 5, 7],
'learning_rate': [0.01, 0.05, 0.1],
'n_estimators': [100, 300, 500],
}
base_model = xgb.XGBClassifier(subsample=0.8, colsample_bytree=0.8,
eval_metric='logloss', random_state=42)
grid_search = GridSearchCV(
estimator=base_model,
param_grid=param_grid,
cv=5,
scoring='roc_auc',
n_jobs=-1, # use all CPU cores
verbose=1
)
t0 = time.perf_counter()
grid_search.fit(X_train, y_train)
print("Best parameters:", grid_search.best_params_)
print(f"Best CV AUC: {grid_search.best_score_:.4f}")
print(f"Time: {time.perf_counter() - t0:.0f} s\n")
results = pd.DataFrame(grid_search.cv_results_)
top5 = results.nlargest(5, 'mean_test_score')[[
'param_max_depth', 'param_learning_rate', 'param_n_estimators', 'mean_test_score']]
print(top5.round(4).to_string(index=False))
Each extra parameter with 5 values multiplies the work by 5. If one XGBoost fit takes 10 seconds and you grid-search 6 parameters with 5 values each: 5⁶ × 5 folds × 10 s = 781,250 s ≈ 217 hours (about 9 days) on one machine. Random Search with 100 iterations and 5 folds takes 100 × 5 × 10 s ≈ 83 minutes, and often finds a comparable result.
5 values वाला हर extra parameter काम को 5 गुना कर देता है। अगर एक XGBoost fit में 10 seconds लगते हैं और आप 5-5 values वाले 6 parameters grid-search करते हैं: 5⁶ × 5 folds × 10 s = 781,250 s ≈ एक machine पर 217 घंटे (लगभग 9 दिन)। 100 iterations और 5 folds वाले Random Search में 100 × 5 × 10 s ≈ 83 मिनट लगते हैं, और अक्सर इतना ही अच्छा result मिलता है।
每多一个有 5 个取值的参数,工作量就乘以 5。如果一次 XGBoost 训练要 10 秒,对 6 个参数各 5 个值做网格搜索:5⁶ × 5 折 × 10 秒 = 781,250 秒 ≈ 单机 217 小时(约 9 天)。100 次迭代、5 折的随机搜索只需 100 × 5 × 10 秒 ≈ 83 分钟,而且常常能找到差不多好的结果。
The green shading is the CV score. Only learning_rate (left–right) really matters; colsample (up–down) barely does. The ticks under each panel show which learning_rate values were actually tried. Yellow ring = best point found.
हरा रंग CV score है। सिर्फ़ learning_rate (बाएँ–दाएँ) असल में मायने रखता है; colsample (ऊपर–नीचे) मुश्किल से। हर panel के नीचे के निशान दिखाते हैं कि learning_rate की कौन-सी values सच में आज़माई गईं। पीला घेरा = मिला सबसे अच्छा point.
绿色深浅表示 CV 分数。只有 learning_rate(左右方向)真正重要,colsample(上下方向)几乎无关。每个面板下方的刻度显示实际尝试了哪些 learning_rate 值。黄圈 = 找到的最佳点。
| Grid | Random | |
|---|---|---|
Strategy 2 — Random SearchStrategy 2 — Random Search策略 2 — 随机搜索
The gold lies in a thin seam that runs along one direction. Prospector A's grid tests only a few distinct positions along that direction, and can miss the seam. Prospector B tests a new position with every dart, so he is more likely to hit it.
Bergstra & Bengio (2012) showed this for hyperparameters: when only a few parameters really matter, random search is usually more efficient than grid search.
सोना एक पतली पट्टी में है जो एक दिशा में चलती है। Prospector A का grid उस दिशा में बस कुछ अलग-अलग जगहें test करता है, और पट्टी से चूक सकता है। Prospector B हर dart के साथ एक नई जगह test करता है, इसलिए उसके उसे पाने की संभावना ज़्यादा है।
Bergstra & Bengio (2012) ने hyperparameters के लिए यह दिखाया: जब सिर्फ़ कुछ parameters सच में मायने रखते हैं, तो random search आमतौर पर grid search से ज़्यादा efficient है।
金子在一条沿某个方向延伸的细矿脉里。A 的网格在这个方向上只测试了少数几个不同位置,可能错过矿脉;B 的每支飞镖都测试一个新位置,所以更可能碰到它。
Bergstra 和 Bengio(2012)在超参数上证明了这一点:当只有少数参数真正重要时,随机搜索通常比网格搜索更高效。
import time
import xgboost as xgb
from scipy.stats import randint, uniform, loguniform
from sklearn.model_selection import RandomizedSearchCV
from sklearn.metrics import roc_auc_score
# Wide search space: Random Search explores it efficiently
param_dist = {
'n_estimators': randint(100, 1000),
'learning_rate': loguniform(0.005, 0.3), # log scale: more small values
'max_depth': randint(3, 10),
'min_child_weight': randint(1, 10),
'subsample': uniform(0.5, 0.5), # uniform(loc, scale) -> [0.5, 1.0]
'colsample_bytree': uniform(0.4, 0.6), # -> [0.4, 1.0]
'gamma': uniform(0, 2),
'reg_alpha': loguniform(1e-4, 10),
'reg_lambda': loguniform(1e-4, 10),
}
base = xgb.XGBClassifier(eval_metric='logloss', random_state=42)
random_search = RandomizedSearchCV(
estimator=base,
param_distributions=param_dist,
n_iter=100, # 100 random combinations
cv=5,
scoring='roc_auc',
n_jobs=-1,
verbose=1,
random_state=42
)
t0 = time.perf_counter()
random_search.fit(X_train, y_train)
print("Best parameters:")
for k, v in sorted(random_search.best_params_.items()):
print(f" {k:<17}: {v:.4g}" if isinstance(v, float) else f" {k:<17}: {v}")
print(f"Best CV AUC: {random_search.best_score_:.5f}")
proba = random_search.best_estimator_.predict_proba(X_test)[:, 1]
print(f"Test AUC: {roc_auc_score(y_test, proba):.5f}")
print(f"Time: {time.perf_counter() - t0:.0f} s")
| MetricMetric指标 | ValueValue数值 |
|---|---|
| FitsFits训练次数 | 135 (27 × 5 folds) |
| Best CV AUCBest CV AUC最佳 CV AUC | 0.9914 |
| Time on this page's runइस page के run में समय本页运行耗时 | 72 s |
| Never tunedकभी tune नहीं हुए从未调整 | subsample, min_child_weight, gamma, alpha, lambda |
| MetricMetric指标 | ValueValue数值 |
|---|---|
| FitsFits训练次数 | 500 (100 × 5 folds) |
| Best CV AUCBest CV AUC最佳 CV AUC | 0.99061 |
| Time on this page's runइस page के run में समय本页运行耗时 | 310 s |
| CoveredCover हुए覆盖 | All 9 key parametersसभी 9 मुख्य parameters全部 9 个关键参数 |
Both searches use the same data and the same scoring (ROC-AUC), so the numbers compare directly. A surprise: Grid Search scored slightly higher here (0.9914 vs 0.9906), in a quarter of the time. This synthetic data is easy, and the three parameters in the grid (depth, learning rate, number of trees) are exactly the ones that matter; the grid also happened to include good values. Random Search spent much of its budget on parameters that barely matter for this data. The gap is smaller than the noise between CV folds, so treat it as a tie. Timings are from a 2-core machine; yours will differ.
दोनों searches एक ही data और एक ही scoring (ROC-AUC) इस्तेमाल करती हैं, इसलिए numbers की सीधी तुलना होती है। एक हैरानी: यहाँ Grid Search ने थोड़ा ज़्यादा score किया (0.9914 बनाम 0.9906), वह भी एक-चौथाई समय में। यह synthetic data आसान है, और grid के तीन parameters (depth, learning rate, trees की संख्या) ठीक वही हैं जो मायने रखते हैं; grid में संयोग से अच्छी values भी थीं। Random Search ने अपना बहुत सा budget उन parameters पर खर्च किया जो इस data के लिए मुश्किल से मायने रखते हैं। यह अंतर CV folds के बीच के noise से छोटा है, इसलिए इसे बराबरी मानें। समय 2-core machine का है; आपका अलग होगा।
两种搜索使用相同的数据和评分(ROC-AUC),所以数字可以直接比较。意外的是:这里网格搜索的分数略高(0.9914 vs 0.9906),用时只有四分之一。这份合成数据很简单,网格里的三个参数(深度、学习率、树的数量)恰好就是最重要的那些,而且网格碰巧包含了好的取值。随机搜索把大量预算花在了对这份数据几乎无关紧要的参数上。这个差距比交叉验证各折之间的噪声还小,所以可以视为平局。耗时来自双核机器,你的结果会不同。
Strategy 3 — Optuna (TPE + Pruning)Strategy 3 — Optuna (TPE + Pruning)策略 3 — Optuna(TPE + 剪枝)
Optuna's Tree-structured Parzen Estimator (TPE) learns which parameter regions give good results and samples more from them. Its pruner stops bad trials early and saves compute.
Optuna का Tree-structured Parzen Estimator (TPE) सीखता है कि कौन से parameter क्षेत्र अच्छे results देते हैं और वहाँ से ज़्यादा sample लेता है। इसका pruner बुरे trials को जल्दी रोककर compute बचाता है।
Optuna 的 Tree-structured Parzen Estimator(TPE)会学习哪些参数区域效果好,并在那里多抽样。它的剪枝器会提前终止差的试验,节省计算。
Optuna, from Preferred Networks, is a modern tuning framework. TPE splits the trials so far into a "good" group and a "bad" group, models each with a probability density, and samples where good / bad is highest.
Preferred Networks का Optuna एक modern tuning framework है। TPE अब तक के trials को "अच्छे" और "बुरे" group में बाँटता है, हर एक को probability density से model करता है, और वहाँ sample लेता है जहाँ अच्छा / बुरा सबसे ज़्यादा है।
Optuna 是 Preferred Networks 开发的现代调参框架。TPE 把已有的试验分为"好"和"差"两组,分别用概率密度建模,然后在"好/差"比值最高的地方抽样。
pip install optuna
import time
import optuna
import xgboost as xgb
from sklearn.model_selection import cross_val_score
from sklearn.metrics import roc_auc_score
optuna.logging.set_verbosity(optuna.logging.WARNING) # quiet output
def objective(trial):
params = {
'n_estimators': trial.suggest_int('n_estimators', 100, 1000),
'learning_rate': trial.suggest_float('learning_rate', 0.005, 0.3, log=True),
'max_depth': trial.suggest_int('max_depth', 3, 10),
'min_child_weight': trial.suggest_int('min_child_weight', 1, 10),
'subsample': trial.suggest_float('subsample', 0.5, 1.0),
'colsample_bytree': trial.suggest_float('colsample_bytree', 0.4, 1.0),
'gamma': trial.suggest_float('gamma', 0, 5),
'reg_alpha': trial.suggest_float('reg_alpha', 1e-4, 10, log=True),
'reg_lambda': trial.suggest_float('reg_lambda', 1e-4, 10, log=True),
}
model = xgb.XGBClassifier(**params, eval_metric='logloss', random_state=42)
scores = cross_val_score(model, X_train, y_train, cv=5, scoring='roc_auc', n_jobs=-1)
return scores.mean() # Optuna maximises this
study = optuna.create_study(
direction='maximize',
sampler=optuna.samplers.TPESampler(seed=42) # Tree-structured Parzen Estimator
)
t0 = time.perf_counter()
study.optimize(objective, n_trials=100)
# Best score after 10, 30, 60, 100 trials
best_so_far = [max(t.value for t in study.trials[:n]) for n in (10, 30, 60, 100)]
for n, v in zip((10, 30, 60, 100), best_so_far):
print(f"After {n:>3} trials: best CV AUC = {v:.5f}")
print("\nBest parameters:")
for k, v in study.best_params.items():
print(f" {k:<17}: {v:.4g}" if isinstance(v, float) else f" {k:<17}: {v}")
best_model = xgb.XGBClassifier(**study.best_params, eval_metric='logloss', random_state=42)
best_model.fit(X_train, y_train)
print(f"\nTest AUC: {roc_auc_score(y_test, best_model.predict_proba(X_test)[:, 1]):.5f}")
print(f"Time: {time.perf_counter() - t0:.0f} s")
Some tutorials add pruner=MedianPruner() to a study whose objective just calls cross_val_score. That pruner never fires: pruning needs the objective to report intermediate scores during training (with trial.report or a callback). The next example shows pruning that actually works.
कुछ tutorials ऐसी study में pruner=MedianPruner() जोड़ते हैं जिसका objective बस cross_val_score call करता है। वह pruner कभी नहीं चलता: pruning के लिए objective को training के दौरान बीच के scores report करने पड़ते हैं (trial.report या callback से)। अगला example ऐसी pruning दिखाता है जो सच में काम करती है।
有些教程会给一个目标函数只调用 cross_val_score 的 study 加上 pruner=MedianPruner()。这个剪枝器永远不会触发:剪枝需要目标函数在训练过程中汇报中间分数(用 trial.report 或回调)。下一个例子展示了真正有效的剪枝。
Optuna with Pruning (Real Speed-up)Pruning के साथ Optuna (असली Speed-up)带剪枝的 Optuna(真正提速)
pip install optuna-integration
import optuna
import xgboost as xgb
from optuna_integration import XGBoostPruningCallback # pip install optuna-integration
from sklearn.model_selection import train_test_split
optuna.logging.set_verbosity(optuna.logging.WARNING)
X_tr, X_val, y_tr, y_val = train_test_split(X_train, y_train, test_size=0.15, random_state=42)
def objective_with_pruning(trial):
model = xgb.XGBClassifier(
n_estimators=1000,
learning_rate=trial.suggest_float('learning_rate', 0.005, 0.3, log=True),
max_depth=trial.suggest_int('max_depth', 3, 10),
subsample=trial.suggest_float('subsample', 0.5, 1.0),
colsample_bytree=trial.suggest_float('colsample_bytree', 0.4, 1.0),
reg_alpha=trial.suggest_float('reg_alpha', 1e-4, 10, log=True),
eval_metric='logloss',
early_stopping_rounds=50,
# The scikit-learn API names the first eval set "validation_0"
callbacks=[XGBoostPruningCallback(trial, 'validation_0-logloss')],
random_state=42
)
model.fit(X_tr, y_tr, eval_set=[(X_val, y_val)], verbose=False)
return model.best_score # best validation logloss
study2 = optuna.create_study(
direction='minimize',
sampler=optuna.samplers.TPESampler(seed=42),
pruner=optuna.pruners.MedianPruner(n_startup_trials=10, n_warmup_steps=20)
)
study2.optimize(objective_with_pruning, n_trials=80)
pruned = [t for t in study2.trials if t.state == optuna.trial.TrialState.PRUNED]
print(f"Pruned trials: {len(pruned)} of {len(study2.trials)}")
print(f"Best logloss: {study2.best_value:.5f}")
1. XGBoostPruningCallback now lives in the separate optuna-integration package. 2. The callback must watch the exact metric name XGBoost logs. With the scikit-learn API, the first eval_set is called validation_0, so the name is 'validation_0-logloss', not 'validation-logloss'. A wrong name makes every trial fail.
1. XGBoostPruningCallback अब अलग optuna-integration package में है। 2. Callback को वही metric नाम देखना चाहिए जो XGBoost log करता है। scikit-learn API में पहले eval_set का नाम validation_0 होता है, इसलिए नाम 'validation_0-logloss' है, 'validation-logloss' नहीं। गलत नाम से हर trial fail होता है।
1. XGBoostPruningCallback 现在在单独的 optuna-integration 包里。2. 回调必须监视 XGBoost 实际记录的指标名。在 scikit-learn API 中,第一个 eval_set 叫 validation_0,所以名字是 'validation_0-logloss',而不是 'validation-logloss'。名字写错会让每个试验都失败。
20 trials, each a validation-loss curve over 100 boosting rounds. The first 5 (grey) always run fully. After round 20, every 10 rounds, a trial is cut (✂) if its loss is worse than the median of earlier trials at the same round.
20 trials, हर एक 100 boosting rounds का validation-loss curve. पहले 5 (grey) हमेशा पूरे चलते हैं। Round 20 के बाद, हर 10 rounds पर, अगर किसी trial का loss उसी round पर पहले के trials के median से बुरा है तो उसे काट दिया जाता है (✂)।
20 个试验,每个都是 100 轮提升的验证 loss 曲线。前 5 个(灰色)总是完整运行。第 20 轮之后每 10 轮检查一次:如果某个试验的 loss 比之前试验在同一轮的中位数还差,就剪掉(✂)。
:
Turn pruning off and on: the best final loss stays the same, but with pruning much less compute is spent on trials that were never going to win.
Pruning को बंद और चालू करें: सबसे अच्छा final loss वही रहता है, पर pruning के साथ उन trials पर बहुत कम compute खर्च होता है जो कभी जीतने वाले नहीं थे।
把剪枝关掉再打开:最佳最终 loss 不变,但开启剪枝后,在那些注定不会赢的试验上花的计算少得多。
optuna.visualization.plot_param_importances(study) shows which hyperparameters matter most, plot_optimization_history(study) shows how the best score improved, and plot_contour(study) shows how pairs of parameters interact. They need pip install plotly.
optuna.visualization.plot_param_importances(study) दिखाता है कि कौन से hyperparameters सबसे ज़्यादा मायने रखते हैं, plot_optimization_history(study) दिखाता है कि best score कैसे सुधरा, और plot_contour(study) दिखाता है कि parameters के जोड़े आपस में कैसे असर डालते हैं। इनके लिए pip install plotly चाहिए।
optuna.visualization.plot_param_importances(study) 显示哪些超参数最重要,plot_optimization_history(study) 显示最佳分数如何提升,plot_contour(study) 显示参数两两之间的相互作用。需要 pip install plotly。
Strategy 4 — Bayesian Optimisation with a Gaussian ProcessStrategy 4 — Gaussian Process के साथ Bayesian Optimisation策略 4 — 基于高斯过程的贝叶斯优化
She balances exploitation (dig near good spots) and exploration (check unknown areas). Bayesian optimisation does the same: a surrogate model (here a Gaussian process) predicts the score and its uncertainty everywhere, and an acquisition function (Expected Improvement) picks the next point to try.
वह exploitation (अच्छी जगहों के पास खोदना) और exploration (अनजान जगहें जाँचना) में संतुलन रखती है। Bayesian optimisation भी यही करता है: एक surrogate model (यहाँ Gaussian process) हर जगह score और उसकी uncertainty predict करता है, और एक acquisition function (Expected Improvement) अगला point चुनता है।
她在利用(在好地方附近挖)和探索(查看未知区域)之间取得平衡。贝叶斯优化也是这样:代理模型(这里是高斯过程)预测每个位置的分数及其不确定性,采集函数(期望改进 EI)选出下一个要尝试的点。
A real GP with an RBF kernel and Expected Improvement. Dots = evaluations (green = best so far). Orange line = predicted score; shaded band = ±2 standard deviations of uncertainty. Purple area = EI; the dashed line marks the next point it will try.
RBF kernel और Expected Improvement वाला असली GP. Dots = evaluations (हरा = अब तक का best)। नारंगी line = predicted score; छायादार band = uncertainty के ±2 standard deviations. बैंगनी क्षेत्र = EI; dashed line अगला point दिखाती है जो यह आज़माएगा।
这是一个真实的高斯过程,使用 RBF 核和期望改进。圆点 = 已评估的点(绿色 = 目前最佳)。橙线 = 预测分数,阴影带 = ±2 个标准差的不确定性。紫色区域 = EI,虚线标出它下一个要尝试的点。
Bayesian Optimisation with scikit-optimizescikit-optimize के साथ Bayesian Optimisation用 scikit-optimize 做贝叶斯优化
pip install scikit-optimize
import time
import xgboost as xgb
from skopt import BayesSearchCV # pip install scikit-optimize
from skopt.space import Real, Integer
search_space = {
'n_estimators': Integer(100, 1000),
'learning_rate': Real(0.005, 0.3, prior='log-uniform'),
'max_depth': Integer(3, 10),
'min_child_weight': Integer(1, 10),
'subsample': Real(0.5, 1.0),
'colsample_bytree': Real(0.4, 1.0),
'gamma': Real(0, 5.0),
'reg_alpha': Real(1e-4, 10, prior='log-uniform'),
'reg_lambda': Real(1e-4, 10, prior='log-uniform'),
}
base = xgb.XGBClassifier(eval_metric='logloss', random_state=42)
bayes_search = BayesSearchCV(
estimator=base,
search_spaces=search_space,
n_iter=50, # 50 evaluations
cv=5,
scoring='roc_auc',
n_jobs=-1,
random_state=42
)
best = []
def on_step(result): # result.fun = best (lowest) -AUC so far
best.append(-result.fun)
if len(best) in (1, 10, 25, 50):
print(f" Iter {len(best):3d} | best CV AUC so far: {-result.fun:.5f}")
t0 = time.perf_counter()
bayes_search.fit(X_train, y_train, callback=[on_step])
print(f"\nBest CV AUC: {bayes_search.best_score_:.5f}")
print("Best parameters:")
for k, v in sorted(bayes_search.best_params_.items()):
print(f" {k:<17}: {v:.4g}" if isinstance(v, float) else f" {k:<17}: {v}")
print(f"Time: {time.perf_counter() - t0:.0f} s")
scikit-optimize is no longer actively developed. The code above works with scikit-optimize 0.10 and scikit-learn 1.9, but for new projects, Optuna (TPE or GPSampler) is the safer long-term choice.
scikit-optimize अब सक्रिय रूप से develop नहीं हो रहा। ऊपर का code scikit-optimize 0.10 और scikit-learn 1.9 के साथ काम करता है, पर नए projects के लिए Optuna (TPE या GPSampler) लंबे समय के लिए सुरक्षित विकल्प है।
scikit-optimize 已不再积极开发。上面的代码可在 scikit-optimize 0.10 和 scikit-learn 1.9 下运行,但对新项目来说,Optuna(TPE 或 GPSampler)是更稳妥的长期选择。
Bayesian Optimisation with Optuna (GP Sampler)Optuna के साथ Bayesian Optimisation (GP Sampler)用 Optuna 做贝叶斯优化(GP 采样器)
import optuna
from optuna.samplers import GPSampler # Gaussian-process sampler (Optuna >= 3.6; needs: pip install torch)
study_gp = optuna.create_study(
direction='maximize',
sampler=GPSampler(seed=42),
study_name='xgb_gp_tuning'
)
study_gp.optimize(objective, n_trials=50) # same objective as the TPE example
print(f"GP-Optuna best AUC: {study_gp.best_value:.5f}")
This reuses the objective from the TPE example; only the sampler changes. GPSampler needs PyTorch installed (pip install torch).
यह TPE example वाला objective ही इस्तेमाल करता है; सिर्फ़ sampler बदलता है। GPSampler के लिए PyTorch installed होना चाहिए (pip install torch)।
这里复用 TPE 示例中的 objective,只是换了采样器。GPSampler 需要安装 PyTorch(pip install torch)。
Tuning Strategy ComparisonTuning Strategies की तुलना调参策略对比
| Propertyगुण属性 | Grid Search | Random Search | Optuna (TPE) | Bayesian (GP) |
|---|---|---|---|---|
| How it searchesकैसे खोजता है搜索方式 | Every combinationहर combination所有组合 | Random samplesRandom samples随机样本 | Model of good vs bad regionsअच्छे vs बुरे क्षेत्रों का model好坏区域的模型 | Score surface + Expected ImprovementScore surface + Expected Improvement分数曲面 + 期望改进 |
| Learns from past?पिछले से सीखता है?从过去学习? | Noनहीं否 | Noनहीं否 | Yesहाँ是 | Yesहाँ是 |
| Many parameters?कई parameters?参数很多时? | Explodesफट जाता है爆炸 | Scales wellअच्छा scale扩展良好 | Scales wellअच्छा scale扩展良好 | Medium (GP cost grows as n³)मध्यम (GP cost n³ से बढ़ता है)中等(GP 成本按 n³ 增长) |
| Parallel?Parallel?可并行? | Yesहाँ是 | Yesहाँ是 | Yes (with care)हाँ (सावधानी से)是(需注意) | Partly: it is sequential by designआंशिक: design से sequential部分:设计上是串行的 |
| Trial pruning?Trial pruning?试验剪枝? | Noनहीं否 | Noनहीं否 | Yesहाँ是 | With Optuna, yesOptuna के साथ, हाँ用 Optuna 可以 |
| Typical evaluations (rule of thumb)आम evaluations (अनुमान)常见评估次数(经验) | All combinationsसभी combinations全部组合 | 50–200 | 50–150 | 25–75 |
| Best for XGBoost when…XGBoost के लिए सबसे अच्छा जब…对 XGBoost 最适合… | Fine-tuning 2–3 params2–3 params की बारीक tuning精调 2–3 个参数 | First broad search, cheap fitsपहली व्यापक खोज, सस्ते fits首轮大范围搜索,训练便宜 | Most real projectsज़्यादातर असली projects大多数实际项目 | Each fit is slowहर fit धीमा हो每次训练很慢 |
| LibraryLibrary库 | GridSearchCV | RandomizedSearchCV | optuna | optuna GPSampler, scikit-optimize |
All four strategies tune the same hidden 2-D landscape (a big peak and a smaller decoy peak), with 30 evaluations each. Grid uses a 5 × 5 grid in the usual row-by-row order. Top: where each strategy looked. Bottom: best score found so far.
चारों strategies एक ही छिपे 2-D landscape (एक बड़ी चोटी और एक छोटी धोखे वाली चोटी) को tune करती हैं, हर एक 30 evaluations के साथ। Grid सामान्य row-by-row क्रम में 5 × 5 grid इस्तेमाल करता है। ऊपर: हर strategy ने कहाँ देखा। नीचे: अब तक मिला best score.
四种策略在同一个隐藏的二维地形上调参(一个大峰和一个较小的诱饵峰),每种 30 次评估。网格搜索按常规的逐行顺序使用 5 × 5 网格。上方:每种策略查看了哪里。下方:目前找到的最佳分数。
Model-based methods shine when the score surface is smooth and each fit is expensive. On cheap problems with many noisy parameters, Random Search with a decent budget is often just as good, and it parallelises perfectly. A practical rule: fast fits (under a minute) → Random Search or Optuna with 100+ trials; slow fits (many minutes) → Optuna or GP with 25–75 trials; Grid Search only for a final, narrow 2–3 parameter sweep.
Model-based methods तब चमकते हैं जब score surface smooth हो और हर fit महँगा हो। कई noisy parameters वाले सस्ते problems पर ठीक-ठाक budget वाला Random Search अक्सर उतना ही अच्छा होता है, और पूरी तरह parallel होता है। व्यावहारिक नियम: तेज़ fits (एक मिनट से कम) → Random Search या 100+ trials वाला Optuna; धीमे fits (कई मिनट) → 25–75 trials वाला Optuna या GP; Grid Search सिर्फ़ आख़िर में 2–3 parameters की छोटी जाँच के लिए।
当分数曲面平滑且每次训练很昂贵时,基于模型的方法优势最明显。对于训练便宜、参数多且噪声大的问题,预算适中的随机搜索往往同样好,而且可以完美并行。实用规则:训练快(不到一分钟)→ 随机搜索或 100+ 次试验的 Optuna;训练慢(几分钟以上)→ 25–75 次试验的 Optuna 或 GP;网格搜索只用于最后对 2–3 个参数的小范围扫描。
On the Real Churn Dataअसली Churn Data पर在真实的流失数据上
| StrategyStrategy策略 | FitsFits训练次数 | Best CV AUCBest CV AUC最佳 CV AUC | Time (2-core machine)समय (2-core machine)耗时(双核机器) |
|---|---|---|---|
| Grid Search (3 params) | 135 | 0.9914 | 72 s |
| Random Search (100) | 500 | 0.99061 | 310 s |
| Optuna TPE (100) | 500 | 0.99103 | 616 s |
| scikit-optimize GP (50) | 250 | 0.99019 | 228 s |
These numbers come from the code on this page. All four strategies finish within about 0.001 AUC of each other, which is smaller than the noise between CV folds. Grid even comes first, because this synthetic data is easy and its three parameters are the ones that matter. The lesson: a sensible search space plus early stopping matters more than the choice of search method. The method starts to matter when fits are slow and many parameters interact, as in the race simulator above.
ये numbers इस page के code से आए हैं। चारों strategies एक-दूसरे से लगभग 0.001 AUC के अंदर ख़त्म होती हैं, जो CV folds के बीच के noise से भी छोटा है। Grid तो पहले स्थान पर भी है, क्योंकि यह synthetic data आसान है और उसके तीन parameters वही हैं जो मायने रखते हैं। सबक: समझदारी भरा search space और early stopping, search method के चुनाव से ज़्यादा मायने रखते हैं। Method तब मायने रखने लगता है जब fits धीमे हों और कई parameters आपस में असर डालें, जैसा ऊपर race simulator में है।
这些数字来自本页的代码。四种策略的结果彼此相差不到约 0.001 AUC,比交叉验证各折之间的噪声还小。网格搜索甚至排第一,因为这份合成数据很简单,而它的三个参数正是最重要的那些。结论:合理的搜索空间加上 early stopping,比选择哪种搜索方法更重要。当训练很慢、很多参数相互影响时(就像上面的赛跑模拟器),方法的选择才开始变得重要。
Feature Importance in XGBoostXGBoost में Feature ImportanceXGBoost 特征重要性
XGBoost has three built-in importance types. Each measures something different:
XGBoost में तीन built-in importance types हैं। हर एक कुछ अलग मापता है:
XGBoost 有三种内置重要性类型,各自衡量不同的东西:
feature_importances_.feature_importances_ का default.feature_importances_ 的默认值。import pandas as pd
import matplotlib.pyplot as plt
import xgboost as xgb
import shap # pip install shap
# `model`, `X_test` come from the churn example above
feature_names = [f"f{i}" for i in range(X_test.shape[1])]
model.get_booster().feature_names = feature_names
gain = model.get_booster().get_score(importance_type='gain')
imp_df = (pd.DataFrame({'feature': list(gain), 'gain': list(gain.values())})
.sort_values('gain', ascending=False))
print(imp_df.head(5).round(2).to_string(index=False))
xgb.plot_importance(model, importance_type='gain', max_num_features=15)
plt.title('XGBoost Feature Importance (Gain)')
plt.tight_layout()
plt.savefig('importance.png')
# SHAP values: the most reliable view of each feature's effect
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(X_test)
shap.summary_plot(shap_values, X_test, feature_names=feature_names, show=False)
mean_abs = abs(shap_values).mean(axis=0)
top = sorted(zip(feature_names, mean_abs), key=lambda kv: -kv[1])[:5]
print("\nTop 5 by mean |SHAP|: " + ", ".join(f"{f} ({v:.3f})" for f, v in top))
Built-in importances can mislead, especially with correlated features. Above, gain ranks f18 second, while SHAP ranks it fifth and puts f2 second. SHAP values are consistent and show the direction of each feature's effect for each row. They are not magic either: when two features are strongly correlated, SHAP has to split the credit between them, so read those pairs together. TreeExplainer is fast on XGBoost models.
Built-in importances गुमराह कर सकती हैं, ख़ासकर correlated features के साथ। ऊपर gain, f18 को दूसरे स्थान पर रखता है, जबकि SHAP उसे पाँचवें पर रखता है और f2 को दूसरे पर। SHAP values consistent हैं और हर row के लिए हर feature के असर की दिशा दिखाती हैं। ये भी जादू नहीं हैं: जब दो features बहुत correlated हों, तो SHAP को credit उनके बीच बाँटना पड़ता है, इसलिए ऐसे जोड़ों को साथ पढ़ें। XGBoost models पर TreeExplainer तेज़ है।
内置重要性可能产生误导,特别是在特征相关时。上面 gain 把 f18 排第二,而 SHAP 把它排第五,并把 f2 排第二。SHAP 值具有一致性,能显示每个特征对每一行影响的方向。但它也不是万能的:两个特征高度相关时,SHAP 只能在它们之间分配功劳,所以要把这类特征放在一起看。TreeExplainer 在 XGBoost 上很快。
Complete Production Pipeline — End-to-Endपूरी Production Pipeline — शुरू से अंत तक完整生产流程 — 端到端
This pipeline fixes a common mistake. Many tutorials find the number of trees once (at learning_rate 0.05), then let Optuna change the learning rate while keeping that tree count fixed. But the right number of trees depends on the learning rate. Here, every trial uses early stopping on the validation set, so it finds its own tree count.
यह pipeline एक आम गलती ठीक करती है। कई tutorials trees की संख्या एक बार खोजते हैं (learning_rate 0.05 पर), फिर Optuna को learning rate बदलने देते हैं जबकि trees की संख्या वही रहती है। पर trees की सही संख्या learning rate पर निर्भर करती है। यहाँ हर trial validation set पर early stopping इस्तेमाल करता है, इसलिए वह अपनी trees की संख्या खुद खोजता है।
这个流程修正了一个常见错误。很多教程只找一次树的数量(在 learning_rate 0.05 时),然后让 Optuna 改变学习率,却保持树的数量不变。但合适的树数量取决于学习率。这里每个试验都在验证集上使用 early stopping,因此会找到自己的树数量。
import optuna
import xgboost as xgb
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score, classification_report
# ── STEP 1: Data: train / validation / test ──────────────
X, y = make_classification(n_samples=10000, n_features=25,
n_informative=15, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, stratify=y, random_state=42)
X_tr, X_val, y_tr, y_val = train_test_split(
X_train, y_train, test_size=0.15, stratify=y_train, random_state=42)
# ── STEP 2: Optuna. Each trial uses early stopping on the validation set,
# so the number of trees is found per trial (it depends on learning_rate).
optuna.logging.set_verbosity(optuna.logging.WARNING)
def objective(trial):
model = xgb.XGBClassifier(
n_estimators=3000,
learning_rate=trial.suggest_float('learning_rate', 0.01, 0.2, log=True),
max_depth=trial.suggest_int('max_depth', 3, 8),
min_child_weight=trial.suggest_int('min_child_weight', 1, 7),
subsample=trial.suggest_float('subsample', 0.6, 1.0),
colsample_bytree=trial.suggest_float('colsample_bytree', 0.5, 1.0),
gamma=trial.suggest_float('gamma', 0, 3),
reg_alpha=trial.suggest_float('reg_alpha', 1e-4, 5, log=True),
reg_lambda=trial.suggest_float('reg_lambda', 1e-4, 5, log=True),
eval_metric='logloss', early_stopping_rounds=50, random_state=42)
model.fit(X_tr, y_tr, eval_set=[(X_val, y_val)], verbose=False)
trial.set_user_attr('n_trees', model.best_iteration + 1)
return model.best_score # validation logloss
study = optuna.create_study(direction='minimize',
sampler=optuna.samplers.TPESampler(seed=42))
study.optimize(objective, n_trials=80)
best_n = study.best_trial.user_attrs['n_trees']
print(f"Best val logloss: {study.best_value:.5f} with {best_n} trees")
# ── STEP 3: Refit on train + validation with the best settings ──
final_model = xgb.XGBClassifier(**study.best_params, n_estimators=best_n,
eval_metric='logloss', random_state=42)
final_model.fit(X_train, y_train)
# ── STEP 4: Test set: used exactly once ──────────────────
y_proba = final_model.predict_proba(X_test)[:, 1]
print(f"\nTest AUC-ROC: {roc_auc_score(y_test, y_proba):.5f}\n")
print(classification_report(y_test, final_model.predict(X_test), digits=4))
Golden Rules — XGBoost & Hyperparameter TuningGolden Rules — XGBoost और Hyperparameter Tuning黄金法则 — XGBoost 与超参数调优
n_estimators high (1000–3000) and early_stopping_rounds=50 on a validation set. When you tune the learning rate, let early stopping find the tree count inside each trial, because it changes with the learning rate.n_estimators ऊँचा (1000–3000) और early_stopping_rounds=50 रखें। जब आप learning rate tune करें, तो हर trial के अंदर early stopping को trees की संख्या खोजने दें, क्योंकि यह learning rate के साथ बदलती है।n_estimators 设大(1000–3000),并设 early_stopping_rounds=50。调学习率时,让 early stopping 在每个试验里找树的数量,因为它会随学习率变化。learning_rate=0.05. At the end, halve it and let early stopping roughly double the trees. This often gives a small extra gain, at about twice the training time.learning_rate=0.05 से शुरू करें। आख़िर में इसे आधा करें और early stopping को trees लगभग दोगुने करने दें। इससे अक्सर थोड़ा और फ़ायदा मिलता है, लगभग दोगुने training time पर।learning_rate=0.05 开始。最后把它减半,让 early stopping 把树大约翻倍。这常常能再带来一点提升,代价是训练时间约翻倍。max_depth=4–6 works well; going deeper rarely helps and raises the overfitting risk.max_depth=4–6 अच्छा चलता है; ज़्यादा गहरा जाने से शायद ही फ़ायदा होता है और overfitting का ख़तरा बढ़ता है।max_depth=4–6 效果很好;更深很少有帮助,还会增加过拟合风险。subsample and colsample_bytree between 0.6 and 0.9 make trees less alike and are among XGBoost's strongest tools against overfitting.subsample और colsample_bytree trees को कम एक जैसा बनाते हैं और overfitting के ख़िलाफ़ XGBoost के सबसे मज़बूत tools में से हैं।subsample 和 colsample_bytree 设在 0.6–0.9,让树之间差异更大,这是 XGBoost 对抗过拟合最有力的工具之一。scale_pos_weight = negatives / positives and use eval_metric='aucpr' (precision-recall AUC), which is more sensitive to the rare class than ROC-AUC. Then choose the decision threshold on validation data.scale_pos_weight = negatives / positives रखें और eval_metric='aucpr' (precision-recall AUC) इस्तेमाल करें, जो ROC-AUC से ज़्यादा rare class के प्रति sensitive है। फिर validation data पर decision threshold चुनें।scale_pos_weight = 负类数 / 正类数,并使用 eval_metric='aucpr'(精确率-召回率 AUC),它比 ROC-AUC 对少数类更敏感。然后在验证集上选择决策阈值。TreeExplainer is fast on XGBoost. Read correlated features together.TreeExplainer तेज़ है। Correlated features को साथ पढ़ें।TreeExplainer 在 XGBoost 上很快。相关特征要放在一起看。XGBoost vs LightGBM vs CatBoost — Quick Decision GuideXGBoost vs LightGBM vs CatBoost — जल्दी फ़ैसलाXGBoost vs LightGBM vs CatBoost — 快速选择指南
| Propertyगुण属性 | XGBoost | LightGBM | CatBoost |
|---|---|---|---|
| Default tree growthDefault tree growth默认生长方式 | Depth-wise (lossguide optional)Depth-wise (lossguide वैकल्पिक)按层(可选 lossguide) | Leaf-wiseLeaf-wise按叶 | Symmetric (oblivious) treesSymmetric (oblivious) trees对称(oblivious)树 |
| Training speedTraining speed训练速度 | Fast (hist)तेज़ (hist)快(hist) | Often the fastestअक्सर सबसे तेज़通常最快 | Slower on large dense dataबड़े dense data पर धीमा大规模稠密数据上较慢 |
| Categorical featuresCategorical features类别特征 | Native with enable_categorical=Trueenable_categorical=True के साथ native设 enable_categorical=True 后原生支持 | Native (category dtype)Native (category dtype)原生(category 类型) | Excellent native supportबेहतरीन native support出色的原生支持 |
| Missing valuesMissing values缺失值 | NativeNative原生 | NativeNative原生 | NativeNative原生 |
| Very large data (>1M rows)बहुत बड़ा data (>1M rows)超大数据(>100 万行) | Good (hist, GPU)अच्छा (hist, GPU)良好(hist、GPU) | Excellentबेहतरीन出色 | Goodअच्छा良好 |
| Sensitivity to settingsSettings के प्रति sensitivity对参数的敏感度 | Mediumमध्यम中 | High (num_leaves)ज़्यादा (num_leaves)高(num_leaves) | Low (strong defaults)कम (मज़बूत defaults)低(默认值强) |
Start with XGBoost for its reliability and huge documentation. Try LightGBM when training is too slow on very large data. Try CatBoost when you have many categorical columns or little time to tune. In competitions, people often blend all three.
Reliability और बहुत ज़्यादा documentation के लिए XGBoost से शुरू करें। बहुत बड़े data पर training बहुत धीमी हो तो LightGBM आज़माएँ। कई categorical columns हों या tuning का समय कम हो तो CatBoost आज़माएँ। Competitions में लोग अक्सर तीनों को मिला देते हैं।
因为可靠且文档丰富,先从 XGBoost 开始。在超大数据上训练太慢时试试 LightGBM。类别列很多或调参时间不多时试试 CatBoost。在比赛中,人们常把三者融合使用。