Tree-Based Algorithms

Lesson 1

Decision Trees

Grow a classifier by asking the most informative question first

A decision tree is the simplest model that still feels like reasoning. It asks a sequence of yes or no questions about the features, "is petal length below 2.5 cm?", "is income above 60k?", and each answer walks you down to a leaf that holds a prediction. No weights, no gradient descent, no calculus at inference time. Just a nested set of if statements the model discovered on its own.

That simplicity is not a toy. The ensembles built from trees, random forests and gradient boosting, still win the majority of Kaggle competitions on tabular data and quietly power fraud detection, credit scoring, and ranking systems in production. Before you can understand those ensembles, you have to understand the single tree they are made of. This lesson is that tree: how it picks a split, the two classic recipes for scoring a split (Gini and entropy), the knobs that stop it from memorizing the training set, and the failure modes a deep-learning engineer needs to name in an interview.


The one question every tree keeps asking

Growing a tree is a single operation applied over and over: take a group of samples and split it into two groups that are each more "pure" than the parent. A pure group is one where almost every sample shares the same label, because then the tree can confidently predict that label and stop.

So the whole algorithm reduces to two questions:

  1. How do we measure how mixed a group of labels is? (impurity)
  2. How do we compare candidate splits so we can pick the best one? (information gain)

Answer those two and you have built a decision tree.

1. Impurity

A number that is high when a node is a 50/50 mess and 0 when it is one pure class.

2. Split & score

Try a feature and a threshold; measure how much impurity the split removes.

3. Recurse

Keep the best split, then repeat inside each child until a stopping rule fires.

Play with the split step directly. In the builder below, pick a feature and drag the threshold. Each cut carves the plane into two axis-aligned regions, and the readout shows the impurity of each region and the information gain the cut buys you. Press Find best split to let the greedy search scan every candidate and land on the largest gain, exactly what the algorithm does at each node.

🌳 Decision Tree Builder

Click a region, pick an axis, drag the split line, then Apply — greedy impurity cuts carve the plane into rectangles.

Split axis
class Aclass Bcandidate split
Accuracy
50%
Leaves
1
Tree Gini
0.500
Candidate: x < 0.50 on a node of 60 pts (Gini 0.500)
Left (x < thr)
n=25 · G=0.147
A 23 / B 2
Right (x ≥ thr)
n=35 · G=0.320
A 7 / B 28
Information gain+0.252
Tree
B · 60G 0.50

Each split is chosen to maximize information gain = drop in impurity. Recursively splitting leaves partitions feature space into axis-aligned rectangles, each predicting its majority class.

Notice three things while you play. First, the split lines are always axis-aligned: a tree can only ask about one feature at a time, so its regions are rectangles, never diagonals. Second, the best cut is the one that leaves each side as pure as possible. Third, once you split, you can split again inside a region, and that recursion is what lets a shallow-looking tree carve out surprisingly complex shapes.


Measuring impurity: Gini and entropy

We need a function that takes the class proportions in a node and returns a single "how mixed is this" score. Two functions dominate, and they agree on the essentials.

Let a node hold samples from CC classes, and let pip_i be the fraction of the node that belongs to class ii.

Gini impurity is the probability that you misclassify a random sample if you label it by drawing from the node's own class distribution:

G=1i=1Cpi2G = 1 - \sum_{i=1}^{C} p_i^{\,2}

Entropy is the average number of bits needed to encode the class of a sample, borrowed straight from information theory:

H=i=1Cpilog2piH = -\sum_{i=1}^{C} p_i \log_2 p_i

For a two-class node with positive fraction pp, these become G=2p(1p)G = 2p(1-p) and H=plog2p(1p)log2(1p)H = -p\log_2 p - (1-p)\log_2(1-p). Both share the same shape: zero at a pure node (p=0p = 0 or p=1p = 1) and maximum at a perfect 50/50 mix. Gini tops out at 0.50.5; entropy tops out at 11 bit. Drag the mix below and watch both rise and fall together.

⚖️ Impurity Meter — Gini vs. Entropy

Drag the mix. Both impurity measures peak at a 50/50 split and fall to 0 when the node is pure.

