How `gamma` Controls Tree Pruning in XGBoost

12 min read

If XGBoost’s hyperparameters were a band, gamma would be the bassist — often overlooked, but everything falls apart without it. While practitioners obsess over max_depth, eta, and n_estimators, gamma quietly does the heavy lifting of controlling model complexity at the finest granularity: per-leaf.

What gamma actually does

When XGBoost evaluates a candidate split at a tree node, it computes a gain score:

$$ \text{Gain} = \frac{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] $$

The split is accepted if and only if:

$$ \text{Gain} > \gamma $$

If the gain is less than gamma, the algorithm stops splitting at this node. Gamma is the minimum loss reduction required to add a new leaf. A higher gamma means the tree demands a larger improvement to justify making the tree deeper.

Gamma vs. max_depth vs. min_child_weight

These three parameters all constrain tree growth, but at different levels:

ParameterConstrainsEffect
gammaPer-split gainPrunes any split that doesn’t reduce loss enough
max_depthMaximum tree depthCaps the tree at a fixed number of levels
min_child_weightMinimum sum of Hessian in a leafPrevents creation of leaves with too few “effective” samples

Gamma is the most principled of the three: it’s directly derived from the optimization objective. max_depth and min_child_weight are practical heuristics that often achieve similar effects but without the theoretical backing.

How to think about gamma values

For a typical regression problem with squared error loss:

  • gamma = 0 (default): no minimum gain threshold. The tree will grow until max_depth or min_child_weight stops it. In practice, this is often fine because the other regularization parameters (eta, subsample, colsample) prevent overfitting.
  • gamma = 1-5: moderate pruning. Prevents splits that reduce MSE by less than 1-5 units. Useful when you know the noise level in your data.
  • gamma = 10+: aggressive pruning. Only splits with substantial gain survive. Results in very shallow trees, which might underfit unless compensated by adding more trees (higher n_estimators).

Gamma and the loss function scale

A critical practical detail: gamma is loss-scale-dependent. If your loss function values range from 0 to 1, a gamma of 1 would almost certainly prevent any splitting. If your loss values range from 1000 to 10000, gamma = 1 would have almost no effect.

This means you should re-tune gamma whenever you:

  1. Change the objective function (e.g., switching from MSE to MAE)
  2. Rescale your target variable
  3. Switch from regression to classification (loss scales change dramatically)

A reasonable approach: start with gamma = 0, observe the typical gain values in your first few trees (enable verbosity=2 to see split gain logs), and set gamma to a fraction of the median gain.

The interaction with learning rate

Low eta (learning rate) and low gamma often work well together — small step sizes allow many shallow trees to collectively learn the signal. High eta and high gamma is trickier: each tree makes a larger contribution, so pruning aggressively might cut off signal-bearing splits.

A practical rule of thumb: if you’re using eta = 0.3 (the default), keep gamma = 0 unless you see clear overfitting. If you’re using eta = 0.01 (fine-grained learning), gamma = 0 is almost always correct — the small learning rate itself controls overfitting by shrinking each tree’s contribution.

Debugging with gamma

If your XGBoost model is producing trees with fewer leaves than expected, check gamma first. Setting gamma = 0 and re-running will tell you whether gamma was overly aggressive. Conversely, if your training loss keeps dropping but validation loss plateaus early, increasing gamma can prune the overfitting splits.

import xgboost as xgb

# See what gamma does with verbose output
model = xgb.XGBRegressor(
    gamma=2.0,
    max_depth=6,
    eta=0.1,
    verbosity=2
)
model.fit(X_train, y_train)
# The log will show gain values for each split —
# splits with gain < 2.0 will be skipped

When to use gamma vs. post-pruning

Some practitioners prefer to grow deep trees (low gamma, high max_depth) and then post-prune based on validation performance. XGBoost’s gamma provides in-training pruning — the tree never grows the branch in the first place. In-training pruning is generally faster (fewer split evaluations) but might miss interactions that only look weak at the current node but prove valuable deeper in the tree. If your data has strong feature interactions, consider lower gamma and rely on other regularization instead.