Decision Trees
Learn how decision trees carve up feature space with if/else questions, how gini impurity picks the best split, and how to read and control a tree in scikit-learn.
Every model you've met so far draws smooth curves through the data. A decision tree does something completely different: it plays twenty questions. "Is petal length below 2.45 cm? Yes → it's a setosa. No → ask another question." The result is a model you can literally read out loud — and the building block for random forests and gradient boosting, the workhorses of tabular machine learning.
A model made of if/else rules
A trained tree is just a flowchart of yes/no questions about the features. Each internal node tests one feature against one threshold, each branch is an answer, and each leaf holds a prediction. Prediction is cheap: drop a sample in at the root and follow the answers down to a leaf.
Training is where the magic happens — the algorithm learns which questions to ask, in which order, from the data. Each question splits the feature space with an axis-aligned cut, so the decision boundary is built from rectangles. Watch what happens to the boundary as you let the tree ask more questions:
Decision tree playground
A CART tree splits the plane with axis-aligned cuts that minimize gini impurity. Depth 1–2 underfits the moons; depth 7–8 carves rectangles around individual noisy points.
At depth 1 the tree makes a single cut — one question. Each extra level lets it subdivide every region again, so the boundary gets more intricate. Push the depth high enough and the tree starts fencing off individual points: it has memorized the training set, noise included. Keep that picture in mind — depth is the tree's main complexity knob.
How a split is chosen: gini impurity
At every node the algorithm tries many candidate splits — every feature, many thresholds — and keeps the one that makes the resulting child nodes as pure as possible. The default purity measure in scikit-learn is gini impurity:
G = 1 − Σ pₖ²
where pₖ is the fraction of samples in the node belonging to class k. A pure node (all one class) has G = 0; a 50/50 node has G = 0.5. A candidate split is scored by the weighted average of its children's impurities — lower is better. Let's work a tiny example by hand:
The parent starts at 0.48. Split A drops the weighted impurity to 0.267 —
mostly because its left child is completely pure — while split B barely helps
at all. The tree greedily picks the biggest impurity drop, then repeats the
whole search inside each child. Entropy (criterion="entropy") is an
alternative measure with the same spirit; in practice the two produce very
similar trees, and gini is slightly cheaper to compute.
Depth and leaf size: the overfitting controls
Left alone, a tree keeps splitting until every leaf is pure — which usually means memorizing the training data. Two hyperparameters rein it in:
max_depth— hard cap on the number of questions along any path. Smaller = simpler boundary (exactly what you saw in the playground).min_samples_leaf— a split is only allowed if each child keeps at least this many samples. Larger values stop the tree from carving out tiny regions around individual noisy points, which indirectly limits depth too.
There's also min_samples_split (don't split nodes smaller than this) and
max_leaf_nodes. You rarely need all of them — tuning max_depth plus
min_samples_leaf covers most situations.
A real tree on iris
Let's train one and — this is the fun part — print its rules as plain text:
Read the printout top to bottom: the very first question — petal length vs 2.45 cm — separates all the setosas in one cut, and the rest of the tree works on telling versicolor from virginica. No coefficients, no probabilities to decode: the model is the explanation.
Notice what we didn't do: no feature scaling. A tree only asks "is this feature above this threshold?", so stretching or squashing a feature's scale changes the threshold but not the tree. Standardization, so critical for KNN and SVMs, is simply irrelevant here.
Drawing the tree
For reports and sanity checks, plot_tree renders the same structure
graphically — each node shows its split rule, gini, sample count, and class
mix:
Darker node colors mean purer nodes. Follow any root-to-leaf path and you can state the exact rule that produces that prediction — try explaining a neural network's prediction that easily.
Strengths — and the flaw that motivates forests
Decision trees have a lot going for them:
- Interpretable — the model is a readable set of rules.
- No scaling needed — thresholds don't care about units.
- Mixed feature types — numeric and (encoded) categorical features coexist happily, and monotone transformations of features change nothing.
- Nonlinear out of the box — no kernels or polynomial features required.
But they have one serious weakness: instability. Because each split is a greedy, winner-takes-all choice, removing a handful of training samples can flip which question wins at the root — and everything below the root then changes too. Two nearly identical datasets can produce wildly different trees. In statistics terms, a deep tree is a high-variance model.
Here's the beautiful trick: if one tree is unstable, train hundreds of slightly different trees and average them. The individual wobbles cancel out. That's a random forest — the subject of the next lesson.
Check your understanding
Q1.A node contains 8 samples of class A and 0 of class B. What is its gini impurity?
Q2.How does a decision tree pick which split to make at a node?
Q3.Why is feature scaling unnecessary for decision trees?
Q4.Your tree gets 100% train accuracy but 78% test accuracy. Which change is most likely to help?
Q5.What does it mean that decision trees are unstable?
Exercise: Find the sweet-spot depth on the wine dataset
Load load_wine from scikit-learn, split it 70/30 (stratified), and train
DecisionTreeClassifier models with max_depth from 1 to 10. Print train and
test accuracy for each depth and plot both curves. At what depth does test
accuracy peak, and where does the train–test gap start to widen?
Next up: random forests — how averaging hundreds of deliberately randomized trees turns one unstable learner into one of the most reliable models in machine learning.