Skip to content
Ahmed Haroon
Machine Learning

Decision Trees and Ensembles

Introduction

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.

Decision tree beside the axis-aligned partition of the feature space its splits produce

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 SS. Let pkp_k be the fraction of examples in the node that belong to class kk:

pk=SkS p_k = \frac{|S_k|}{|S|}

Gini impurity is small when most examples belong to one class and large when the classes are mixed:

G(S)=k=1cpk(1pk) G(S) = \sum_{k=1}^c p_k(1-p_k)

If the node is completely pure, one class has proportion 11 and all others have proportion 00, so:

G(S)=0 G(S)=0

Entropy measures the same general idea: how uncertain the class label is within the node.

H(S)=k=1cpklogpk H(S) = - \sum_{k=1}^c p_k\log p_k

We define 0log0=00\log0=0.

Both Gini impurity and entropy are 00 for a pure node and largest when the classes are evenly represented.

Binary Gini and entropy impurity as a function of one class proportion, both peaking at one half

In binary classification, both Gini impurity and entropy are 00 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 SLS_L and a right child SRS_R.

For either impurity measure II, the weighted impurity after the split is:

Isplit=SLSI(SL)+SRSI(SR) I_{\mathrm{split}} = \frac{|S_L|}{|S|} I(S_L) + \frac{|S_R|}{|S|} I(S_R)

The gain from the split is the reduction in impurity:

ΔI=I(S)Isplit \Delta I = I(S) - I_{\mathrm{split}}

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 qq be the uniform distribution over the cc classes:

qi=1c q_i = \frac{1}{c}

Then:

DKL(pq)=i=1cpilogpiqi D_{KL}(p\|q) = \sum_{i=1}^c p_i \log \frac{p_i}{q_i}
=i=1c(pilogpipilog1c) = \sum_{i=1}^c \left( p_i\log p_i - p_i\log\frac{1}{c} \right)
=i=1cpilogpi+logci=1cpi = \sum_{i=1}^c p_i\log p_i + \log c \sum_{i=1}^c p_i
=i=1cpilogpi+logc = \sum_{i=1}^c p_i\log p_i + \log c

Therefore:

argmaxpDKL(pq)=argmaxp[i=1cpilogpi+logc] \arg\max_p D_{KL}(p\|q) = \arg\max_p \left[ \sum_{i=1}^c p_i\log p_i + \log c \right]
=argmaxpi=1cpilogpi = \arg\max_p \sum_{i=1}^c p_i\log p_i
=argminp(i=1cpilogpi) = \arg\min_p \left( - \sum_{i=1}^c p_i\log p_i \right) =argminpH(p) = \arg\min_p H(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 xjx_j, a split chooses a threshold tt.

Examples with:

xjt x_j\leq t

go to the left child, while examples with:

xj>t x_j>t

go to the right child.

Therefore:

SL(j,t)={(x,y)S:xjt} S_L(j,t) = \{(x,y)\in S:x_j\leq t\} SR(j,t)={(x,y)S:xj>t} S_R(j,t) = \{(x,y)\in S:x_j>t\}

Suppose the distinct observed values of feature jj are:

v1<v2<<vr v_1<v_2<\cdots<v_r

We only need to consider thresholds between consecutive values:

Tj={vl+vl+12:l=1,,r1} \mathcal{T}_j = \left\{ \frac{v_l+v_{l+1}}{2} : l=1,\ldots,r-1 \right\}

For a candidate feature jj and threshold tt, the gain is:

ΔI(j,t)=I(S)SL(j,t)SI(SL(j,t))SR(j,t)SI(SR(j,t)) \Delta I(j,t) = I(S) - \frac{|S_L(j,t)|}{|S|} I(S_L(j,t)) - \frac{|S_R(j,t)|}{|S|} I(S_R(j,t))

The greedy split is:

(j,t)argmaxj,  tTjΔI(j,t) (j^*,t^*) \in \arg\max_{j,\;t\in\mathcal T_j} \Delta I(j,t)

If we keep splitting until every leaf is pure, the tree can become very large and overfit the training data.

Common stopping rules include a maximum depth, a minimum number of examples per node or leaf, and a minimum required gain.

We can also prune a tree after training by removing branches that do not improve generalization.

At a classification leaf, we estimate the class probabilities using the class proportions within that leaf:

p^(y=kleaf S)=SkS \widehat p(y=k\mid \text{leaf }S) = \frac{|S_k|}{|S|}

The predicted class is usually the majority class:

y^=argmaxkSk \widehat y = \arg\max_k |S_k|

Decision trees can also be used for regression.

The splitting process is the same, but instead of measuring class impurity, we measure how much the target values vary within the node.

The prediction at a regression leaf is the mean target:

y^S=1S(x,y)Sy \widehat y_S = \frac{1}{|S|} \sum_{(x,y)\in S} y

A common regression impurity is the mean squared deviation from this mean:

Ireg(S)=1S(x,y)S(yy^S)2 I_{\mathrm{reg}}(S) = \frac{1}{|S|} \sum_{(x,y)\in S} \left( y-\widehat y_S \right)^2

Regression splits choose the feature and threshold that minimize the weighted child impurity.

BuildTree(S): \operatorname{BuildTree}(S): If a stopping rule applies, return Leaf(S) \quad \text{If a stopping rule applies, return }\operatorname{Leaf}(S) Find (j,t)argmaxj,tΔI(j,t) \quad \text{Find } (j^*,t^*) \in \arg\max_{j,t} \Delta I(j,t) If ΔI(j,t)0, return Leaf(S) \quad \text{If } \Delta I(j^*,t^*)\leq0, \text{ return }\operatorname{Leaf}(S) Return Node(j,t,BuildTree(SL(j,t)),BuildTree(SR(j,t))) \quad \text{Return } \operatorname{Node} \left( j^*, t^*, \operatorname{BuildTree}(S_L(j^*,t^*)), \operatorname{BuildTree}(S_R(j^*,t^*)) \right)

Different tree algorithms mainly differ in how they choose splits.

ID3 traditionally uses entropy reduction. CART uses binary splits and commonly uses Gini impurity for classification and squared error for regression.

Both use greedy splitting, so a locally unhelpful split may be rejected even if it would enable better splits farther down the tree.

Bagging

Decision trees can have high variance: small changes in the training data can produce very different trees.

Bagging reduces this variance by training many models on slightly different datasets and averaging their predictions.

The idea comes from a simple fact: averaging noisy predictions makes the final prediction more stable.

Recall that mean squared prediction error can be decomposed into irreducible noise, squared bias, and variance:

ES,Yx[(YhS(x))2]=σ2(x)+(f(x)havg(x))2bias2+VarS(hS(x))variance \mathbb{E}_{S,Y\mid x} \left[ (Y-h_S(x))^2 \right] = \sigma^2(x) + \underbrace{ \left( f^*(x)-h_{\mathrm{avg}}(x) \right)^2 }_{\text{bias}^2} + \underbrace{ \operatorname{Var}_S \left( h_S(x) \right) }_{\text{variance}}

The variance term measures how much the prediction at xx 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 BB models and average them:

h^B(x)=1Bb=1BhDb(x) \widehat h_B(x) = \frac{1}{B} \sum_{b=1}^B h_{D_b}(x)

then as the number of models grows:

h^B(x)BED[hD(x)] \widehat h_B(x) \xrightarrow[B\to\infty]{} \mathbb E_D[h_D(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 NN examples, each bootstrap dataset is created by drawing NN 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 BB bootstrap datasets:

D1,,DB D_1^*,\ldots,D_B^*

and train one model on each, the bagged prediction for regression is:

h^B(x)=1Bb=1BhDb(x) \widehat h_B^*(x) = \frac{1}{B} \sum_{b=1}^B h_{D_b^*}(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 xx all have variance σh2\sigma_h^2 and pairwise correlation ρ\rho. Then:

Var(h^B(x))=σh2(ρ+1ρB) \operatorname{Var} \left( \widehat h_B^*(x) \right) = \sigma_h^2 \left( \rho + \frac{1-\rho}{B} \right)

As BB grows, the second term becomes smaller.

However, the correlated part:

ρσh2 \rho\sigma_h^2

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:

(11N)N \left( 1-\frac{1}{N} \right)^N

For large NN:

(11N)Ne10.37 \left( 1-\frac{1}{N} \right)^N \approx e^{-1} \approx 0.37

So about 3737% 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 ii, let OiO_i be the set of models whose bootstrap samples did not contain that example.

For regression, its OOB prediction is:

h~i=1OibOihb(x(i)) \widetilde h_i = \frac{1}{|O_i|} \sum_{b\in O_i} h_b(x^{(i)})

For classification, we use the same voting or probability-averaging rule used by the full ensemble.

The OOB error is then:

ϵoob=1Ni=1Nloss(h~i,y(i)) \epsilon_{\mathrm{oob}} = \frac{1}{N} \sum_{i=1}^N \operatorname{loss} \left( \widetilde h_i, y^{(i)} \right)

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 dd 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 \sqrt 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=1tαjhj(x) H_t(x) = \sum_{j=1}^t \alpha_j h_j(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=1n(y(i),H(x(i))) \mathcal L(H) = \sum_{i=1}^n \ell \left( y^{(i)}, H(x^{(i)}) \right)

where \ell 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)=(y(i),u)uu=Ht(x(i)) g_t^{(i)} = \left. \frac{ \partial \ell(y^{(i)},u) }{ \partial u } \right|_{ u=H_t(x^{(i)}) }

The negative gradient:

gt(i) -g_t^{(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=argminhHi=1n[gt(i)h(x(i))]2 h_{t+1} = \arg\min_{h\in\mathcal H} \sum_{i=1}^n \left[ -g_t^{(i)} - h(x^{(i)}) \right]^2

For squared error:

(y,u)=12(uy)2 \ell(y,u) = \frac12(u-y)^2

the gradient is:

gt(i)=Ht(x(i))y(i) g_t^{(i)} = H_t(x^{(i)})-y^{(i)}

so the negative gradient is:

gt(i)=y(i)Ht(x(i)) -g_t^{(i)} = y^{(i)}-H_t(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=1ngt(i)h(x(i)) \mathcal L(H_t+\alpha h) \approx \mathcal L(H_t) + \alpha \sum_{i=1}^n g_t^{(i)} h(x^{(i)})

For a fixed positive α\alpha, minimizing this approximation gives:

ht+1=argminhH[L(Ht)+αi=1ngt(i)h(x(i))] h_{t+1} = \arg\min_{h\in\mathcal H} \left[ \mathcal L(H_t) + \alpha \sum_{i=1}^n g_t^{(i)} h(x^{(i)}) \right]
=argminhHi=1ngt(i)h(x(i)) = \arg\min_{h\in\mathcal H} \sum_{i=1}^n g_t^{(i)} h(x^{(i)})

Therefore, we want a weak learner whose predictions point against the gradient.

For squared loss:

(y(i),Ht(x(i)))=12(Ht(x(i))y(i))2 \ell \left( y^{(i)}, H_t(x^{(i)}) \right) = \frac12 \left( H_t(x^{(i)})-y^{(i)} \right)^2

Differentiating:

gt(i)=Ht(x(i)) g_t^{(i)} = \frac{ \partial \ell }{ \partial H_t(x^{(i)}) } =Ht(x(i))y(i) = H_t(x^{(i)})-y^{(i)}

Therefore:

gt(i)=y(i)Ht(x(i)) -g_t^{(i)} = y^{(i)}-H_t(x^{(i)})

which is the residual.

Once the weak learner has been fitted, we choose a step size α\alpha that reduces the actual loss:

α=argmina0L(Ht+aht+1) \alpha = \arg\min_{a\geq0} \mathcal L(H_t+a h_{t+1})

Then update:

Ht+1=Ht+αht+1 H_{t+1} = H_t + \alpha h_{t+1}

So gradient boosting repeatedly:

  1. computes the direction in which each prediction should move,
  2. fits a weak learner to approximate that direction,
  3. chooses a step size,
  4. adds the weak learner to the ensemble.
HH0 H\leftarrow H_0 Repeat { \text{Repeat } \{ For each i,r(i)(y(i),H(x(i)))H(x(i)) \quad \text{For each }i,\quad r^{(i)} \leftarrow - \frac{ \partial \ell(y^{(i)},H(x^{(i)})) }{ \partial H(x^{(i)}) } hargminhHi=1n(r(i)h(x(i)))2 \quad h \leftarrow \arg\min_{h\in\mathcal H} \sum_{i=1}^n \left( r^{(i)} - h(x^{(i)}) \right)^2 αargmina0L(H+ah) \quad \alpha \leftarrow \arg\min_{a\geq0} \mathcal L(H+a h) HH+αh \quad H \leftarrow H+\alpha 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.

AdaBoost pipeline: dataset, weak learner, reweighted dataset, second weak learner, and the combined strong learner

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-1 or +1+1:

y(i){1,1} y^{(i)} \in \{-1,1\} h(x){1,1} h(x) \in \{-1,1\}

With this encoding:

y(i)h(x(i))=1 y^{(i)}h(x^{(i)})=1

when the prediction is correct, and:

y(i)h(x(i))=1 y^{(i)}h(x^{(i)})=-1

when it is wrong.

AdaBoost uses exponential loss:

i(H)=ey(i)H(x(i)) \ell_i(H) = e^{-y^{(i)}H(x^{(i)})}

and the total training loss is:

L(H)=i=1ney(i)H(x(i)) \mathcal L(H) = \sum_{i=1}^n e^{-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 ii is:

LH(x(i))=y(i)ey(i)H(x(i)) \frac{ \partial\mathcal L }{ \partial H(x^{(i)}) } = -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 ii at round tt as:

wt(i)=ey(i)Ht(x(i))j=1ney(j)Ht(x(j)) w_t^{(i)} = \frac{ e^{-y^{(i)}H_t(x^{(i)})} }{ \sum_{j=1}^n e^{-y^{(j)}H_t(x^{(j)})} }

Examples that the current ensemble handles poorly receive larger weights.

The next weak learner minimizes the weighted classification error:

ht+1=argminhHi=1nwt(i)1{y(i)h(x(i))} h_{t+1} = \arg\min_{h\in\mathcal H} \sum_{i=1}^n w_t^{(i)} 1\left\{ y^{(i)} \neq h(x^{(i)}) \right\}
See derivation

The weak learner should point against the gradient:

ht+1=argminhHi=1nLH(x(i))h(x(i)) h_{t+1} = \arg\min_{h\in\mathcal H} \sum_{i=1}^n \frac{ \partial\mathcal L }{ \partial H(x^{(i)}) } h(x^{(i)})

Substituting the derivative of the exponential loss:

=argminhH[i=1ny(i)h(x(i))ey(i)Ht(x(i))] = \arg\min_{h\in\mathcal H} \left[ - \sum_{i=1}^n y^{(i)} h(x^{(i)}) e^{-y^{(i)}H_t(x^{(i)})} \right]
=argminhH[i=1ny(i)h(x(i))wt(i)] = \arg\min_{h\in\mathcal H} \left[ - \sum_{i=1}^n y^{(i)} h(x^{(i)}) w_t^{(i)} \right]

Because both y(i)y^{(i)} and h(x(i))h(x^{(i)}) are in 1,1{-1,1}:

y(i)h(x(i))={1,y(i)=h(x(i))1,y(i)h(x(i)) -y^{(i)}h(x^{(i)}) = \begin{cases} -1, & y^{(i)}=h(x^{(i)}) \\ 1, & y^{(i)}\neq h(x^{(i)}) \end{cases}

Therefore:

i=1ny(i)h(x(i))wt(i) - \sum_{i=1}^n y^{(i)} h(x^{(i)}) w_t^{(i)} =i=1n1{y(i)h(x(i))}wt(i)i=1n1{y(i)=h(x(i))}wt(i) = \sum_{i=1}^n 1\left\{ y^{(i)}\neq h(x^{(i)}) \right\} w_t^{(i)} - \sum_{i=1}^n 1\left\{ y^{(i)}=h(x^{(i)}) \right\} w_t^{(i)}
=2i=1n1{y(i)h(x(i))}wt(i)1 = 2 \sum_{i=1}^n 1\left\{ y^{(i)}\neq h(x^{(i)}) \right\} w_t^{(i)} - 1

The constant factor 22 and constant term 1-1 do not affect the minimizer.

Therefore:

ht+1=argminhHi=1nwt(i)1{y(i)h(x(i))} h_{t+1} = \arg\min_{h\in\mathcal H} \sum_{i=1}^n w_t^{(i)} 1\left\{ y^{(i)}\neq h(x^{(i)}) \right\}

Let the weighted error of the selected weak learner be:

ϵt=i=1nwt(i)1{y(i)ht(x(i))} \epsilon_t = \sum_{i=1}^n w_t^{(i)} 1\left\{ y^{(i)} \neq h_t(x^{(i)}) \right\}

Once we choose the weak learner, we still need to decide how much influence it should have in the ensemble.

AdaBoost chooses the step size that minimizes the exponential loss:

αt=argminαL(Ht1+αht) \alpha_t = \arg\min_\alpha \mathcal L \left( H_{t-1} + \alpha h_t \right)

This gives:

αt=12ln(1ϵtϵt) \alpha_t = \frac12 \ln \left( \frac{1-\epsilon_t}{\epsilon_t} \right)

If:

0<ϵt<12 0<\epsilon_t<\frac12

then:

αt>0 \alpha_t>0

A more accurate weak learner has smaller ϵt\epsilon_t and therefore receives a larger weight in the final ensemble.

If:

ϵt=12 \epsilon_t=\frac12

then:

αt=0 \alpha_t=0

so the learner contributes nothing.

See derivation

We choose:

α=argminαL(Ht+αh) \alpha = \arg\min_\alpha \mathcal L(H_t+\alpha h)

Using exponential loss:

α=argminαi=1ney(i)(Ht(x(i))+αh(x(i))) \alpha = \arg\min_\alpha \sum_{i=1}^n e^{-y^{(i)} \left( H_t(x^{(i)}) + \alpha h(x^{(i)}) \right)}

Differentiate with respect to α\alpha and set the result equal to 00:

i=1ny(i)h(x(i))ey(i)Ht(x(i))eαy(i)h(x(i))=0 - \sum_{i=1}^n y^{(i)} h(x^{(i)}) e^{-y^{(i)}H_t(x^{(i)})} e^{-\alpha y^{(i)}h(x^{(i)})} = 0
eαi:y(i)=h(x(i))ey(i)Ht(x(i))=eαi:y(i)h(x(i))ey(i)Ht(x(i)) e^{-\alpha} \sum_{i:y^{(i)}=h(x^{(i)})} e^{-y^{(i)}H_t(x^{(i)})} = e^\alpha \sum_{i:y^{(i)}\neq h(x^{(i)})} e^{-y^{(i)}H_t(x^{(i)})}

Divide by the normalization constant used to define w(i)w^{(i)}:

eαi:y(i)=h(x(i))w(i)=eαi:y(i)h(x(i))w(i) e^{-\alpha} \sum_{i:y^{(i)}=h(x^{(i)})} w^{(i)} = e^\alpha \sum_{i:y^{(i)}\neq h(x^{(i)})} w^{(i)}

The total weight of the incorrectly classified examples is:

ϵ=i:y(i)h(x(i))w(i) \epsilon = \sum_{i:y^{(i)}\neq h(x^{(i)})} w^{(i)}

so the total weight of the correctly classified examples is:

1ϵ 1-\epsilon

Therefore:

eα(1ϵ)=eαϵ e^{-\alpha}(1-\epsilon) = e^\alpha\epsilon e2α=1ϵϵ e^{2\alpha} = \frac{1-\epsilon}{\epsilon}

Taking logs:

2α=ln(1ϵϵ) 2\alpha = \ln \left( \frac{1-\epsilon}{\epsilon} \right)

Therefore:

α=12ln(1ϵϵ) \alpha = \frac12 \ln \left( \frac{1-\epsilon}{\epsilon} \right)

After adding the weak learner, AdaBoost changes the example weights.

Misclassified examples receive more weight, while correctly classified examples receive less.

Before normalization:

wt+1(i)wt(i)eαty(i)ht(x(i)) w_{t+1}^{(i)} \propto w_t^{(i)} e^{-\alpha_t y^{(i)}h_t(x^{(i)})}

Because:

y(i)ht(x(i))=1 y^{(i)}h_t(x^{(i)}) = 1

for a correct prediction, its weight is multiplied by:

eαt e^{-\alpha_t}

For a misclassified example:

y(i)ht(x(i))=1 y^{(i)}h_t(x^{(i)}) = -1

so its weight is multiplied by:

eαt e^{\alpha_t}

We then normalize the weights so they sum to 11:

wt+1(i)=wt(i)eαty(i)ht(x(i))j=1nwt(j)eαty(j)ht(x(j)) w_{t+1}^{(i)} = \frac{ w_t^{(i)} e^{-\alpha_t y^{(i)}h_t(x^{(i)})} }{ \sum_{j=1}^n w_t^{(j)} e^{-\alpha_t y^{(j)}h_t(x^{(j)})} }

For the optimal AdaBoost step size, the normalization factor has a closed form.

See derivation

Let:

Zt=i=1nwt(i)eαty(i)ht(x(i)) Z_t = \sum_{i=1}^n w_t^{(i)} e^{-\alpha_t y^{(i)}h_t(x^{(i)})}

Split the sum into correctly and incorrectly classified examples:

Zt=eαt(1ϵt)+eαtϵt Z_t = e^{-\alpha_t}(1-\epsilon_t) + e^{\alpha_t}\epsilon_t

Using:

αt=12ln(1ϵtϵt) \alpha_t = \frac12 \ln \left( \frac{1-\epsilon_t}{\epsilon_t} \right)

we have:

eαt=ϵt1ϵt e^{-\alpha_t} = \sqrt{ \frac{\epsilon_t}{1-\epsilon_t} }

and:

eαt=1ϵtϵt e^{\alpha_t} = \sqrt{ \frac{1-\epsilon_t}{\epsilon_t} }

Therefore:

Zt=ϵt1ϵt(1ϵt)+1ϵtϵtϵt Z_t = \sqrt{ \frac{\epsilon_t}{1-\epsilon_t} } (1-\epsilon_t) + \sqrt{ \frac{1-\epsilon_t}{\epsilon_t} } \epsilon_t =2ϵt(1ϵt) = 2 \sqrt{ \epsilon_t(1-\epsilon_t) }

After TT rounds, the ensemble is:

HT(x)=t=1Tαtht(x) H_T(x) = \sum_{t=1}^T \alpha_t h_t(x)

AdaBoost predicts using the sign of this weighted vote:

y^(x)=sign(HT(x)) \widehat y(x) = \operatorname{sign} \left( H_T(x) \right) =sign(t=1Tαtht(x)) = \operatorname{sign} \left( \sum_{t=1}^T \alpha_t h_t(x) \right)

The standard closed-form step assumes:

0<ϵt<12 0<\epsilon_t<\frac12

If ϵt=0\epsilon_t=0, the weak learner perfectly classifies all examples with positive weight, so boosting can stop.

If ϵt12\epsilon_t\geq\frac12, the learner has no positive edge under the current weights and should not be added in this form.

H0 H\leftarrow0 For each i,w(i)1n \text{For each }i,\quad w^{(i)} \leftarrow \frac1n Repeat { \text{Repeat } \{ hargminhHi=1nw(i)1{y(i)h(x(i))} \quad h \leftarrow \arg\min_{h\in\mathcal H} \sum_{i=1}^n w^{(i)} 1\left\{ y^{(i)} \neq h(x^{(i)}) \right\} ϵi=1nw(i)1{y(i)h(x(i))} \quad \epsilon \leftarrow \sum_{i=1}^n w^{(i)} 1\left\{ y^{(i)} \neq h(x^{(i)}) \right\} α12ln(1ϵϵ) \quad \alpha \leftarrow \frac12 \ln \left( \frac{1-\epsilon}{\epsilon} \right) HH+αh \quad H \leftarrow H+\alpha h For each i,w(i)w(i)eαy(i)h(x(i)) \quad \text{For each }i,\quad w^{(i)} \leftarrow w^{(i)} e^{-\alpha y^{(i)}h(x^{(i)})} Normalize the weights so that iw(i)=1 \quad \text{Normalize the weights so that } \sum_i w^{(i)}=1 } \}