A decision tree makes predictions by repeatedly splitting the data into smaller groups.
At each split, it tries to separate the training examples so that the resulting groups contain examples with similar labels.
Each split divides the feature space into smaller regions. Each leaf of the tree corresponds to one of these regions and produces a final prediction.
Impurity and Split Selection
To decide which split is best, we need a way to measure how mixed the labels are at a node. This is called impurity.
A pure node contains examples from only one class. A highly impure node contains a mixture of classes.
Two common impurity measures are Gini impurity and entropy.
Suppose a node contains a set of training examples S. Let pk be the fraction of examples in the node that belong to class k:
pk=∣S∣∣Sk∣
Gini impurity is small when most examples belong to one class and large when the classes are mixed:
G(S)=k=1∑cpk(1−pk)
If the node is completely pure, one class has proportion 1 and all others have proportion 0, so:
G(S)=0
Entropy measures the same general idea: how uncertain the class label is within the node.
H(S)=−k=1∑cpklogpk
We define 0log0=0.
Both Gini impurity and entropy are 0 for a pure node and largest when the classes are evenly represented.
In binary classification, both Gini impurity and entropy are 0 at a pure node and largest when the two classes are equally represented.
A candidate split divides the examples at a node into a left child SL and a right child SR.
For either impurity measure I, the weighted impurity after the split is:
Isplit=∣S∣∣SL∣I(SL)+∣S∣∣SR∣I(SR)
The gain from the split is the reduction in impurity:
ΔI=I(S)−Isplit
A greedy decision tree chooses the split with the largest gain, or equivalently the smallest weighted child impurity.
Entropy also has an information-theoretic interpretation. Relative to the uniform class distribution, lower entropy corresponds to larger KL divergence.
›See derivation
Let q be the uniform distribution over the c classes:
qi=c1
Then:
DKL(p∥q)=i=1∑cpilogqipi
=i=1∑c(pilogpi−pilogc1)
Substituting qi=c1.
=i=1∑cpilogpi+logci=1∑cpi
=i=1∑cpilogpi+logc
The class proportions sum to 1.
Therefore:
argpmaxDKL(p∥q)=argpmax[i=1∑cpilogpi+logc]
=argpmaxi=1∑cpilogpi
logc does not depend on p.
=argpmin(−i=1∑cpilogpi)=argpminH(p)
Building a Tree
Decision trees are usually built greedily: at each node, we choose the best split available at that moment and then repeat the process on each child.
This does not guarantee the globally best tree, but it makes training practical.
For a numerical feature xj, a split chooses a threshold t.
Examples with:
xj≤t
go to the left child, while examples with:
xj>t
go to the right child.
Therefore:
SL(j,t)={(x,y)∈S:xj≤t}SR(j,t)={(x,y)∈S:xj>t}
Suppose the distinct observed values of feature j are:
v1<v2<⋯<vr
We only need to consider thresholds between consecutive values:
Tj={2vl+vl+1:l=1,…,r−1}
For a candidate feature j and threshold t, the gain is:
The variance term measures how much the prediction at x would change if we trained the model on a different dataset.
Imagine we could repeatedly draw new training datasets from the population and train one model on each dataset.
If we train B models and average them:
hB(x)=B1b=1∑BhDb(x)
then as the number of models grows:
hB(x)B→∞ED[hD(x)]
Averaging therefore makes the prediction more stable across independently trained models.
In practice, however, we only have one training set.
Bagging creates new datasets from it using bootstrap sampling.
If the original training set contains N examples, each bootstrap dataset is created by drawing N examples from the training set with replacement.
This means that some examples may appear multiple times, while others may not appear at all.
If we generate B bootstrap datasets:
D1∗,…,DB∗
and train one model on each, the bagged prediction for regression is:
hB∗(x)=B1b=1∑BhDb∗(x)
For classification, we usually use a majority vote or average the predicted class probabilities.
Bagging is especially useful for unstable, high-variance models such as deep decision trees.
Averaging works best when the individual models make different errors.
If the models are highly correlated, averaging cannot remove much variance.
Suppose the predictions of the base models at some fixed x all have variance σh2 and pairwise correlation ρ. Then:
Var(hB∗(x))=σh2(ρ+B1−ρ)
As B grows, the second term becomes smaller.
However, the correlated part:
ρσh2
remains.
This is why it is useful for the models in an ensemble to be both accurate and different from one another.
Out-of-Bag Error
Because bootstrap sampling uses replacement, each tree leaves out some training examples.
The probability that a particular training example is not selected in one bootstrap sample is:
(1−N1)N
For large N:
(1−N1)N≈e−1≈0.37
So about 37 of the training examples are left out of any particular bootstrap sample.
These are called out-of-bag, or OOB, examples.
For each training example i, let Oi be the set of models whose bootstrap samples did not contain that example.
For regression, its OOB prediction is:
hi=∣Oi∣1b∈Oi∑hb(x(i))
For classification, we use the same voting or probability-averaging rule used by the full ensemble.
The OOB error is then:
ϵoob=N1i=1∑Nloss(hi,y(i))
OOB error gives us an internal estimate of predictive performance without creating a separate validation set.
With very few trees, some examples may not yet have any OOB predictions. In that case, we compute the estimate only using examples with at least one OOB model.
Random Forests
Random forests extend bagging by adding randomness inside each tree.
In ordinary bagging, every tree can consider all d features when choosing a split.
In a random forest, each split considers only a random subset of the available features.
This makes the trees less similar to one another, reducing their correlation and making averaging more effective.
The number of candidate features considered at each split is a tunable hyperparameter.
A common classification default is approximately:
d
although different defaults are often used for regression.
Boosting
Bagging trains many models independently and then combines them.
Boosting works differently: it trains models sequentially.
Each new model tries to improve the mistakes made by the current ensemble.
The final model is a weighted sum of weak learners:
Ht(x)=j=1∑tαjhj(x)
A weak learner is a simple model that performs only slightly better than a trivial baseline. In tree-based boosting, it is often a shallow decision tree.
Gradient Boosting
At each round, we want to add a new learner that reduces the training loss.
Let:
L(H)=i=1∑nℓ(y(i),H(x(i)))
where ℓ is the loss for one example.
To know how the prediction for each training example should change, we differentiate the loss with respect to the current prediction:
gt(i)=∂u∂ℓ(y(i),u)u=Ht(x(i))
The negative gradient:
−gt(i)
tells us the direction in which the prediction should move to locally reduce the loss.
Gradient boosting therefore fits the next weak learner to approximate these negative gradients:
ht+1=argh∈Hmini=1∑n[−gt(i)−h(x(i))]2
For squared error:
ℓ(y,u)=21(u−y)2
the gradient is:
gt(i)=Ht(x(i))−y(i)
so the negative gradient is:
−gt(i)=y(i)−Ht(x(i))
These are simply the residuals.
So for squared-error regression, gradient boosting repeatedly fits a weak learner to the current residuals.
›See derivation
Using a first-order Taylor approximation around the current predictions:
L(Ht+αh)≈L(Ht)+αi=1∑ngt(i)h(x(i))
For a fixed positive α, minimizing this approximation gives:
ht+1=argh∈Hmin[L(Ht)+αi=1∑ngt(i)h(x(i))]
=argh∈Hmini=1∑ngt(i)h(x(i))
L(Ht) and the fixed positive value α do not depend on h.
Therefore, we want a weak learner whose predictions point against the gradient.
For squared loss:
ℓ(y(i),Ht(x(i)))=21(Ht(x(i))−y(i))2
Differentiating:
gt(i)=∂Ht(x(i))∂ℓ=Ht(x(i))−y(i)
Therefore:
−gt(i)=y(i)−Ht(x(i))
which is the residual.
Once the weak learner has been fitted, we choose a step size α that reduces the actual loss:
α=arga≥0minL(Ht+aht+1)
Then update:
Ht+1=Ht+αht+1
So gradient boosting repeatedly:
computes the direction in which each prediction should move,
fits a weak learner to approximate that direction,
chooses a step size,
adds the weak learner to the ensemble.
H←H0Repeat {For each i,r(i)←−∂H(x(i))∂ℓ(y(i),H(x(i)))h←argh∈Hmini=1∑n(r(i)−h(x(i)))2α←arga≥0minL(H+ah)H←H+αh}
AdaBoost
AdaBoost is a boosting algorithm for binary classification.
Its key idea is to give more attention to training examples that the current ensemble gets wrong.
Each round fits a weak learner, gives more weight to examples it misclassifies, and adds the new learner to the weighted ensemble.
We encode both the true label and each weak learner's prediction as either −1 or +1:
y(i)∈{−1,1}h(x)∈{−1,1}
With this encoding:
y(i)h(x(i))=1
when the prediction is correct, and:
y(i)h(x(i))=−1
when it is wrong.
AdaBoost uses exponential loss:
ℓi(H)=e−y(i)H(x(i))
and the total training loss is:
L(H)=i=1∑ne−y(i)H(x(i))
Correct predictions with a large positive margin have small loss, while incorrect predictions have large loss.
The derivative with respect to the prediction for example i is:
∂H(x(i))∂L=−y(i)e−y(i)H(x(i))
This naturally gives more importance to examples with large exponential loss.
Define the normalized weight of example i at round t as:
wt(i)=∑j=1ne−y(j)Ht(x(j))e−y(i)Ht(x(i))
Examples that the current ensemble handles poorly receive larger weights.
The next weak learner minimizes the weighted classification error:
For the optimal AdaBoost step size, the normalization factor has a closed form.
›See derivation
Let:
Zt=i=1∑nwt(i)e−αty(i)ht(x(i))
Split the sum into correctly and incorrectly classified examples:
Zt=e−αt(1−ϵt)+eαtϵt
Correct examples have y(i)ht(x(i))=1, while incorrect examples have y(i)ht(x(i))=−1.
Using:
αt=21ln(ϵt1−ϵt)
we have:
e−αt=1−ϵtϵt
and:
eαt=ϵt1−ϵt
Therefore:
Zt=1−ϵtϵt(1−ϵt)+ϵt1−ϵtϵt=2ϵt(1−ϵt)
After T rounds, the ensemble is:
HT(x)=t=1∑Tαtht(x)
AdaBoost predicts using the sign of this weighted vote:
y(x)=sign(HT(x))=sign(t=1∑Tαtht(x))
The standard closed-form step assumes:
0<ϵt<21
If ϵt=0, the weak learner perfectly classifies all examples with positive weight, so boosting can stop.
If ϵt≥21, the learner has no positive edge under the current weights and should not be added in this form.
H←0For each i,w(i)←n1Repeat {h←argh∈Hmini=1∑nw(i)1{y(i)=h(x(i))}ϵ←i=1∑nw(i)1{y(i)=h(x(i))}α←21ln(ϵ1−ϵ)H←H+αhFor each i,w(i)←w(i)e−αy(i)h(x(i))Normalize the weights so that i∑w(i)=1}