How a tree chooses a split
A decision tree tries every possible question, scores how cleanly each one sorts the labels, and keeps the question with the purest result — here is that scoring, by hand.
- 7 min read
- 3 reading levels
- Published
Read these first
On this page 5
One lesson, three depths. Pick the one that fits you today — you can switch any time.
Beginner — No maths. Plain English.
A tree chooses a split by trying every possible question and keeping the one that sorts the labels most cleanly.
Think of sorting a mixed basket of apples and oranges using a weighing scale. You could ask "is it heavier than 120 grams?" or "heavier than 140?". Each question splits the basket into two piles. A good question makes each pile nearly one fruit; a lazy question leaves both piles mixed.
A decision tree plays this game with brute force. It tries every question the data allows and measures the mess left in each pair of piles.
Why it exists
The tree needs a number for "how mixed is this pile" — otherwise it cannot compare questions. That number is called impurity.
The common recipe is Gini impurity: a pile of all apples scores zero — perfectly pure. A fifty-fifty pile scores the maximum. The tree scores a question by the impurity left over, averaged across both piles, giving the bigger pile more say.
One question rarely finishes the job. So the tree asks the best question, then repeats the whole search inside each pile, and again inside those — which is how a tree grows.
How it works
basket: 4 oranges, 4 apples (very mixed)
ask "weight > 141g?"
├── lighter pile: ○○○○● almost pure — one small apple slipped in
└── heavier pile: ●●● perfectly pure
ask "weight > 127g?"
├── lighter pile: ○○● mixed
└── heavier pile: ○●●●● mixed — a worse question
the tree keeps "weight > 141g" and moves onA real example you have seen
Loan approval screens work this way: "income above X? → then, EMI above Y?". Triage at a clinic — fever above 102? breathing difficulty? — follows the same sorted-questions shape. That familiar shape is why trees are the model businesses accept without argument: every split is a readable question.
Remember this
- The tree tries every candidate question and keeps the cleanest split.
- "Clean" is measured by impurity — zero for a pure pile, maximum for a fifty-fifty mix.
- Trees grow by repeating this greedy search inside each new pile.
What to learn next
- Pruning a decision tree — how a grown tree gets cut back to what it truly knows.
- Random forest — many noisy trees, averaged into a steady model.
- XGBoost — this split search, industrialised.
Developer — Code and libraries.
Setup
pip install scikit-learnOutputs verified with scikit-learn 1.7.2 on CPU.
Score every split by hand
import numpy as np
# fruit weights in grams; 0 = orange, 1 = apple (one apple is unusually small)
weights = np.array([110, 118, 125, 130, 138, 145, 150, 160])
labels = np.array([0, 0, 1, 0, 0, 1, 1, 1])
def gini(y):
if len(y) == 0:
return 0.0
p = y.mean() # fraction of apples in this pile
return 1 - p ** 2 - (1 - p) ** 2
n = len(labels)
for t in (114.0, 121.5, 127.5, 134.0, 141.5, 147.5, 155.0):
left, right = labels[weights <= t], labels[weights > t]
score = (len(left) * gini(left) + len(right) * gini(right)) / n
print(f"split at {t:5.1f} g -> weighted impurity {score:.3f}")split at 114.0 g -> weighted impurity 0.429 split at 121.5 g -> weighted impurity 0.333 split at 127.5 g -> weighted impurity 0.467 split at 134.0 g -> weighted impurity 0.375 split at 141.5 g -> weighted impurity 0.200 split at 147.5 g -> weighted impurity 0.333 split at 155.0 g -> weighted impurity 0.429
One split wins outright at 0.200. Does scikit-learn agree with our arithmetic?
from sklearn.tree import DecisionTreeClassifier, export_text
tree = DecisionTreeClassifier(max_depth=1, random_state=0)
tree.fit(weights.reshape(-1, 1), labels)
print(export_text(tree, feature_names=["weight"]))|--- weight <= 141.50 | |--- class: 0 |--- weight > 141.50 | |--- class: 1
The library picked 141.5 g — the same winner our arithmetic found.
The walkthrough
Where do candidate thresholds come from? Sort the feature; the midpoint between each pair of neighbouring values is a candidate. Eight fruits give seven candidates — no other threshold can produce a different split, so nothing else is worth trying.
Score the 141.5 split yourself. Left pile: [0, 0, 1, 0, 0] — one apple among five fruits, Gini 0.32. Right pile: [1, 1, 1] — pure, Gini 0. Weighted: (5 × 0.32 + 3 × 0) / 8 = 0.200. Our printed number, recovered by hand.
Note what the tree did with the odd small apple. The 125 g apple sits in the "orange" pile and the tree accepted that mistake. Chasing it with an extra question would carve out a one-fruit pile — the seed of overfitting, and the reason pruning exists.
Greedy means never looking back. The tree keeps the best question now and recurses. It never revisits a split in light of later ones, so the final tree can miss a globally better arrangement. Finding the optimal tree is computationally infeasible; greedy is the affordable compromise.
Common mistakes
Believing the tree tests every real number. People imagine infinite thresholds. Sorted midpoints are the complete list — which is why numeric precision of thresholds in exported trees looks odd (141.5, not 140).
Confusing Gini with entropy. criterion="entropy" swaps the impurity formula for information-gain. The two disagree on real data only occasionally; neither is reliably better (see researcher notes). Do not burn tuning budget here.
Reading feature importances as causal truth. Importances add up impurity reductions. Correlated features split credit unpredictably, and high-cardinality features get inflated scores. Treat importances as hints, not findings.
Letting the tree grow unlimited. Default DecisionTreeClassifier grows until leaves are pure — memorising noise like our odd apple. Set max_depth, min_samples_leaf, or prune afterwards.
Try it yourself
Change the odd apple's label at 125 g to orange, rerun both scripts, and confirm one split now scores 0.0. Then add a second feature — skin smoothness from the KNN lesson — and check whether the depth-1 tree prefers it over weight.
What to learn next
- Pruning a decision tree — how a grown tree gets cut back to what it truly knows.
- Random forest — many noisy trees, averaged into a steady model.
- XGBoost — this split search, industrialised.
Researcher — Mathematics and papers.
Impurity measures
For a node with class proportions $p_1, \dots, p_K$:
$$ G = 1 - \sum_{c=1}^{K} p_c^2, \qquad H = -\sum_{c=1}^{K} p_c \log_2 p_c $$
Where:
- $G$ — Gini impurity: the probability two random draws from the node disagree.
- $H$ — entropy in bits; "information gain" is the reduction in $H$ from a split.
- $p_c$ — fraction of node samples in class $c$; $K$ — number of classes.
A split of node $S$ into $S_L, S_R$ is scored by weighted child impurity:
$$ \Delta = I(S) - \frac{|S_L|}{|S|} I(S_L) - \frac{|S_R|}{|S|} I(S_R) $$
with $I$ either $G$ or $H$; the split maximising $\Delta$ wins. Both measures are concave in $p$, guaranteeing $\Delta \geq 0$. Empirically they disagree on ~2% of splits (Raileanu and Stoffel, 2004); Gini is marginally cheaper (no logarithm) and is CART's default.
For regression trees the impurity is the node variance, $I(S) = \frac{1}{|S|}\sum_{i \in S}(y_i - \bar{y}_S)^2$, and splits minimise summed child variance.
Complexity
At a node with $m$ samples and $d$ features: sort each feature, $O(d\, m \log m)$, then sweep thresholds updating class counts incrementally — $O(m)$ per feature. Total tree construction is $O(d\, n \log^2 n)$ typical, and modern gradient-boosting libraries cut the constant with histogram binning: features pre-bucketed into ~256 bins, splits scored on bin statistics (LightGBM; Ke et al., 2017).
Categorical features and axis-alignment
Optimal binary partition of an unordered categorical with $L$ levels naively costs $2^{L-1} - 1$ evaluations; for binary classification, sorting levels by their positive rate finds the optimum in $O(L \log L)$ (Breiman et al., 1984). Axis-aligned questions are a real representational limit — a diagonal boundary costs a staircase of splits. Oblique trees (Murthy et al., 1994) split on linear combinations; the idea resurfaces in tree-based neural hybrids.
The greedy gap and honest history
Learning an optimal decision tree is NP-complete (Hyafil and Rivest, 1976) — greedy induction is a heuristic, not a shortcut to optimality. Canon: CART (Breiman, Friedman, Olshen, Stone, 1984), ID3 and C4.5 (Quinlan, 1986; 1993) — the entropy lineage. Single trees are high-variance learners; their modern life is as base learners inside random forests and gradient boosting, where the split search above runs millions of times per model.
What to learn next
- Pruning a decision tree — how a grown tree gets cut back to what it truly knows.
- Random forest — many noisy trees, averaged into a steady model.
- XGBoost — this split search, industrialised.