A node holding 24 samples
Positive proportion p = 0.50
● positive 12
● negative 12
0.000.250.500.751.00p = 0p = 0.5p = 1impurity
Gini
0.500
1 − p² − (1−p)² · max 0.5
Entropy
1.000
−Σ pᵢ log₂ pᵢ · max 1.0

Maximally mixed (≈50/50). Both measures are at their peak — this node is the most "confused".

The two curves almost never disagree about which split is better, so the choice between them is rarely about accuracy. Gini is slightly cheaper (no logarithm) and is scikit-learn's default; entropy is the one from classic information theory and the original ID3 algorithm. Treat them as two dialects of the same idea: lower is purer.


Information gain: scoring a split

Impurity scores a single node. To score a split, we compare the parent's impurity against the combined impurity of its children, weighted by how many samples fall into each:

IG=H(parent)knknH(childk)\text{IG} = H(\text{parent}) - \sum_{k} \frac{n_k}{n}\, H(\text{child}_k)

Here nn is the number of samples at the parent, nkn_k the number in child kk, and HH can be entropy (for information gain proper) or Gini (then it is usually called the "Gini decrease"). The weighting matters: a split that produces one tiny pure child and one huge messy child barely helps, and the nk/nn_k/n factors say so. The greedy tree evaluates this quantity for every feature and every candidate threshold, then keeps the split with the largest gain.

One split, computed by hand

Take a node of 10 samples: 6 positive (churned) and 4 negative (stayed). We test the split "tenure 12\le 12 months?" which sends 5 samples left and 5 right.

NodeSamplesPositiveNegativeComposition
Parent106460% / 40%
Left (tenure ≤ 12)51420% / 80%
Right (tenure > 12)550100% / 0%

Step 1, parent impurity. With p=0.6p = 0.6:

Gparent=1(0.62+0.42)=10.52=0.48G_{\text{parent}} = 1 - (0.6^2 + 0.4^2) = 1 - 0.52 = 0.48 Hparent=(0.6log20.6+0.4log20.4)=0.971 bitsH_{\text{parent}} = -(0.6\log_2 0.6 + 0.4\log_2 0.4) = 0.971 \text{ bits}

Step 2, child impurities. The left child is 20/8020/80 and the right child is pure:

Gleft=1(0.22+0.82)=0.32,Gright=1(12+02)=0G_{\text{left}} = 1 - (0.2^2 + 0.8^2) = 0.32, \qquad G_{\text{right}} = 1 - (1^2 + 0^2) = 0 Hleft=(0.2log20.2+0.8log20.8)=0.722,Hright=0H_{\text{left}} = -(0.2\log_2 0.2 + 0.8\log_2 0.8) = 0.722, \qquad H_{\text{right}} = 0

Step 3, weight and subtract. Each child holds half the samples, so the weights are 5/10=0.55/10 = 0.5:

Gsplit=0.5(0.32)+0.5(0)=0.16    Gini gain=0.480.16=0.32G_{\text{split}} = 0.5(0.32) + 0.5(0) = 0.16 \;\Rightarrow\; \text{Gini gain} = 0.48 - 0.16 = 0.32 Hsplit=0.5(0.722)+0.5(0)=0.361    Info gain=0.9710.361=0.610 bitsH_{\text{split}} = 0.5(0.722) + 0.5(0) = 0.361 \;\Rightarrow\; \text{Info gain} = 0.971 - 0.361 = 0.610 \text{ bits}

Both scores agree the split is excellent: it drops Gini by 0.320.32 and buys 0.610.61 bits of information, largely because it isolates a perfectly pure right child. This is the exact arithmetic the builder above runs for every candidate cut. You can reproduce it in NumPy in a few lines:

Python
First run loads the Python runtime (~10 MB) — takes ~5–10 seconds. Subsequent runs are instant.

CART vs ID3: two recipes, one idea

The measurement and the search combine into named algorithms. You will hear two in interviews.

CART

Classification and Regression Trees

  • Impurity: Gini by default.
  • Splits are strictly binary (two children per node).
  • Handles numeric features via thresholds; does regression too (splits on variance reduction).
  • The algorithm behind scikit-learn's tree.

ID3 / C4.5

