Boosting: models that learn from the last one's mistakes

On this page
  1. Bagging vs boosting in one picture
  2. AdaBoost: reweight the mistakes
  3. Gradient boosting: fit the leftover error
  4. The code
  5. What the big libraries add
  6. Summary
  7. References

Boosting is covered in section 8.2.3 of An Introduction to Statistical Learning, and its classic example is AdaBoost. Boosted trees, including the popular XGBoost and LightGBM libraries, are built on the same idea, so it is worth knowing what they do.

Bagging vs boosting in one picture

Boosting

data, mistakes up-weighted

data, mistakes up-weighted

data

tree 1

tree 2

tree 3

weighted sum

Bagging

data

tree 1

tree 2

tree 3

average

Table 1. Bagging against boosting
ItemBagging / random forestBoosting
How trees are trainedindependently, in parallelone after another
What each tree seesa random resamplethe previous trees’ mistakes
Typical treesdeep (low bias, high variance)shallow (high bias, low variance)
What it reducesvariancemainly bias
Riskcan’t overfit by adding treescan overfit if you add too many

In the bias and variance terms of Table 1: bagging takes complex, unstable models and steadies them. Boosting takes simple, stable models and makes them smarter.

AdaBoost: reweight the mistakes

AdaBoost (adaptive boosting, Freund and Schapire, 1997) was the first widely used boosting method.

  1. Give every training example the same weight.
  2. Train a weak model, often a stump: a tree with a single question.
  3. Measure its weighted error ε\risk{\varepsilon}: the total weight of the examples it got wrong.
  4. Give the model a vote α\key{\alpha}: the lower its error, the bigger its say.
  5. Increase the weight of the examples it got wrong, decrease the rest, and repeat from step 2.

The final prediction is a weighted vote of all the models.

The formulas

α, the model's voteε, its weighted errorwrong examplesright examples

The vote of model tt:

αt=12ln⁡ ⁣(1−εtεt)\key{\alpha_t} = \frac{1}{2} \ln\!\left(\frac{1 - \risk{\varepsilon_t}}{\risk{\varepsilon_t}}\right)

If εt=0.5\risk{\varepsilon_t} = 0.5 (a coin flip), αt=0\key{\alpha_t} = 0: no say. The smaller the error, the larger αt\key{\alpha_t}.

The weight update for each example ii, depending on whether model tt got it wrong or right:

wi←wi×{eαtif wronge−αtif rightw_i \leftarrow w_i \times \begin{cases} \bad{e^{\key{\alpha_t}}} & \bad{\text{if wrong}} \\ \good{e^{-\key{\alpha_t}}} & \good{\text{if right}} \end{cases}

Then all the weights are divided by their total, so they add up to 1 again.

Worked example: one round, ten rows

Ten training rows, each with weight 0.1. The first stump gets 3 of them wrong:

ε=3×0.1\risk{\varepsilon} = 3 \times 0.1 ε=0.3\risk{\varepsilon} = \risk{0.3} α=12ln⁡ ⁣(0.70.3)\key{\alpha} = \tfrac{1}{2} \ln\!\left(\tfrac{0.7}{\risk{0.3}}\right) α=0.4236\key{\alpha} = \key{0.4236}

wrong rows are multiplied by e0.4236=1.5275\bad{e^{\key{0.4236}}} = 1.5275, right ones by e−0.4236=0.6547\good{e^{-\key{0.4236}}} = 0.6547 (Table 2):

Table 2. One AdaBoost weight update on ten rows
ItemBefore×\times factorUnnormalisedAfter normalising (÷\div 0.9165)
Each wrong row (3)0.11.52750.152750.1667
Each right row (7)0.10.65470.065470.0714

After one round, the 3 wrong rows carry half the total weight (3×0.1667=0.53 \times 0.1667 = 0.5), and the 7 right ones the other half. That’s always true after an AdaBoost update: the next model is forced to treat the previous model’s mistakes as half of its whole problem.

Notation in other books

Murphy’s Probabilistic Machine Learning: An Introduction (section 18.5.3, equations 18.30 and 18.34) writes the same algorithm slightly differently. He calls the vote βm=12ln⁡((1−errm)/errm)\key{\beta_m} = \tfrac{1}{2}\ln\big((1 - \risk{\text{err}_m}) / \risk{\text{err}_m}\big), and only multiplies the wrong examples, by eαm\bad{e^{\key{\alpha_m}}} with αm=2βm\key{\alpha_m} = 2\key{\beta_m}, before normalising. That’s the same result: either way, a wrong example ends up e2βe^{2\key{\beta}} times heavier than a right one.

A note on scikit-learn’s numbers

scikit-learn’s AdaBoostClassifier (version 1.9) uses the SAMME form of the algorithm. With two classes, the weight it reports is

αt=ln⁡ ⁣(1−εtεt)\key{\alpha_t} = \ln\!\left(\frac{1 - \risk{\varepsilon_t}}{\risk{\varepsilon_t}}\right)

without the 12\tfrac{1}{2}. That’s exactly Murphy’s αm=2βm\key{\alpha_m} = 2\key{\beta_m}. Every vote is twice as big, so the final ranking of predictions is the same; only the printed numbers differ. If you compare a textbook with ada.estimator_weights_, that’s why.

What AdaBoost did on the stress-month data

I boosted stumps on the 4,930 training rows (2020 to 2023) of the stress-month problem: will the next 20 days’ volatility be above 30%? 36.8% of training rows had a stress month ahead but only 24.1% of test rows, so accuracy is misleading (saying “calm” every time scores 75.9% on the test rows); that’s why the scores below are AUC (0.5 is a coin flip, 1.0 is perfect). Boosting libraries also offer class weights (scale_pos_weight in XGBoost) for rarer classes than this. The first three rounds are in Table 3:

Table 3. The first three AdaBoost rounds on the stress-month rows
RoundStump’s questionWeighted errorscikit-learn weight (its name for the vote)
120-day volatility?0.18681.4708
220-day volatility? (a different cut-off)0.39700.4181
320-day volatility? (a third cut-off)0.37540.5092

Round 1’s stump gets the easy cases: one cut on 20-day volatility is wrong on 18.7%\risk{18.7\%} of the weight, far better than the 36.8% of calling everything calm. AdaBoost then gives the rows it got wrong, mostly stress months that followed a calm one, half the total weight, which forces round 2 to look at them.

Round 2 asks about the same feature at a different cut-off and is wrong on 39.7% of the reweighted problem, so it earns a much smaller vote. Round 3 stays on 20-day volatility at a third cut-off, is wrong on 37.5%, and earns a vote a little larger than round 2’s. Each round fixes a part of what the earlier ones missed, and each gets a vote sized by how well it did on its version of the problem.

A single stump scores an AUC of 0.824 on the test rows. Boosting 81 of them reaches 0.895\key{0.895}.

Gradient boosting: fit the leftover error

Gradient boosting (Friedman, 2001) generalises the idea. Instead of reweighting examples, each new tree is trained to predict what the current model still gets wrong.

For regression with squared error, that’s literally the residuals. An Introduction to Statistical Learning gives it as Algorithm 8.2. Start with f^(x)=0\hat{f}(x) = 0 and residuals ri=yi\risk{r_i} = y_i. Then, for each round b=1,2,…,Bb = 1, 2, \dots, B, fit a small tree f^b\hat{f}^b to the residuals and update:

λ, how much of each tree is addedr, the error left

f^(x)←f^(x)+λf^b(x)(8.10)\hat{f}(x) \leftarrow \hat{f}(x) + \key{\lambda} \hat{f}^b(x) \text{(8.10)} ri←ri−λf^b(xi)(8.11)\risk{r_i} \leftarrow \risk{r_i} - \key{\lambda} \hat{f}^b(x_i) \text{(8.11)}

The final model is the sum of all the shrunken trees (symbols in Table 4):

f^(x)=∑b=1Bλf^b(x)(8.12)\hat{f}(x) = \sum_{b=1}^{B} \key{\lambda} \hat{f}^b(x) \qquad \text{(8.12)}
Table 4. Symbols in gradient boosting
SymbolMeaning
f^(x)\hat{f}(x)the model so far
ri\risk{r_i}the residuals: what’s still unexplained for example ii
f^b\hat{f}^bthe small tree added in round bb, trained to predict the residuals
λ\key{\lambda}the shrinkage or learning rate, a small number like 0.1 (ISLP suggests 0.01 or 0.001)
BBthe number of trees

Plain meaning: start with a rough guess. Look at the errors. Train a small tree to predict the errors. Add a fraction of it to the guess. Repeat. For other losses, like the log loss used for classification, “residuals” become the negative gradient of the loss (often called pseudo-residuals), which gives the method its name. The idea is the same.

The learning rate λ\key{\lambda} matters a lot. Each tree only corrects part of the error, so no single tree can push the model too far (Figure 1):

{"panels":[{"x0":52.28,"x1":565.2,"y0":29.16,"y1":232.48,"title":"Test score as trees are added (dot = round chosen on validation)","xlabel":"Number of trees in the model","ylabel":"Test AUC, 2022\u20132023 (0.5 = coin flip, 1 = perfect)","xlog":false}],"series":[{"panel":0,"label":"AdaBoost, stumps","color":"var(--chart-blue, #3b6ea5)","kind":"line","x":[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.0,20.0,21.0,22.0,23.0,24.0,25.0,26.0,27.0,28.0,29.0,30.0,31.0,32.0,33.0,34.0,35.0,36.0,37.0,38.0,39.0,40.0,41.0,42.0,43.0,44.0,45.0,46.0,47.0,48.0,49.0,50.0,51.0,52.0,53.0,54.0,55.0,56.0,57.0,58.0,59.0,60.0,61.0,62.0,63.0,64.0,65.0,66.0,67.0,68.0,69.0,70.0,71.0,72.0,73.0,74.0,75.0,76.0,77.0,78.0,79.0,80.0,81.0,82.0,83.0,84.0,85.0,86.0,87.0,88.0,89.0,90.0,91.0,92.0,93.0,94.0,95.0,96.0,97.0,98.0,99.0,100.0,101.0,102.0,103.0,104.0,105.0,106.0,107.0,108.0,109.0,110.0,111.0,112.0,113.0,114.0,115.0,116.0,117.0,118.0,119.0,120.0,121.0,122.0,123.0,124.0,125.0,126.0,127.0,128.0,129.0,130.0,131.0,132.0,133.0,134.0,135.0,136.0,137.0,138.0,139.0,140.0,141.0,142.0,143.0,144.0,145.0,146.0,147.0,148.0,149.0,150.0,151.0,152.0,153.0,154.0,155.0,156.0,157.0,158.0,159.0,160.0,161.0,162.0,163.0,164.0,165.0,166.0,167.0,168.0,169.0,170.0,171.0,172.0,173.0,174.0,175.0,176.0,177.0,178.0,179.0,180.0,181.0,182.0,183.0,184.0,185.0,186.0,187.0,188.0,189.0,190.0,191.0,192.0,193.0,194.0,195.0,196.0,197.0,198.0,199.0,200.0,201.0,202.0,203.0,204.0,205.0,206.0,207.0,208.0,209.0,210.0,211.0,212.0,213.0,214.0,215.0,216.0,217.0,218.0,219.0,220.0,221.0,222.0,223.0,224.0,225.0,226.0,227.0,228.0,229.0,230.0,231.0,232.0,233.0,234.0,235.0,236.0,237.0,238.0,239.0,240.0,241.0,242.0,243.0,244.0,245.0,246.0,247.0,248.0,249.0,250.0,251.0,252.0,253.0,254.0,255.0,256.0,257.0,258.0,259.0,260.0,261.0,262.0,263.0,264.0,265.0,266.0,267.0,268.0,269.0,270.0,271.0,272.0,273.0,274.0,275.0,276.0,277.0,278.0,279.0,280.0,281.0,282.0,283.0,284.0,285.0,286.0,287.0,288.0,289.0,290.0,291.0,292.0,293.0,294.0,295.0,296.0,297.0,298.0,299.0,300.0],"y":[0.823804,0.823804,0.870212,0.877734,0.877734,0.879367,0.879367,0.879367,0.879367,0.880283,0.880283,0.880139,0.883284,0.883347,0.880846,0.880846,0.880958,0.880958,0.881003,0.881003,0.881003,0.888396,0.888337,0.888337,0.888449,0.888449,0.888449,0.888449,0.888256,0.888256,0.888312,0.888747,0.888747,0.888747,0.888747,0.888753,0.888744,0.888744,0.888751,0.888751,0.888751,0.888233,0.890606,0.890453,0.890453,0.890325,0.890325,0.890711,0.890711,0.890711,0.890711,0.89072,0.891639,0.891677,0.891677,0.891686,0.891686,0.892535,0.892535,0.892535,0.892867,0.892867,0.892867,0.89299,0.89299,0.892988,0.892988,0.892977,0.892977,0.892977,0.892977,0.892977,0.893027,0.893027,0.893005,0.893097,0.893097,0.893095,0.892177,0.893468,0.894992,0.895827,0.895827,0.895799,0.895799,0.895801,0.895801,0.895801,0.895801,0.895799,0.895794,0.895794,0.895794,0.895801,0.895801,0.895801,0.895801,0.895788,0.895788,0.895788,0.89599,0.895896,0.895843,0.895843,0.895767,0.895803,0.895776,0.895776,0.895733,0.895705,0.895745,0.895727,0.895727,0.895718,0.895712,0.895712,0.895707,0.895708,0.895719,0.89571,0.895651,0.895655,0.897032,0.897029,0.897035,0.897023,0.897023,0.897018,0.897018,0.897016,0.897016,0.897014,0.897014,0.897014,0.897026,0.897019,0.897019,0.897017,0.897036,0.897034,0.897034,0.897292,0.897293,0.897244,0.897244,0.897165,0.897165,0.897156,0.897156,0.897152,0.897156,0.897152,0.897152,0.89715,0.89715,0.897133,0.897136,0.897629,0.897022,0.897015,0.897214,0.897214,0.897157,0.897166,0.897155,0.897155,0.897161,0.897161,0.897156,0.897156,0.897153,0.897153,0.897151,0.897155,0.897149,0.897149,0.897149,0.897149,0.897154,0.897156,0.897156,0.897569,0.897525,0.897527,0.897527,0.897444,0.897456,0.897456,0.897422,0.897422,0.897422,0.897422,0.897429,0.897429,0.897427,0.897392,0.897392,0.897435,0.897435,0.897435,0.897435,0.897435,0.897435,0.897445,0.897445,0.897445,0.897445,0.897445,0.897445,0.897445,0.897445,0.897454,0.897454,0.897452,0.897452,0.897456,0.897471,0.897475,0.897481,0.897851,0.897851,0.897851,0.897614,0.897635,0.897635,0.897635,0.897635,0.897622,0.897622,0.897617,0.89762,0.89762,0.897633,0.897635,0.897628,0.897628,0.897628,0.897628,0.897626,0.897626,0.897656,0.897656,0.897658,0.897658,0.897658,0.897654,0.897654,0.897652,0.897652,0.897652,0.897652,0.897652,0.897615,0.897616,0.897616,0.897616,0.897622,0.897622,0.897622,0.897622,0.897622,0.897622,0.897606,0.897606,0.897605,0.897605,0.897605,0.897605,0.897605,0.897605,0.897605,0.897605,0.897601,0.897601,0.897601,0.897601,0.897599,0.897599,0.897608,0.897608,0.897608,0.897571,0.897571,0.897558,0.897674,0.897674,0.897673,0.897663,0.897672,0.897659,0.897636,0.897636,0.897641,0.897638,0.897646,0.897657,0.897657,0.897657,0.897657,0.897658],"sx":[75.6,77.16,78.72,80.28,81.83,83.39,84.95,86.51,88.07,89.63,91.19,92.75,94.31,95.87,97.43,98.99,100.55,102.11,103.67,105.23,106.79,108.35,109.91,111.47,113.02,114.58,116.14,117.7,119.26,120.82,122.38,123.94,125.5,127.06,128.62,130.18,131.74,133.3,134.86,136.42,137.98,139.54,141.1,142.66,144.21,145.77,147.33,148.89,150.45,152.01,153.57,155.13,156.69,158.25,159.81,161.37,162.93,164.49,166.05,167.61,169.17,170.73,172.29,173.84,175.4,176.96,178.52,180.08,181.64,183.2,184.76,186.32,187.88,189.44,191.0,192.56,194.12,195.68,197.24,198.8,200.36,201.92,203.48,205.03,206.59,208.15,209.71,211.27,212.83,214.39,215.95,217.51,219.07,220.63,222.19,223.75,225.31,226.87,228.43,229.99,231.55,233.11,234.67,236.22,237.78,239.34,240.9,242.46,244.02,245.58,247.14,248.7,250.26,251.82,253.38,254.94,256.5,258.06,259.62,261.18,262.74,264.3,265.86,267.41,268.97,270.53,272.09,273.65,275.21,276.77,278.33,279.89,281.45,283.01,284.57,286.13,287.69,289.25,290.81,292.37,293.93,295.49,297.04,298.6,300.16,301.72,303.28,304.84,306.4,307.96,309.52,311.08,312.64,314.2,315.76,317.32,318.88,320.44,322.0,323.56,325.12,326.68,328.23,329.79,331.35,332.91,334.47,336.03,337.59,339.15,340.71,342.27,343.83,345.39,346.95,348.51,350.07,351.63,353.19,354.75,356.31,357.87,359.42,360.98,362.54,364.1,365.66,367.22,368.78,370.34,371.9,373.46,375.02,376.58,378.14,379.7,381.26,382.82,384.38,385.94,387.5,389.06,390.61,392.17,393.73,395.29,396.85,398.41,399.97,401.53,403.09,404.65,406.21,407.77,409.33,410.89,412.45,414.01,415.57,417.13,418.69,420.25,421.8,423.36,424.92,426.48,428.04,429.6,431.16,432.72,434.28,435.84,437.4,438.96,440.52,442.08,443.64,445.2,446.76,448.32,449.88,451.43,452.99,454.55,456.11,457.67,459.23,460.79,462.35,463.91,465.47,467.03,468.59,470.15,471.71,473.27,474.83,476.39,477.95,479.51,481.07,482.62,484.18,485.74,487.3,488.86,490.42,491.98,493.54,495.1,496.66,498.22,499.78,501.34,502.9,504.46,506.02,507.58,509.14,510.7,512.26,513.81,515.37,516.93,518.49,520.05,521.61,523.17,524.73,526.29,527.85,529.41,530.97,532.53,534.09,535.65,537.21,538.77,540.33,541.89],"sy":[67.89,67.89,44.3,40.48,40.48,39.65,39.65,39.65,39.65,39.18,39.18,39.25,37.65,37.62,38.89,38.89,38.84,38.84,38.81,38.81,38.81,35.06,35.09,35.09,35.03,35.03,35.03,35.03,35.13,35.13,35.1,34.88,34.88,34.88,34.88,34.87,34.88,34.88,34.88,34.88,34.88,35.14,33.93,34.01,34.01,34.08,34.08,33.88,33.88,33.88,33.88,33.87,33.41,33.39,33.39,33.38,33.38,32.95,32.95,32.95,32.78,32.78,32.78,32.72,32.72,32.72,32.72,32.73,32.73,32.73,32.73,32.73,32.7,32.7,32.71,32.67,32.67,32.67,33.13,32.48,31.7,31.28,31.28,31.29,31.29,31.29,31.29,31.29,31.29,31.29,31.3,31.3,31.3,31.29,31.29,31.29,31.29,31.3,31.3,31.3,31.2,31.24,31.27,31.27,31.31,31.29,31.3,31.3,31.33,31.34,31.32,31.33,31.33,31.33,31.34,31.34,31.34,31.34,31.33,31.34,31.37,31.37,30.67,30.67,30.66,30.67,30.67,30.67,30.67,30.67,30.67,30.68,30.68,30.68,30.67,30.67,30.67,30.67,30.66,30.67,30.67,30.53,30.53,30.56,30.56,30.6,30.6,30.6,30.6,30.61,30.6,30.61,30.61,30.61,30.61,30.61,30.61,30.36,30.67,30.67,30.57,30.57,30.6,30.6,30.6,30.6,30.6,30.6,30.6,30.6,30.6,30.6,30.61,30.6,30.61,30.61,30.61,30.61,30.6,30.6,30.6,30.39,30.42,30.41,30.41,30.46,30.45,30.45,30.47,30.47,30.47,30.47,30.46,30.46,30.47,30.48,30.48,30.46,30.46,30.46,30.46,30.46,30.46,30.46,30.46,30.46,30.46,30.46,30.46,30.46,30.46,30.45,30.45,30.45,30.45,30.45,30.44,30.44,30.44,30.25,30.25,30.25,30.37,30.36,30.36,30.36,30.36,30.37,30.37,30.37,30.37,30.37,30.36,30.36,30.36,30.36,30.36,30.36,30.36,30.36,30.35,30.35,30.35,30.35,30.35,30.35,30.35,30.35,30.35,30.35,30.35,30.35,30.37,30.37,30.37,30.37,30.37,30.37,30.37,30.37,30.37,30.37,30.37,30.37,30.37,30.37,30.37,30.37,30.37,30.37,30.37,30.37,30.38,30.38,30.38,30.38,30.38,30.38,30.37,30.37,30.37,30.39,30.39,30.4,30.34,30.34,30.34,30.35,30.34,30.35,30.36,30.36,30.36,30.36,30.35,30.35,30.35,30.35,30.35,30.35]},{"panel":0,"label":"gradient boosting, depth-3 trees, rate 0.1","color":"var(--chart-maroon, #b6262c)","kind":"line","x":[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.0,20.0,21.0,22.0,23.0,24.0,25.0,26.0,27.0,28.0,29.0,30.0,31.0,32.0,33.0,34.0,35.0,36.0,37.0,38.0,39.0,40.0,41.0,42.0,43.0,44.0,45.0,46.0,47.0,48.0,49.0,50.0,51.0,52.0,53.0,54.0,55.0,56.0,57.0,58.0,59.0,60.0,61.0,62.0,63.0,64.0,65.0,66.0,67.0,68.0,69.0,70.0,71.0,72.0,73.0,74.0,75.0,76.0,77.0,78.0,79.0,80.0,81.0,82.0,83.0,84.0,85.0,86.0,87.0,88.0,89.0,90.0,91.0,92.0,93.0,94.0,95.0,96.0,97.0,98.0,99.0,100.0,101.0,102.0,103.0,104.0,105.0,106.0,107.0,108.0,109.0,110.0,111.0,112.0,113.0,114.0,115.0,116.0,117.0,118.0,119.0,120.0,121.0,122.0,123.0,124.0,125.0,126.0,127.0,128.0,129.0,130.0,131.0,132.0,133.0,134.0,135.0,136.0,137.0,138.0,139.0,140.0,141.0,142.0,143.0,144.0,145.0,146.0,147.0,148.0,149.0,150.0,151.0,152.0,153.0,154.0,155.0,156.0,157.0,158.0,159.0,160.0,161.0,162.0,163.0,164.0,165.0,166.0,167.0,168.0,169.0,170.0,171.0,172.0,173.0,174.0,175.0,176.0,177.0,178.0,179.0,180.0,181.0,182.0,183.0,184.0,185.0,186.0,187.0,188.0,189.0,190.0,191.0,192.0,193.0,194.0,195.0,196.0,197.0,198.0,199.0,200.0,201.0,202.0,203.0,204.0,205.0,206.0,207.0,208.0,209.0,210.0,211.0,212.0,213.0,214.0,215.0,216.0,217.0,218.0,219.0,220.0,221.0,222.0,223.0,224.0,225.0,226.0,227.0,228.0,229.0,230.0,231.0,232.0,233.0,234.0,235.0,236.0,237.0,238.0,239.0,240.0,241.0,242.0,243.0,244.0,245.0,246.0,247.0,248.0,249.0,250.0,251.0,252.0,253.0,254.0,255.0,256.0,257.0,258.0,259.0,260.0,261.0,262.0,263.0,264.0,265.0,266.0,267.0,268.0,269.0,270.0,271.0,272.0,273.0,274.0,275.0,276.0,277.0,278.0,279.0,280.0,281.0,282.0,283.0,284.0,285.0,286.0,287.0,288.0,289.0,290.0,291.0,292.0,293.0,294.0,295.0,296.0,297.0,298.0,299.0,300.0],"y":[0.881454,0.891681,0.891011,0.890997,0.890881,0.890773,0.890501,0.88997,0.890991,0.890934,0.891748,0.89111,0.891082,0.891071,0.891642,0.892762,0.892071,0.891954,0.89207,0.892317,0.892375,0.892919,0.893311,0.893592,0.893896,0.896464,0.895869,0.896685,0.896603,0.896818,0.896791,0.896677,0.896659,0.896654,0.896602,0.89663,0.896349,0.896846,0.896638,0.897228,0.89722,0.89714,0.897767,0.897624,0.897776,0.897963,0.897168,0.897768,0.897722,0.897625,0.897087,0.897309,0.897245,0.896706,0.896705,0.896761,0.896639,0.896592,0.896504,0.896731,0.896655,0.89707,0.897224,0.897263,0.897358,0.897356,0.897441,0.897308,0.897012,0.89697,0.897066,0.897056,0.897168,0.897164,0.897268,0.897195,0.897002,0.896961,0.896437,0.896329,0.896657,0.896608,0.896572,0.896466,0.896335,0.896483,0.896409,0.896453,0.896725,0.896686,0.896739,0.896755,0.896759,0.896738,0.896776,0.896602,0.896594,0.896596,0.896648,0.896487,0.896336,0.896329,0.895881,0.895836,0.895917,0.896092,0.895234,0.895271,0.895088,0.893885,0.89392,0.893842,0.893647,0.893581,0.89364,0.893569,0.893568,0.893443,0.893377,0.893305,0.893218,0.893374,0.893258,0.89304,0.892817,0.892671,0.891818,0.891804,0.891699,0.89145,0.891489,0.89177,0.891782,0.891657,0.890636,0.890563,0.890543,0.890399,0.890344,0.890272,0.890467,0.890349,0.89038,0.890463,0.890307,0.890412,0.890436,0.890366,0.890113,0.890083,0.890058,0.889895,0.889828,0.889509,0.889443,0.889343,0.889675,0.888645,0.888646,0.888653,0.88861,0.888598,0.888565,0.888476,0.888444,0.888443,0.888562,0.88851,0.888528,0.888656,0.888665,0.888493,0.888646,0.888376,0.888412,0.888245,0.88837,0.888389,0.888129,0.888166,0.888019,0.888042,0.888012,0.887985,0.887792,0.887756,0.887975,0.887815,0.887774,0.887733,0.887725,0.887732,0.888143,0.888203,0.888155,0.888171,0.88803,0.887934,0.887842,0.88767,0.887615,0.88702,0.886885,0.886675,0.886653,0.886666,0.88649,0.886498,0.886482,0.886547,0.886451,0.886609,0.88658,0.886635,0.886744,0.887003,0.886906,0.886894,0.88696,0.886981,0.886633,0.886582,0.886453,0.886501,0.885825,0.885744,0.885657,0.885321,0.884857,0.884784,0.884674,0.88469,0.884445,0.884409,0.884448,0.884504,0.88421,0.883937,0.883915,0.883637,0.883635,0.883581,0.883526,0.883505,0.883522,0.883459,0.883371,0.883425,0.883354,0.883332,0.883318,0.882859,0.882628,0.882462,0.882568,0.882519,0.882534,0.882578,0.882568,0.882632,0.882596,0.882515,0.882471,0.882372,0.882315,0.882282,0.882228,0.882182,0.882185,0.882467,0.882504,0.882462,0.88244,0.882185,0.882091,0.881735,0.881845,0.882142,0.88219,0.882453,0.882426,0.882471,0.882525,0.882519,0.882615,0.88256,0.882707,0.88271,0.882445,0.88217,0.882195,0.882301,0.88233,0.882165,0.882173,0.88214,0.882079,0.882109,0.882022,0.881884],"sx":[75.6,77.16,78.72,80.28,81.83,83.39,84.95,86.51,88.07,89.63,91.19,92.75,94.31,95.87,97.43,98.99,100.55,102.11,103.67,105.23,106.79,108.35,109.91,111.47,113.02,114.58,116.14,117.7,119.26,120.82,122.38,123.94,125.5,127.06,128.62,130.18,131.74,133.3,134.86,136.42,137.98,139.54,141.1,142.66,144.21,145.77,147.33,148.89,150.45,152.01,153.57,155.13,156.69,158.25,159.81,161.37,162.93,164.49,166.05,167.61,169.17,170.73,172.29,173.84,175.4,176.96,178.52,180.08,181.64,183.2,184.76,186.32,187.88,189.44,191.0,192.56,194.12,195.68,197.24,198.8,200.36,201.92,203.48,205.03,206.59,208.15,209.71,211.27,212.83,214.39,215.95,217.51,219.07,220.63,222.19,223.75,225.31,226.87,228.43,229.99,231.55,233.11,234.67,236.22,237.78,239.34,240.9,242.46,244.02,245.58,247.14,248.7,250.26,251.82,253.38,254.94,256.5,258.06,259.62,261.18,262.74,264.3,265.86,267.41,268.97,270.53,272.09,273.65,275.21,276.77,278.33,279.89,281.45,283.01,284.57,286.13,287.69,289.25,290.81,292.37,293.93,295.49,297.04,298.6,300.16,301.72,303.28,304.84,306.4,307.96,309.52,311.08,312.64,314.2,315.76,317.32,318.88,320.44,322.0,323.56,325.12,326.68,328.23,329.79,331.35,332.91,334.47,336.03,337.59,339.15,340.71,342.27,343.83,345.39,346.95,348.51,350.07,351.63,353.19,354.75,356.31,357.87,359.42,360.98,362.54,364.1,365.66,367.22,368.78,370.34,371.9,373.46,375.02,376.58,378.14,379.7,381.26,382.82,384.38,385.94,387.5,389.06,390.61,392.17,393.73,395.29,396.85,398.41,399.97,401.53,403.09,404.65,406.21,407.77,409.33,410.89,412.45,414.01,415.57,417.13,418.69,420.25,421.8,423.36,424.92,426.48,428.04,429.6,431.16,432.72,434.28,435.84,437.4,438.96,440.52,442.08,443.64,445.2,446.76,448.32,449.88,451.43,452.99,454.55,456.11,457.67,459.23,460.79,462.35,463.91,465.47,467.03,468.59,470.15,471.71,473.27,474.83,476.39,477.95,479.51,481.07,482.62,484.18,485.74,487.3,488.86,490.42,491.98,493.54,495.1,496.66,498.22,499.78,501.34,502.9,504.46,506.02,507.58,509.14,510.7,512.26,513.81,515.37,516.93,518.49,520.05,521.61,523.17,524.73,526.29,527.85,529.41,530.97,532.53,534.09,535.65,537.21,538.77,540.33,541.89],"sy":[38.58,33.39,33.73,33.73,33.79,33.85,33.99,34.26,33.74,33.77,33.35,33.68,33.69,33.7,33.41,32.84,33.19,33.25,33.19,33.06,33.03,32.76,32.56,32.41,32.26,30.95,31.26,30.84,30.88,30.78,30.79,30.85,30.86,30.86,30.88,30.87,31.01,30.76,30.87,30.57,30.57,30.61,30.29,30.36,30.29,30.19,30.6,30.29,30.32,30.36,30.64,30.53,30.56,30.83,30.83,30.8,30.87,30.89,30.93,30.82,30.86,30.65,30.57,30.55,30.5,30.5,30.46,30.53,30.68,30.7,30.65,30.65,30.6,30.6,30.55,30.58,30.68,30.7,30.97,31.02,30.86,30.88,30.9,30.95,31.02,30.95,30.98,30.96,30.82,30.84,30.81,30.81,30.8,30.82,30.8,30.88,30.89,30.89,30.86,30.94,31.02,31.02,31.25,31.27,31.23,31.14,31.58,31.56,31.65,32.27,32.25,32.29,32.39,32.42,32.39,32.43,32.43,32.49,32.52,32.56,32.6,32.53,32.58,32.7,32.81,32.88,33.32,33.32,33.38,33.5,33.48,33.34,33.33,33.4,33.92,33.95,33.96,34.04,34.07,34.1,34.0,34.06,34.05,34.01,34.08,34.03,34.02,34.05,34.18,34.2,34.21,34.29,34.33,34.49,34.52,34.57,34.41,34.93,34.93,34.93,34.95,34.95,34.97,35.01,35.03,35.03,34.97,35.0,34.99,34.92,34.92,35.01,34.93,35.07,35.05,35.13,35.07,35.06,35.19,35.17,35.25,35.24,35.25,35.26,35.36,35.38,35.27,35.35,35.37,35.39,35.4,35.39,35.18,35.15,35.18,35.17,35.24,35.29,35.34,35.42,35.45,35.76,35.82,35.93,35.94,35.93,36.02,36.02,36.03,36.0,36.04,35.96,35.98,35.95,35.9,35.76,35.81,35.82,35.79,35.77,35.95,35.98,36.04,36.02,36.36,36.4,36.45,36.62,36.85,36.89,36.95,36.94,37.06,37.08,37.06,37.03,37.18,37.32,37.33,37.47,37.48,37.5,37.53,37.54,37.53,37.57,37.61,37.58,37.62,37.63,37.64,37.87,37.99,38.07,38.02,38.04,38.04,38.01,38.02,37.99,38.0,38.05,38.07,38.12,38.15,38.16,38.19,38.21,38.21,38.07,38.05,38.07,38.08,38.21,38.26,38.44,38.39,38.23,38.21,38.08,38.09,38.07,38.04,38.04,37.99,38.02,37.95,37.95,38.08,38.22,38.21,38.15,38.14,38.22,38.22,38.24,38.27,38.25,38.3,38.37]},{"panel":0,"label":"gradient boosting, depth-3 trees, rate 1.0","color":"#e0676b","kind":"line","x":[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0,16.0,17.0,18.0,19.0,20.0,21.0,22.0,23.0,24.0,25.0,26.0,27.0,28.0,29.0,30.0,31.0,32.0,33.0,34.0,35.0,36.0,37.0,38.0,39.0,40.0,41.0,42.0,43.0,44.0,45.0,46.0,47.0,48.0,49.0,50.0,51.0,52.0,53.0,54.0,55.0,56.0,57.0,58.0,59.0,60.0,61.0,62.0,63.0,64.0,65.0,66.0,67.0,68.0,69.0,70.0,71.0,72.0,73.0,74.0,75.0,76.0,77.0,78.0,79.0,80.0,81.0,82.0,83.0,84.0,85.0,86.0,87.0,88.0,89.0,90.0,91.0,92.0,93.0,94.0,95.0,96.0,97.0,98.0,99.0,100.0,101.0,102.0,103.0,104.0,105.0,106.0,107.0,108.0,109.0,110.0,111.0,112.0,113.0,114.0,115.0,116.0,117.0,118.0,119.0,120.0,121.0,122.0,123.0,124.0,125.0,126.0,127.0,128.0,129.0,130.0,131.0,132.0,133.0,134.0,135.0,136.0,137.0,138.0,139.0,140.0,141.0,142.0,143.0,144.0,145.0,146.0,147.0,148.0,149.0,150.0,151.0,152.0,153.0,154.0,155.0,156.0,157.0,158.0,159.0,160.0,161.0,162.0,163.0,164.0,165.0,166.0,167.0,168.0,169.0,170.0,171.0,172.0,173.0,174.0,175.0,176.0,177.0,178.0,179.0,180.0,181.0,182.0,183.0,184.0,185.0,186.0,187.0,188.0,189.0,190.0,191.0,192.0,193.0,194.0,195.0,196.0,197.0,198.0,199.0,200.0,201.0,202.0,203.0,204.0,205.0,206.0,207.0,208.0,209.0,210.0,211.0,212.0,213.0,214.0,215.0,216.0,217.0,218.0,219.0,220.0,221.0,222.0,223.0,224.0,225.0,226.0,227.0,228.0,229.0,230.0,231.0,232.0,233.0,234.0,235.0,236.0,237.0,238.0,239.0,240.0,241.0,242.0,243.0,244.0,245.0,246.0,247.0,248.0,249.0,250.0,251.0,252.0,253.0,254.0,255.0,256.0,257.0,258.0,259.0,260.0,261.0,262.0,263.0,264.0,265.0,266.0,267.0,268.0,269.0,270.0,271.0,272.0,273.0,274.0,275.0,276.0,277.0,278.0,279.0,280.0,281.0,282.0,283.0,284.0,285.0,286.0,287.0,288.0,289.0,290.0,291.0,292.0,293.0,294.0,295.0,296.0,297.0,298.0,299.0,300.0],"y":[0.881454,0.888061,0.88832,0.888802,0.879582,0.878412,0.879726,0.877899,0.875882,0.873849,0.87374,0.876185,0.873216,0.869061,0.869096,0.869237,0.86613,0.862222,0.863077,0.864271,0.864663,0.85912,0.859812,0.859013,0.857686,0.861727,0.862153,0.86387,0.859288,0.851935,0.858013,0.85893,0.859488,0.856264,0.8573,0.853771,0.854041,0.852014,0.852592,0.855859,0.858211,0.859002,0.860824,0.858809,0.859479,0.857055,0.85743,0.857689,0.857378,0.8535,0.852514,0.853107,0.852919,0.852078,0.852076,0.852989,0.849593,0.85025,0.848567,0.847752,0.848568,0.848312,0.849805,0.849648,0.848133,0.847781,0.847791,0.846182,0.846273,0.847895,0.847389,0.848193,0.84801,0.848901,0.847852,0.846712,0.846948,0.842574,0.843397,0.844889,0.843977,0.843599,0.844668,0.842732,0.842958,0.841958,0.843091,0.84234,0.843218,0.843853,0.841593,0.842416,0.842438,0.842001,0.842052,0.841486,0.841861,0.8424,0.842133,0.841551,0.840888,0.839285,0.840588,0.839127,0.840967,0.841904,0.843304,0.843675,0.842018,0.842283,0.841987,0.841541,0.842531,0.839967,0.840375,0.838841,0.840093,0.840457,0.838959,0.838043,0.839217,0.840011,0.840621,0.840791,0.840209,0.83976,0.840204,0.839318,0.83913,0.840226,0.839928,0.840592,0.839449,0.839195,0.840205,0.839839,0.839822,0.839757,0.83973,0.839874,0.840531,0.839668,0.840204,0.84002,0.84035,0.840229,0.839982,0.839521,0.839119,0.838593,0.840204,0.840138,0.840595,0.840496,0.840612,0.841893,0.84171,0.841472,0.843752,0.843719,0.843671,0.843931,0.844956,0.845375,0.846298,0.845212,0.84574,0.845693,0.845655,0.846161,0.845041,0.845284,0.84445,0.844568,0.844974,0.843434,0.843493,0.843747,0.843922,0.844095,0.843216,0.842611,0.842566,0.842941,0.843245,0.843312,0.842839,0.843392,0.842942,0.843405,0.842363,0.842429,0.842522,0.842076,0.842088,0.842548,0.842894,0.842421,0.842349,0.841195,0.841341,0.841592,0.842467,0.842377,0.842159,0.841932,0.841836,0.841437,0.842884,0.843251,0.84253,0.842796,0.84335,0.843929,0.844791,0.844392,0.844246,0.84338,0.843382,0.843719,0.843186,0.843325,0.841728,0.841927,0.84317,0.842439,0.842576,0.842382,0.839921,0.840583,0.840124,0.839738,0.839549,0.839572,0.839888,0.839475,0.839892,0.839321,0.839457,0.839317,0.838836,0.839022,0.839585,0.83913,0.838563,0.838367,0.838256,0.838649,0.838547,0.839016,0.83988,0.839577,0.839923,0.839666,0.839671,0.840067,0.840077,0.84041,0.839531,0.838745,0.838245,0.838332,0.838001,0.838423,0.839272,0.839118,0.839126,0.839009,0.839928,0.839565,0.839405,0.839985,0.839511,0.83931,0.839692,0.839794,0.840033,0.839976,0.839797,0.839942,0.840174,0.839669,0.839377,0.839426,0.83931,0.839181,0.839619,0.839387,0.839664,0.83923,0.838733,0.839385,0.83964,0.839648,0.838484,0.839276,0.839176,0.839246,0.839909,0.839065],"sx":[75.6,77.16,78.72,80.28,81.83,83.39,84.95,86.51,88.07,89.63,91.19,92.75,94.31,95.87,97.43,98.99,100.55,102.11,103.67,105.23,106.79,108.35,109.91,111.47,113.02,114.58,116.14,117.7,119.26,120.82,122.38,123.94,125.5,127.06,128.62,130.18,131.74,133.3,134.86,136.42,137.98,139.54,141.1,142.66,144.21,145.77,147.33,148.89,150.45,152.01,153.57,155.13,156.69,158.25,159.81,161.37,162.93,164.49,166.05,167.61,169.17,170.73,172.29,173.84,175.4,176.96,178.52,180.08,181.64,183.2,184.76,186.32,187.88,189.44,191.0,192.56,194.12,195.68,197.24,198.8,200.36,201.92,203.48,205.03,206.59,208.15,209.71,211.27,212.83,214.39,215.95,217.51,219.07,220.63,222.19,223.75,225.31,226.87,228.43,229.99,231.55,233.11,234.67,236.22,237.78,239.34,240.9,242.46,244.02,245.58,247.14,248.7,250.26,251.82,253.38,254.94,256.5,258.06,259.62,261.18,262.74,264.3,265.86,267.41,268.97,270.53,272.09,273.65,275.21,276.77,278.33,279.89,281.45,283.01,284.57,286.13,287.69,289.25,290.81,292.37,293.93,295.49,297.04,298.6,300.16,301.72,303.28,304.84,306.4,307.96,309.52,311.08,312.64,314.2,315.76,317.32,318.88,320.44,322.0,323.56,325.12,326.68,328.23,329.79,331.35,332.91,334.47,336.03,337.59,339.15,340.71,342.27,343.83,345.39,346.95,348.51,350.07,351.63,353.19,354.75,356.31,357.87,359.42,360.98,362.54,364.1,365.66,367.22,368.78,370.34,371.9,373.46,375.02,376.58,378.14,379.7,381.26,382.82,384.38,385.94,387.5,389.06,390.61,392.17,393.73,395.29,396.85,398.41,399.97,401.53,403.09,404.65,406.21,407.77,409.33,410.89,412.45,414.01,415.57,417.13,418.69,420.25,421.8,423.36,424.92,426.48,428.04,429.6,431.16,432.72,434.28,435.84,437.4,438.96,440.52,442.08,443.64,445.2,446.76,448.32,449.88,451.43,452.99,454.55,456.11,457.67,459.23,460.79,462.35,463.91,465.47,467.03,468.59,470.15,471.71,473.27,474.83,476.39,477.95,479.51,481.07,482.62,484.18,485.74,487.3,488.86,490.42,491.98,493.54,495.1,496.66,498.22,499.78,501.34,502.9,504.46,506.02,507.58,509.14,510.7,512.26,513.81,515.37,516.93,518.49,520.05,521.61,523.17,524.73,526.29,527.85,529.41,530.97,532.53,534.09,535.65,537.21,538.77,540.33,541.89],"sy":[38.58,35.23,35.09,34.85,39.54,40.13,39.46,40.39,41.42,42.45,42.51,41.26,42.77,44.88,44.87,44.79,46.37,48.36,47.93,47.32,47.12,49.94,49.59,49.99,50.67,48.61,48.4,47.52,49.85,53.59,50.5,50.03,49.75,51.39,50.86,52.66,52.52,53.55,53.25,51.59,50.4,50.0,49.07,50.1,49.75,50.99,50.8,50.66,50.82,52.79,53.29,52.99,53.09,53.52,53.52,53.05,54.78,54.45,55.3,55.71,55.3,55.43,54.67,54.75,55.52,55.7,55.7,56.51,56.47,55.64,55.9,55.49,55.58,55.13,55.66,56.24,56.12,58.35,57.93,57.17,57.63,57.83,57.28,58.27,58.15,58.66,58.08,58.47,58.02,57.7,58.85,58.43,58.42,58.64,58.61,58.9,58.71,58.44,58.57,58.87,59.2,60.02,59.36,60.1,59.16,58.69,57.98,57.79,58.63,58.5,58.65,58.87,58.37,59.67,59.46,60.24,59.61,59.42,60.18,60.65,60.05,59.65,59.34,59.25,59.55,59.78,59.55,60.0,60.1,59.54,59.69,59.35,59.94,60.06,59.55,59.74,59.75,59.78,59.79,59.72,59.39,59.82,59.55,59.65,59.48,59.54,59.66,59.9,60.1,60.37,59.55,59.59,59.35,59.4,59.34,58.69,58.79,58.91,57.75,57.77,57.79,57.66,57.14,56.92,56.45,57.01,56.74,56.76,56.78,56.52,57.09,56.97,57.39,57.33,57.13,57.91,57.88,57.75,57.66,57.57,58.02,58.33,58.35,58.16,58.01,57.97,58.21,57.93,58.16,57.92,58.45,58.42,58.37,58.6,58.59,58.36,58.18,58.42,58.46,59.05,58.97,58.85,58.4,58.45,58.56,58.67,58.72,58.93,58.19,58.0,58.37,58.23,57.95,57.66,57.22,57.42,57.5,57.94,57.94,57.77,58.04,57.97,58.78,58.68,58.04,58.42,58.35,58.44,59.7,59.36,59.59,59.79,59.88,59.87,59.71,59.92,59.71,60.0,59.93,60.0,60.25,60.15,59.87,60.1,60.39,60.49,60.54,60.34,60.39,60.16,59.72,59.87,59.69,59.83,59.82,59.62,59.62,59.45,59.89,60.29,60.55,60.5,60.67,60.46,60.03,60.1,60.1,60.16,59.69,59.88,59.96,59.66,59.9,60.01,59.81,59.76,59.64,59.67,59.76,59.68,59.57,59.82,59.97,59.95,60.01,60.07,59.85,59.97,59.83,60.05,60.3,59.97,59.84,59.83,60.43,60.02,60.07,60.04,59.7,60.13]},{"panel":0,"label":"random forest (0.891)","color":"var(--chart-grey, #a3a19c)","kind":"line","x":[0.0,1.0],"y":[0.891416,0.891416],"sx":[74.04,75.6],"sy":[33.52,33.52]}]} 2026-10-31T01:54:59.762962 image/svg+xml Matplotlib v3.11.2, https://matplotlib.org/ 0 50 100 150 200 250 300 Number of trees in the model 0.50 0.55 0.60 0.65 0.70 0.75 0.80 0.85 0.90 Test AUC, 2022–2023 (0.5 = coin flip, 1 = perfect) Test score as trees are added (dot = round chosen on validation) AdaBoost, stumps gradient boosting, depth-3 trees, rate 0.1 gradient boosting, depth-3 trees, rate 1.0 random forest (0.891)
Figure 1. Test AUC against number of trees for three boosted models

For Figure 1 the models trained on 2020 to 2022 (3,680 rows) and kept 2023 (1,250 rows) aside as a validation set, after the fitting rows in time, never mixed in. The number of trees to use is chosen on that validation set, never on the test set, and the dot on each line marks the round it picked. Test AUC on 2024 to 2025 (Table 5):

Table 5. Test AUC by number of trees, and the count chosen on validation
Model10 trees50 trees300 treesChosen on validationTest AUC there
AdaBoost, stumps0.8800.8910.898810.895
Gradient boosting, depth-3 trees, rate 0.10.8910.8980.88230.891
Gradient boosting, depth-3 trees, rate 1.00.8740.8540.83930.888
Random forest (last post)0.891

Two lessons from Figure 1:

  • Too high a learning rate overfits fast. At rate 1.0 each tree over-corrects. The score peaks after a handful of trees, then falls to 0.85 by fifty and 0.84 by three hundred as the model fits noise; the validation set stops it at 3.
  • Boosting can overfit by adding trees, unlike a random forest. Even at rate 0.1 the score drifts down from 0.898 at fifty trees to 0.882 at 300. In practice you use early stopping: watch a validation score and stop adding trees when it stops improving, which is what the dots show. Here the 2023 validation year stopped rate 0.1 at three trees, well before the test curve’s best (0.898 at fifty); the validation year is not the test years, and that gap is the price of choosing without looking at the test set.

On this data the three finish within 0.004 of each other: AdaBoost 0.895, gradient boosting 0.891, random forest 0.891, a gap small enough to be noise. With few features, overlapping rows and noisy labels, the model that is harder to overfit is the safer bet, and ISLP notes the same difference: random forests do not overfit as trees are added, while boosting can.

The code

The worked example by hand, then both kinds of boosting on made-up data, so it runs as pasted (pip install numpy scikit-learn). X holds two features, this month’s volatility and return; y the answer, 1 if a stress month followed. The first 3,000 rows train, the last 1,000 test.

import numpy as np
import sklearn
from sklearn.ensemble import AdaBoostClassifier, GradientBoostingClassifier
from sklearn.metrics import roc_auc_score
from sklearn.tree import DecisionTreeClassifier

# 1. One AdaBoost round by hand: ten rows, weight 0.1 each, three of them wrong
w = np.full(10, 0.1)
wrong = np.array([True] * 3 + [False] * 7)
eps = w[wrong].sum()                                  # weighted error: 0.3
alpha = 0.5 * np.log((1 - eps) / eps)                 # the model's vote: 0.4236
w = w * np.where(wrong, np.exp(alpha), np.exp(-alpha))
w = w / w.sum()                                       # back to a total of 1
print(f"error {eps:.1f}, vote {alpha:.4f}, wrong rows now {w[0]:.4f}, right rows {w[-1]:.4f}, "
      f"wrong rows' share {w[wrong].sum():.1f}")

# 2. Boosting on made-up data: two features, stress is rare
rng = np.random.default_rng(0)
n = 4000
X = np.c_[rng.uniform(5, 50, n), rng.normal(0, 5, n)]          # [volatility, return]
y = ((X[:, 0] / 50 - X[:, 1] / 40 + rng.normal(0, 0.2, n)) > 0.8).astype(int)
X_train, X_test, y_train, y_test = X[:3000], X[3000:], y[:3000], y[3000:]

ada = AdaBoostClassifier(DecisionTreeClassifier(max_depth=1), n_estimators=100, random_state=0)
ada.fit(X_train, y_train)                             # each round: a stump on reweighted rows
print("AdaBoost: first three errors", np.round(ada.estimator_errors_[:3], 3),
      "and weights", np.round(ada.estimator_weights_[:3], 3))
print("AdaBoost test AUC", round(roc_auc_score(y_test, ada.predict_proba(X_test)[:, 1]), 3))

gb = GradientBoostingClassifier(n_estimators=300, learning_rate=0.1, max_depth=3,
                                validation_fraction=0.1, n_iter_no_change=20, random_state=0)
gb.fit(X_train, y_train)                              # stops when the held-back 10% stops improving
print("gradient boosting used", gb.n_estimators_, "of 300 trees, test AUC",
      round(roc_auc_score(y_test, gb.predict_proba(X_test)[:, 1]), 3))
print("scikit-learn", sklearn.__version__)

It prints the worked example’s numbers: error 0.3, vote 0.4236, the wrong rows at 0.1667, the right ones at 0.0714, and the wrong rows’ share at exactly 0.5. Then the first three AdaBoost rounds, each with its weighted error and scikit-learn’s weight. Check one: an error of 0.192 gives ln⁡(0.808/0.192)=1.437\ln(0.808 / 0.192) = 1.437, the SAMME weight without the 12\tfrac{1}{2}. Then the test AUCs, about 0.90 for both, and the number of trees early stopping kept (about 77 of 300). The last line prints the scikit-learn version, 1.9 when this was written.

For large datasets, scikit-learn’s HistGradientBoostingClassifier, XGBoost and LightGBM are much faster versions of the same idea.

The script behind the real numbers

The tables and the chart come from examples/boosting/boosting.py, which runs on the blog’s five tickers. To run it yourself, clone the examples repo: its README has a three-command Docker setup, or run uv run boosting/boosting.py.

What the big libraries add

  • Speed and extras. XGBoost and LightGBM add penalties on tree size (regularisation), histogram-based splits (faster, by bucketing each feature’s values) and built-in handling of missing values.
  • Monotonic constraints, for example “predicted risk can only go up as a borrower’s debt goes up”, so the model can’t contradict a rule everyone agrees on.
  • Explanations. SHAP values split one prediction into a contribution from each feature.
  • The trade-off: more settings to tune than a random forest, and easier to overfit.

Summary

Table 6 is the post in six lines.

Table 6. Boosting in six lines
IdeaFormula / ruleRemember it as
Boostingweak models in sequence, each fixing the lasta team where each member covers the gaps
AdaBoost voteα=12ln⁡((1−ε)/ε)\key{\alpha} = \tfrac{1}{2}\ln\big((1-\risk{\varepsilon}) / \risk{\varepsilon}\big)lower error, bigger say
AdaBoost updatewrong ×eα\times \bad{e^{\key{\alpha}}}, right ×e−α\times \good{e^{-\key{\alpha}}}, normalisemistakes end up with half the weight
scikit-learn AdaBoostα=ln⁡((1−ε)/ε)\key{\alpha} = \ln\big((1-\risk{\varepsilon}) / \risk{\varepsilon}\big) (SAMME)twice the textbook value, same ranking
Gradient boostingf^←f^+λf^b\hat{f} \leftarrow \hat{f} + \key{\lambda} \hat{f}^b, f^b\hat{f}^b fits the residualskeep fitting what’s left over
Main dangertoo many trees or too high a rateuse a small rate and early stopping

That is the last model in the Machine Learning Series 1. One post remains: putting all of them side by side.

References

Tagged machine-learning, ensembles, finance, volatility← Home