Iterative Dichotomiser

  • Impurity: entropy, split score is information gain.
  • Original ID3 makes one branch per category (multi-way splits).
  • Classic teaching algorithm; C4.5 is its successor (gain ratio, pruning).
  • Foundational, but production tools use CART-style binary trees.

The important takeaway is that they differ in the impurity function and the branching style, not in the core loop. Both are greedy: at each node they pick the single best split available right now and never look back.

Because a tree can only cut on one axis at a time, the boundary it learns is a staircase of rectangles. That is worth seeing directly. The visual below shows how a set of axis-aligned decisions partitions a 2D feature space, the same rectangular carving the builder produced, now on a denser problem.

Two features → the boundary is a line
boundary angle45°
horizontaldiagonalvertical

The knobs: hyperparameters that stop overfitting

Left alone, a tree will keep splitting until every leaf is pure, which usually means one training point per leaf. That tree has memorized the training set and will generalize terribly. The cure is to constrain it. These are the hyperparameters a deep-learning engineer reaches for most:

max_depth

The hard cap on how many questions deep any path can go. Small depth = a coarse, high-bias tree; large depth = a fine, high-variance tree that can carve out one rectangle per point. The single most important knob.

min_samples_leaf / min_samples_split

Refuse to create a leaf (or split a node) unless it holds at least this many samples. Forces every prediction to rest on a meaningful chunk of data, not a single lucky point.

ccp_alpha (cost-complexity pruning)

Grow the tree fully, then prune back branches whose accuracy gain does not justify their added complexity. It minimizes impurity + alpha x (number of leaves): a larger alpha means a smaller, simpler tree.

The first two are pre-pruning (stop early); ccp_alpha is post-pruning (grow, then cut back). Post-pruning often generalizes better because a split that looks weak on its own can enable a strong split beneath it, and pre-pruning would never discover it.

Watch overfitting appear as you unleash depth. The playground below sweeps max_depth on a noisy make_moons problem and prints train and test accuracy side by side. Train accuracy climbs monotonically toward 1.0; test accuracy peaks and then sags. That gap is the tree memorizing noise.

Python
First run loads the Python runtime (~10 MB) — takes ~5–10 seconds. Subsequent runs are instant.

See the whole thing run: fit, score, and read the tree

Here is a full decision tree end to end in scikit-learn: fit on the two-moons dataset, print train and test accuracy, then plot both the axis-aligned decision regions and the tree itself with plot_tree. Read the tree from the root: each box shows the split test, the Gini impurity, the sample count, and the class distribution. Change max_depth and rerun to watch the regions get jagged.

Python
First run loads the Python runtime (~10 MB) — takes ~5–10 seconds. Subsequent runs are instant.

Where a single tree breaks

Trees are interpretable and fast, but a lone tree has real weaknesses. Naming them is standard interview fare, and every one of them motivates the ensembles later in this section.

Greedy, not optimal

Each split is chosen for immediate gain. A locally weak split might have enabled a much stronger one below it, but the greedy search never explores that path. Finding the globally optimal tree is NP-hard.

High variance / instability

Change a few training points and the top split can flip, reshaping the entire tree below it. This sensitivity is exactly what bagging and random forests are built to average away.

Overfitting

Unconstrained, a tree drives training impurity to zero by memorizing points. Depth limits, leaf minimums, and pruning are the only things standing between it and a lookup table.

Bias to high-cardinality features

A feature with many distinct values (an ID, a zip code) offers many candidate thresholds and can score a high gain by chance. Impurity-based splitting is biased toward such features, which is why gain ratio and permutation importance exist.

Check your understanding

1 / 4

A parent node has Gini 0.50. Which candidate split is best?


Interview readiness

Q1ConceptualAmazonMeta

Why does a decision tree overfit, and what are three ways to prevent it?

Q2MathGoogle

A node has 8 samples: 4 positive and 4 negative. A split sends {3 positive, 1 negative} left and {1 positive, 3 negative} right. Compute the Gini information gain.

Test your understanding

Prof is ready

Prof will ask you questions about Decision trees: impurity, splitting, and the CART and ID3 algorithms — not explain it. You'll be surprised what you don't know until you have to say it.

Finished this lesson?

Read through the lesson first (0/20s).