Chapter 5: Decision Trees
Master the most interpretable machine learning models. Learn how decision trees recursively partition feature space, choose optimal splits using Gini impurity and entropy, prevent overfitting through pruning, and extract feature importance from learned structures.
Chapter Overview
Decision trees are among the most intuitive models in machine learning. They mirror human decision-making by asking a series of questions: "Is this feature above a threshold? If yes, go left; if no, go right." This continues until reaching a leaf node that makes the final prediction.
The key advantage of decision trees is interpretability—you can trace exactly why a model made a particular prediction by following the decision path from root to leaf. This makes trees invaluable in domains requiring explainability, like healthcare and finance.
Trees are also remarkably versatile. They handle both numerical and categorical features naturally, don't require feature scaling, and can capture non-linear relationships and interactions without explicit feature engineering. The same algorithm works for classification (predict a class) and regression (predict a continuous value).
The main challenge is overfitting. An unpruned tree will keep splitting until each leaf contains a single training example—perfect training accuracy but useless generalization. Controlling tree complexity through pruning and stopping criteria is essential.
Decision trees also form the foundation for powerful ensemble methods like Random Forests and Gradient Boosting, which combine many trees to achieve state-of-the-art performance.
This chapter covers:
- Tree Construction: How trees recursively partition data through optimal splits
- Splitting Criteria: Measuring node purity with Gini impurity, entropy, and MSE
- Pruning: Pre-pruning and post-pruning to prevent overfitting
- Regression Trees: Decision trees for continuous targets
- Feature Importance: Extracting which features contribute most to predictions
- Tree Visualization: Understanding and explaining tree decisions
Chapter Roadmap
Click any topic to jump in
Decision Tree Basics
Recursive partitioning, tree structure, and how trees make predictions — the most interpretable ML model.
Splitting criteria decide each branch, pruning decides when to stop growing
Splitting Criteria
Gini impurity, entropy, and information gain — mathematical measures that guide optimal split selection.
Pruning
Pre-pruning and post-pruning — controlling tree complexity to prevent overfitting.
Regression trees extend to continuous outputs, feature importance explains the model
Regression Trees
Piecewise constant predictions for continuous targets — MSE splitting and the extrapolation problem.
Feature Importance
Impurity-based importance, permutation importance, and SHAP — understanding what drives predictions.
Visualization & Interpretation
Visualizing trees, extracting rules, and interpreting decisions — the unique explainability advantage of trees.
Suppose a bank wants to approve loans with a model whose every decision can be read aloud to the applicant. Linear and logistic regression, from the earlier chapters, give one weighted sum per prediction: accurate when the relationship is roughly linear, but hard to explain when the true rule is "approve if income is high, unless debt is also high." Such rules involve thresholds and interactions that a single hyperplane cannot express without hand-built features. The previous chapter, Model Evaluation, gave us the tools to measure whether a model generalizes; this chapter builds a model family whose structure we can also inspect.
A decision tree answers a sequence of yes-or-no questions about the features, each answer narrowing the set of possibilities, until it reaches a leaf that makes the prediction. This first topic covers the anatomy of a tree, the recursive partitioning that builds it, and how the best split is searched for. We then look at what classification and regression leaves predict, and close with the strengths and weaknesses that motivate pruning later in this chapter and ensembles in the next.
Definition
A decision tree is a model that recursively partitions the feature space with axis-aligned tests of the form "feature j is at most threshold t". Each internal node holds one test, each branch one outcome, and each leaf a constant prediction: a class (with class proportions) for classification, or a mean value for regression.
In this topic
Tree Structure
A tree is built from three kinds of nodes. The root is the first test, applied to every sample. Internal nodes apply further tests to the samples routed to them, and leaves hold the final predictions. Every root-to-leaf path is a conjunction of conditions, so the whole tree is a set of mutually exclusive rules. Depth is the number of edges on the longest path; a binary tree of depth has at most leaves and nodes. Depth controls both capacity and readability: depth 3 gives at most 8 rules a person can follow, while depth 20 allows over a million leaves.
A binary decision tree with depth has at most leaf nodes and internal nodes, for a maximum of total nodes. Each internal node stores a split rule meaning "feature ?" The number of possible trees with features grows super-exponentially, making brute-force search over all tree structures intractable — greedy top-down construction is necessary.
Tree has root, 2 children (1 leaf, 1 internal with 2 leaves). How many nodes? What depth?
Recursive Partitioning
Trees are grown top-down and greedily. Starting with all training samples at the root, the algorithm chooses the single feature and threshold whose split most improves purity, sends samples to the left or right child, and repeats the same procedure independently inside each child. Growth stops when a node is pure, too small, or a depth limit is reached. Each split cuts a region with a line perpendicular to one feature axis, so the final partition is a set of axis-aligned boxes. Greedy means each split is chosen without looking ahead, so the resulting tree is good but not guaranteed optimal; finding the optimal tree is NP-hard.
Each split on feature divides a region into and . After splits, the feature space is partitioned into at most axis-aligned rectangular regions. The tree prediction is constant within each region: for . This makes trees piecewise constant approximators — they approximate any continuous function by stacking enough rectangular regions.
Root splits on age>30. Left child splits on income>50K. What regions are created?
Split Selection
At each node the tree must choose one feature and one threshold. For a numeric feature with distinct sorted values, only thresholds can produce different partitions, so candidates are the midpoints between consecutive values. For each candidate the algorithm computes the impurity of the two children, weighted by their sizes, and keeps the split with the largest reduction from the parent. Sorting once and scanning with running counts makes each feature cost about . The search is exhaustive over features and thresholds but myopic over depth, which is why a split with little immediate gain can be overlooked.
For a feature with unique values, there are candidate thresholds (midpoints between consecutive sorted values). With features, the greedy algorithm evaluates candidate splits per node. For each candidate, computing the impurity reduction takes time using running sums. The total cost for building a balanced tree of depth is if the data is pre-sorted, or in the worst case for unbalanced trees.
Feature X has values [10, 20, 35, 40]. What thresholds to try?
Classification Trees
In a classification tree each leaf stores the class counts of the training samples that reached it. The predicted class is the majority class, which minimizes misclassification on those samples, and the predicted probabilities are the class proportions, which are maximum likelihood estimates for that region. Probabilities from small leaves are unreliable: a leaf with 3 samples can only output multiples of one third, and a pure leaf outputs probability 1 even when the true rate is lower. Deep trees therefore tend to give overconfident, poorly calibrated probabilities, which is one reason min_samples_leaf and ensembles help.
A leaf containing samples with class counts predicts class and outputs probabilities . The class probabilities are maximum likelihood estimates for a categorical distribution. The prediction minimizes the 0-1 loss (misclassification rate) on the leaf's training samples. More samples in the leaf give more reliable probability estimates, with standard error .
Leaf has 30 samples: 20 cats, 8 dogs, 2 birds. Prediction? Probabilities?
Regression Trees
A regression tree uses the same partitioning, but each leaf predicts a number: the mean of the training targets in that region. The mean is the constant that minimizes squared error within the leaf, so it pairs naturally with the variance-reduction split criterion covered next. The resulting model is a step function: constant inside each region and jumping at the boundaries. A leaf's prediction has variance proportional to the noise variance divided by the number of samples it holds, so deep trees with tiny leaves give noisy, overfitted predictions. A later topic in this chapter treats regression trees in depth.
A leaf predicts , the sample mean of targets in region . This minimizes the squared error over the constant . The prediction variance within the leaf is where is the noise variance. Deep trees with few samples per leaf have high prediction variance — this is the overfitting mechanism in regression trees.
Leaf has 4 house prices, in thousands: [200, 220, 240, 300]. Prediction?
Advantages of Trees
Trees need little preprocessing. A split compares a feature with a threshold, so any monotonic transformation of a feature, such as scaling or taking logs, yields the same partitions; no standardization is required. Trees model interactions automatically, because a split on one feature followed by a split on another creates a rule involving both. They handle mixed feature types, ignore irrelevant features that are never chosen, and predict in time proportional to depth. Above all, a shallow tree is readable. Some caveats apply: scikit-learn's implementation needs categorical features encoded as numbers, and its support for missing values depends on the version.
Trees are invariant to monotonic transformations of features: if is a good split, then produces the same partition. This means no feature scaling is needed. Trees also naturally handle interactions: a split on followed by a split on captures the interaction without explicit feature engineering. Inference is — just follow a path from root to leaf, comparing one feature at each node.
Income in dollars, age in years, city as category. Do you need to preprocess for a tree?
Disadvantages of Trees
The main weakness of a single tree is high variance. Because splits are chosen greedily, a small change in the training data can change the root split, and every split below it changes too, giving a very different tree with similar accuracy. Trees also draw only axis-aligned boundaries, so a diagonal boundary such as must be approximated by a staircase of many splits. Grown fully, they memorize the training set. Finally, regression trees cannot extrapolate beyond the target range seen in training. Pruning reduces overfitting, and ensembles such as random forests, in the next chapter, average away much of the variance.
Trees are high-variance estimators: the greedy split selection means that adding or removing a single training sample can change the root split, cascading to a completely different tree structure. Formally, for smooth functions. Trees also create axis-aligned boundaries only — approximating a diagonal boundary requires splits for accuracy , creating a staircase pattern.
Remove 1 sample, tree structure changes completely. Is this normal?
Theory Exercise
Problem:
Why do decision trees create axis-aligned boundaries? What patterns would be hard for a single tree to capture?
Hints:
- Each split divides on one feature at a time
- Think about diagonal patterns
- What about circular decision boundaries?
Coding Exercise
Problem:
Fit a shallow DecisionTreeClassifier (max_depth=2) on the iris dataset and print its decision rules with export_text. Observe how readable the rules are.
Hints:
- Load iris with load_iris(return_X_y=True) and keep load_iris().feature_names for labeling.
- Constrain the tree with max_depth=2 and always pass random_state=42.
- Use export_text(clf, feature_names=...) to dump human-readable if/else rules, then call clf.score for accuracy.
Related Problems on PixelBank
The previous topic, Decision Tree Basics, said each node picks the split that most improves purity, but never defined purity. That definition decides everything: two different measures can choose different roots and grow different trees from the same data. A node with 50 cats and 50 dogs is clearly impure, and a node with 100 cats is clearly pure, but what about 70 and 30 versus 60, 30, and 10? We need a number that scores any class mix, is zero for a pure node, and rewards splits whose children are purer than their parent.
This topic introduces the impurity measures used in practice. We start with Gini impurity, the scikit-learn default, and entropy from information theory. We then define information gain, the entropy reduction that a split achieves, and gain ratio, which corrects its bias toward features with many values. After comparing Gini and entropy directly, we turn to regression, where squared error and absolute error play the role of impurity and decide whether leaves predict a mean or a median.
Definition
A splitting criterion is an impurity function that scores how mixed the targets in a node are, zero for a pure node. A split is evaluated by its impurity decrease: the parent's impurity minus the size-weighted average impurity of its children. The tree chooses the feature and threshold with the largest decrease.
In this topic
Gini Impurity
Gini impurity is the probability that two samples drawn at random from a node, with replacement, have different classes. Here is the fraction of samples in class and is the number of classes, so is the chance both draws match. Gini is 0 for a pure node and reaches its maximum, , when all classes are equally frequent: 0.5 for two classes, 0.667 for three. For binary problems it simplifies to . Because Gini is concave, the weighted impurity of the children can never exceed the parent's, so every split has a non-negative decrease. It needs no logarithm, which makes it cheap.
Gini impurity = measures the probability that two randomly drawn samples from a node have different classes. For binary classification: , which is maximized at (Gini = 0.5) and zero when (pure node). Gini is a concave function of the class probabilities, and any concave impurity function guarantees that splitting always reduces weighted impurity — the weighted child impurity is always the parent impurity.
Node has 70 class A, 30 class B. Calculate Gini.
Entropy
Entropy, from information theory, measures the average number of bits needed to encode the class of a sample drawn from the node. With class fractions , each class contributes , using the convention that a zero fraction contributes 0. Entropy is 0 for a pure node and when all classes are equally likely: 1 bit for two classes, about 1.585 bits for three. Like Gini it is concave, so splits never increase weighted entropy. Its logarithm penalizes small minority fractions more sharply than Gini does. ID3 and C4.5 use entropy; scikit-learn offers it as criterion='entropy'.
Entropy = measures the expected number of bits needed to encode the class label. Maximum entropy occurs when all classes are equally likely (maximum uncertainty). For binary: , maximized at where bit. Entropy is a strictly concave function of , and it upper-bounds Gini: for binary classification (after unit conversion).
50% class A, 50% class B. Entropy?
Information Gain
Information gain is the reduction in entropy produced by a split. Here is the parent's entropy, its sample count, and the number of samples sent to child ; each child's entropy is weighted by , so a pure but tiny child earns little credit. The tree evaluates the gain of every candidate split and keeps the largest. Information gain equals the mutual information between the class label and the split outcome, so it measures how much the question tells us about the answer. Its weakness is a bias toward features with many distinct values, which can split data into many small, accidentally pure children.
Information gain = is the reduction in entropy from a split. By concavity of entropy, IG for any split. IG is maximized by the split that creates the most homogeneous children. For a binary split, IG can be written as , the mutual information between the class label and the split indicator. ID3 and C4.5 use information gain (or gain ratio) as the splitting criterion.
Parent H=1.0, 100 samples. After split: Left (60 samples, H=0.5), Right (40, H=0.3). Info gain?
Gain Ratio
C4.5 corrects information gain's bias by dividing it by the split information, the entropy of the partition sizes themselves, . A split into two equal halves has split information 1 bit; a split into 100 equal groups has , about 6.64 bits. A feature such as a customer ID can create many tiny, pure children and so a large raw gain, but its huge split information shrinks the ratio. One caveat: a very lopsided split has split information near zero, which can inflate the ratio, so C4.5 only considers splits whose gain is at least average.
Gain ratio = where . SplitInfo is the entropy of the split itself — how evenly it divides the data. A feature with 100 unique values has high SplitInfo ( bits) but might have high IG simply because each child is nearly pure by accident. Gain ratio normalizes IG by this split entropy, penalizing features that create many small children — this is why C4.5 uses gain ratio over plain IG.
Split A: IG=0.5, creates 2 branches. Split B: IG=0.6, creates 100 branches. Which is better?
Gini vs Entropy
Gini and entropy are both concave, zero for pure nodes, and maximized at the uniform distribution, so they rank splits almost identically; studies find they disagree on only a few percent of splits. Their raw values differ in scale, with binary maxima of 0.5 and 1.0, but only the ranking of candidate splits matters, never the absolute number. Gini avoids a logarithm and is slightly faster, which is why it is scikit-learn's default. Entropy weights rare classes a little more heavily, sometimes producing slightly more balanced trees. In practice, the choice of criterion matters far less than depth and pruning.
Both measures are concave, symmetric in the classes, zero for a pure node, and maximized at the uniform distribution. Entropy is ; replacing by its first-order approximation , accurate when is near 1, gives , which is exactly Gini. So Gini behaves like a cheap, log-free version of entropy, and the two rank candidate splits almost identically. They disagree most when a split isolates a small, nearly pure child, because the logarithm penalizes small residual class fractions more heavily.
70/30 split. Gini=0.42, Entropy=0.88. Very different numbers. Problem?
MSE for Regression
For regression, impurity becomes the mean squared error around the node mean, , where is the node mean and its sample count. That is just the variance of the targets in the node. A split is scored by the parent's MSE minus the size-weighted MSE of the children, so the best split separates low targets from high ones. The reduction equals , which rewards balanced children with very different means. Running sums of and make every threshold cheap to score. Squaring makes the criterion sensitive to outliers.
For regression splits, the impurity is , the variance of the target within the node. A split reduces MSE by: . This is equivalent to maximizing the between-group sum of squares: . The optimal threshold for a given feature can be found in by sorting and scanning with running means.
Node has prices, in thousands: [100, 200, 300]. Mean = 200. MSE?
MAE for Regression
Mean absolute error as an impurity uses absolute deviations from the median, . Because the median minimizes absolute error, leaves under this criterion predict the median rather than the mean. Absolute deviations grow linearly, not quadratically, so one extreme target cannot dominate split choices, and the median ignores how far an outlier sits. The cost is speed: medians cannot be updated with running sums, so evaluating thresholds is much slower than with MSE. In scikit-learn, criterion='absolute_error' selects it; it pays off when targets have heavy tails.
MAE splitting minimizes within each child, where the optimal prediction is the median (not the mean). MAE is more robust to outliers than MSE: a single large shifts the mean but barely affects the median. However, MAE splitting is computationally harder — there is no simple incremental formula for the median, requiring per threshold evaluation compared to for MSE with running sums.
Prices, in thousands: [100, 110, 120, 500]. Mean = 207.5, Median = 115. Outlier impact?
Theory Exercise
Problem:
A node has 100 samples: 50 class A, 30 class B, 20 class C. Calculate the Gini impurity and entropy.
Hints:
- Calculate class probabilities first
- Gini: 1 - Σp²
- Entropy: -Σp·log₂(p)
Coding Exercise
Problem:
Implement Gini impurity and entropy from scratch for a label array, then compute the information gain of a candidate threshold split on a feature. Compare the result to intuition for a cleanly separable split.
Hints:
- Gini = 1 - sum(p_i^2) and entropy = -sum(p_i * log2(p_i)), where p_i are class proportions from np.unique(..., return_counts=True).
- Split the labels into left/right by the threshold, then weight each child's impurity by its fraction of samples.
- Information gain = parent_impurity - weighted_child_impurity; a perfect split drives weighted child impurity to 0.
Related Problems on PixelBank
Left alone, the algorithm from the previous topic, Splitting Criteria, keeps splitting until every leaf is pure. On the training set that means near-perfect accuracy; on new data it often means a model that memorized noise, such as a leaf created for one mislabeled sample. A fully grown tree on a few thousand noisy rows can easily reach 100 percent training accuracy with a hundred or more leaves while its test accuracy is no better than a much smaller tree. Every extra leaf is a rule fitted to fewer examples, so it is less trustworthy.
Pruning controls this by limiting the tree's size. This topic covers the two strategies and their main tools. Pre-pruning stops growth early using limits on depth, samples per node, and minimum impurity decrease. Post-pruning grows the full tree first and then cuts back subtrees that do not earn their complexity. We study cost-complexity pruning, the post-pruning method in CART and scikit-learn, and how cross-validation from Model Evaluation picks its strength.
Definition
Pruning limits a decision tree's complexity to reduce overfitting. Pre-pruning stops splitting when a criterion such as maximum depth or minimum samples is met. Post-pruning grows the full tree, then replaces subtrees with leaves when the extra accuracy does not justify the extra leaves, as in cost-complexity pruning.
In this topic
Pre-pruning (Early Stopping)
Pre-pruning stops growing a branch as soon as a stopping rule fires. The main rules in scikit-learn are max_depth, min_samples_split, min_samples_leaf, max_leaf_nodes, and min_impurity_decrease. Pre-pruning is cheap, because unneeded subtrees are never built, and easy to tune. Its weakness is the horizon effect: a split with little immediate gain may enable strong splits below it. The classic case is XOR, where the label depends on two features together; neither alone reduces impurity, so a minimum-gain rule stops before the useful pair of splits is found.
Pre-pruning stops tree growth at a node when a stopping criterion is met: , , or . This is computationally efficient (avoids building subtrees that will be cut) but suffers from the horizon problem: a split that looks useless locally might enable powerful splits deeper in the tree. The interaction requires two consecutive splits that individually have low gain — pre-pruning would miss this.
max_depth=3, but optimal split at depth 4 would help. What happens?
Post-pruning
Post-pruning grows the tree fully, then removes structure bottom-up. In reduced-error pruning each internal node is tentatively replaced by a leaf, and the replacement is kept if accuracy on a separate validation set does not drop. Pruning repeats until no replacement helps. Because the full tree already contains every split, post-pruning avoids the horizon effect: a weak split is kept if the subtree beneath it pays off. The costs are growing a large tree first and, for reduced-error pruning, holding out validation data. Cost-complexity pruning, next, avoids the holdout by using cross-validation to set its single parameter.
Post-pruning builds the full tree first, then removes subtrees bottom-up if removing them does not significantly increase validation error. For each internal node, compare: (a) the subtree error, and (b) the error if this node becomes a leaf. If , prune. Post-pruning avoids the horizon problem because the full tree has already explored all possible splits. The cost is building a larger tree initially, but the result is generally better than pre-pruning alone.
Full tree: 100 leaves, train=99%, val=70%. After pruning: 20 leaves, train=85%, val=82%. Good?
Cost-Complexity Pruning (CCP)
Cost-complexity pruning, from CART, scores a tree by , where is its training error (or total impurity), its number of leaves, and the price per leaf. At the full tree wins; as grows, subtrees whose error reduction per leaf is below are collapsed. Each internal node has a critical value, the error increase from collapsing it divided by the leaves removed, and pruning the weakest link first yields a nested sequence of subtrees. In scikit-learn this is the ccp_alpha parameter.
balances misclassification cost with tree size (number of leaves). As increases, larger trees are penalized more, producing simpler trees. For each subtree rooted at node , pruning is optimal when . This critical is the "effective alpha" — the sequence of nested prunings as grows from 0 to produces a path from the full tree to the root.
Tree A: error=0.1, 50 leaves. Tree B: error=0.12, 10 leaves. α=0.001. Which wins?
Finding Optimal α
Cost-complexity pruning turns tree selection into choosing one number. Scikit-learn's cost_complexity_pruning_path returns the critical alphas at which each successive subtree is pruned, so only those values need testing. Each candidate alpha is scored with K-fold cross-validation, and the one with the best mean score wins. CART also proposed the one-standard-error rule: choose the largest alpha whose score is within one standard error of the best, giving a simpler tree with statistically similar accuracy. The validation curve is U-shaped: alpha near zero overfits, very large alpha underfits, and the sweet spot is in between.
The optimal is found by cross-validation: build the full tree, compute the pruning path (nested sequence of subtrees for increasing ), then evaluate each subtree's CV error. The 1-SE rule selects the simplest tree within one standard error of the minimum CV error: . This trades a small amount of accuracy for significantly simpler trees, improving interpretability and reducing variance.
CV scores: α=0 (80%), α=0.01 (85%), α=0.1 (75%). Best α?
max_depth
max_depth caps the length of every root-to-leaf path, so a tree of depth has at most leaves. It is the most commonly tuned pre-pruning parameter because it controls capacity directly and is easy to explain: depth 3 means at most three questions per prediction. Shallow trees, depth 2 to 5, are readable and stable but can underfit; deep trees capture fine interactions but overfit. Because the effect depends on the data, tune it with cross-validation over a range such as 2 to 15. A depth limit cuts all branches equally, even where one branch would benefit from going deeper.
Limiting depth bounds the number of leaves at and the number of regions in the feature space. A depth- tree can represent at most distinct prediction values. For a function with distinct output levels, you need depth. In practice, balances expressiveness and overfitting. Each additional level doubles the maximum leaf count and the VC dimension of the hypothesis class.
Stakeholder wants to understand the model. Depth 20 tree has 90% accuracy. What to do?
min_samples_split / min_samples_leaf
These parameters require statistical support for every decision. min_samples_split is the smallest node that may be split; min_samples_leaf is the smallest number of samples any child may hold, so a split leaving fewer in one child is rejected. Leaf estimates average fewer points as leaves shrink, so their variance rises: a leaf of 2 samples gives an unreliable mean or class proportion. Raising min_samples_leaf to 5 to 50 smooths regression outputs and calibrates probabilities better. The parameters also accept fractions of the dataset, such as 0.01 for 1 percent, which scale with dataset size.
These constraints control the minimum statistical support for decisions. A leaf with samples has prediction variance — fewer samples means noisier estimates. Setting ensures each prediction is based on at least 5 observations, giving a coefficient of variation of at most . Similarly, ensures splits are based on enough data to be statistically meaningful rather than fitting noise patterns.
Node has 5 samples. min_samples_split=10. What happens?
Minimum Impurity Decrease
min_impurity_decrease rejects any split whose weighted impurity reduction falls below a threshold. In scikit-learn the reduction is weighted by the node's share of all training samples, , so a split deep in the tree, which touches few samples, must be correspondingly purer to qualify. The rule removes splits that barely improve purity and are likely to reflect noise. The right threshold depends on the criterion, because Gini and entropy have different scales, and on the data, so tune it with cross-validation. Like other pre-pruning rules it can stop before splits that only pay off deeper down.
A split is only performed if the impurity decrease exceeds a threshold : . Since the impurity decrease of a random split has expectation , setting filters out splits that provide negligible information. This is equivalent to a significance test: the split must reduce impurity more than expected by chance. However, the threshold interacts with the scale of the impurity measure — Gini and entropy require different values.
Split reduces Gini by 0.001 (negligible). min_impurity_decrease=0.01. Split?
Theory Exercise
Problem:
Your decision tree has 99% training accuracy but 70% test accuracy. List the pruning strategies you'd try to reduce overfitting.
Hints:
- This is classic overfitting
- Consider both pre-pruning and post-pruning
- Which hyperparameters control complexity?
Coding Exercise
Problem:
Grow a full (unconstrained) decision tree on breast cancer data so it overfits, then use cost_complexity_pruning_path to sweep ccp_alpha values and find a pruned tree with better test accuracy and far fewer nodes.
Hints:
- Train an unconstrained DecisionTreeClassifier first and compare train vs test accuracy to see the overfitting gap.
- Call clf.cost_complexity_pruning_path(X_train, y_train) to get a list of candidate ccp_alphas.
- Refit a tree for each alpha with ccp_alpha=alpha, then keep the one with the highest test score and note its smaller depth.
House prices, delivery times, and energy demand are numbers, not classes, and they often depend on their features through thresholds and interactions: a garden adds value only in suburbs, and demand jumps when temperature crosses a heating threshold. Linear regression, from an earlier chapter, fits one global trend and misses such structure unless we engineer features by hand. The previous topic, Pruning, showed how to keep a tree's size under control; now we apply the full tree machinery to continuous targets.
A regression tree partitions the feature space exactly as a classification tree does, but its leaves predict numbers, and its splits are chosen to reduce squared or absolute error instead of class impurity. This topic covers how a regression tree predicts, how squared error drives its splits, and why its output is a step function. We then compare squared and absolute error criteria, examine the important inability of trees to extrapolate beyond the training range, and close by comparing regression trees with linear regression so you know when each fits better.
Definition
A regression tree is a decision tree whose leaves predict a constant numeric value, usually the mean of the training targets that reach the leaf, or the median under an absolute-error criterion. Splits are chosen to minimize the size-weighted squared error of the children, so the fitted function is piecewise constant over axis-aligned regions.
In this topic
Regression Tree Prediction
To predict for a new input, the tree routes it from the root to a leaf by applying each split test, then returns that leaf's stored value. Here is the region of feature space covered by leaf , the number of training samples in it, and the average of their targets. The mean is the constant that minimizes squared error over the leaf's samples. Every input in a region gets the same prediction, so the tree cannot rank two houses in the same leaf. A leaf's mean is estimated from samples, so its variance falls as leaves grow, the reason min_samples_leaf matters.
Each leaf predicts , the sample mean of all training targets in region . This is the constant that minimizes . The tree function is , a sum of indicator functions — a piecewise constant function over rectangular regions that partition the feature space.
New house: 3 bedrooms, 2000 sqft. Falls into leaf with training prices, in thousands: [300, 320, 280]. Prediction?
MSE as Splitting Criterion
For each candidate split, the tree computes the sum of squared deviations of the targets from their own child means, and , and picks the split with the smallest total. Equivalently, it maximizes the reduction in variance from the parent. The reduction depends on the gap between the child means and on the balance of the split, so the best split separates the targets into two groups with distant means. Because the criterion is squared, outliers pull splits toward isolating them. With targets sorted along a feature, running sums score every threshold in one pass.
For a split dividing region into and , the MSE reduction is , which is maximized when the split creates the largest mean difference between the two groups. This is equivalent to one step of the variance reduction criterion: . The greedy algorithm finds the split maximizing this reduction from candidate splits.
Prices, in thousands: [100, 150, 400, 450]. Split A separates the two cheapest from the two most expensive; split B separates the three cheapest from the most expensive. Which is better?
Piecewise Constant Approximation
A regression tree's output is a step function: constant inside each leaf region and jumping at the split thresholds. A smooth curve is approximated by a staircase, and more leaves give finer steps and a closer fit. In one dimension with leaves, a function with bounded slope can be approximated to within about the slope times the step width. In dimensions the steps must shrink along every axis, so the needed leaves grow exponentially, a form of the curse of dimensionality. Steps also mean that small input changes produce no output change until a boundary is crossed, then a jump.
A regression tree with leaves approximates the true function by horizontal steps. The approximation error decreases as grows: for a Lipschitz function with constant , the approximation error is in each region, where is the region diameter. With leaves in dimensions, the average region diameter is , giving approximation error — the curse of dimensionality for piecewise constant models.
True function: y=x². Tree approximation?
MAE Criterion
Replacing squared error with absolute error changes both the leaf value and the split choice. The constant minimizing absolute error is the median, so leaves predict medians, and splits minimize the sum of absolute deviations from each child's median. The median is robust: up to half of a leaf's values can be arbitrarily extreme without moving it far. This suits heavy-tailed targets such as prices or incomes. The costs are slower training, since medians lack cheap running updates, and predictions that track the typical value rather than the average, which matters if the goal is total revenue. In scikit-learn, use criterion='absolute_error'.
Using MAE instead of MSE, the optimal leaf prediction is the conditional median instead of the mean. The MAE split criterion minimizes the sum of absolute deviations: . This is more robust to outliers: the breakdown point of the median is 50% vs. 0% for the mean. In scikit-learn, this is selected via criterion='absolute_error'.
Leaf prices, in thousands: [100, 110, 120, 1000]. MSE criterion predicts? MAE criterion predicts?
Extrapolation Problem
A tree can only output values stored in its leaves, and every leaf value is an average of training targets. Predictions are therefore bounded by the smallest and largest training targets, whatever the input. For an input beyond the training range, the tree applies its split tests as usual, lands in the outermost leaf, and returns that leaf's mean: the prediction flattens instead of following the trend. This matters for data with growth or drift, such as prices rising over time or sizes beyond those observed. Remedies include linear models, linear-tree hybrids, or modeling the trend first and fitting the tree to the residuals.
Trees predict the mean of training targets in each leaf region. For outside all training regions, the tree assigns it to the nearest leaf — predicting the mean of the boundary region. This means tree predictions are bounded by — they cannot extrapolate beyond the range of training targets. For data with trends (e.g., time series with growth), this means predictions plateau at the last observed value rather than continuing the trend.
Training: houses 1000-3000 sqft. New house: 5000 sqft. Tree's prediction?
Comparison to Linear Regression
Linear regression fits one global equation with parameters, so it is stable, extrapolates along its trend, and gives coefficients with a clear per-unit meaning, but misses thresholds and interactions unless engineered. A regression tree fits a local constant per region, so it captures thresholds, interactions, and nonlinear shapes automatically, needs no scaling, and grows its capacity with the data. It is unstable, predicts in steps, and cannot extrapolate. A smooth, roughly linear relationship favors linear regression; an irregular one with interactions favors trees. When unsure, cross-validate both.
Linear regression fits — a global hyperplane with parameters. A tree fits a piecewise constant with parameters (one per leaf). Linear regression has capacity regardless of ; a tree's capacity grows with data, potentially reaching (one leaf per sample). Trees excel when the true function has discontinuities or interactions; linear regression excels when the relationship is approximately linear and extrapolation is needed.
Predict sales from ad spend. Relationship is linear. Tree vs linear regression?
Theory Exercise
Problem:
You fit a regression tree to predict house prices. Training data has prices from 100K to 500K dollars. A new house has features suggesting it should be worth 600K dollars. What will the tree predict?
Hints:
- Trees are piecewise constant
- Can a tree predict values outside training range?
- What leaf will this house fall into?
Coding Exercise
Problem:
Fit a DecisionTreeRegressor to a noisy sine curve, show that its predictions are piecewise-constant inside the training range, and demonstrate that it cannot extrapolate beyond the data it was trained on.
Hints:
- Generate X from a fixed RandomState over [0, 2*pi] and set y = sin(X) plus small Gaussian noise.
- Limit the tree with max_depth=3 so predictions form a few flat steps; count np.unique on its predictions.
- Predict at x-values far outside the training range (e.g. 10, 20) and notice the output stays clamped at the nearest leaf's constant value.
Related Problems on PixelBank
A churn model that is 90 percent accurate still leaves the product team asking: which customer attributes drive the predictions? The previous topic, Regression Trees, completed the picture of how trees predict; this topic asks what a fitted tree can tell us about its features. Trees offer an appealing answer built in, because every split records how much a feature reduced impurity, but that convenient number is easy to misread and can be badly biased.
We first define impurity-based importance, the feature_importances_ attribute in scikit-learn, and work through how it is computed. Then we look at what it does not say: it gives magnitude without direction, it is inflated for features with many unique values, such as IDs, and it is split unpredictably among correlated features. These failure modes lead to two better tools. Permutation importance measures how much held-out performance drops when a feature is shuffled and works for any model. SHAP values, grounded in game theory, explain individual predictions with signed contributions.
Definition
Feature importance is a score of how much a model relies on each input feature. For trees, impurity-based importance sums each feature's weighted impurity decreases over all its splits, normalized to sum to 1. Permutation importance instead measures the drop in a held-out score when the feature's values are randomly shuffled.
In this topic
Impurity-Based Importance
Every split on feature reduces impurity by some for the samples at that node. Impurity-based importance, also called mean decrease in impurity, sums over all splits on and normalizes so all features sum to 1. Splits near the root touch many samples and dominate; a feature never used scores 0. It is free to compute during training and available as feature_importances_. Its flaw is that it is measured on training data, so it rewards features that helped the tree fit noise as well as signal. The next concepts show the consequences.
Feature 's importance is , summing the weighted impurity decrease over all nodes splitting on feature . This is normalized so . The weighting by means splits near the root (affecting more samples) contribute more. This is computed for free during tree building — no additional computation needed. The importance reflects how much each feature contributes to reducing prediction error.
Age: one split (1000 samples, ΔGini=0.2). Income: two splits (800×0.1, 200×0.15). Raw importances?
Interpreting Importance
An importance score says how much the model used a feature, not how the feature affects the outcome. It has no sign: a large importance for age is consistent with older customers churning more, less, or with a U-shaped effect. It describes the model, not the world, so a feature can be truly causal yet unimportant because a correlated feature carried its signal. Scores are relative within one model and sum to 1, so comparing them across models or datasets is not meaningful. For direction, inspect the splits, plot partial dependence, or use SHAP values.
Feature importance ranks features by their total contribution to impurity reduction, but does not indicate direction (positive or negative effect) or interaction structure. A feature with importance 0.3 contributed 30% of the total impurity reduction. Importance values are relative within a single model — they sum to 1 by construction. Comparing importance values across different models or datasets is not meaningful because the total impurity reduction changes.
Age importance = 0.4 for churn prediction. Does older age increase or decrease churn?
High-Cardinality Bias
A feature with many distinct values, such as a customer ID or timestamp, offers many candidate thresholds, while a binary feature offers one. More candidates mean more chances for a threshold to separate the training labels by accident, so deep trees will happily split on IDs to purify small nodes. Those splits fit noise, yet impurity-based importance credits them in full, because it is computed on training data. The result is that meaningless high-cardinality features appear important. Fixes: drop identifiers before training, limit depth, or measure importance with permutation on held-out data, which exposes such features as useless.
Features with many unique values (high cardinality) have more candidate split thresholds: for unique values vs. 1 for binary features. With more candidates, the best split is more likely to overfit noise — similar to multiple testing without correction. This inflates the impurity-based importance of high-cardinality features. A random ID feature with unique values would appear highly important despite containing no real signal, because it can perfectly separate training data.
Customer ID has importance=0.5, actual predictive features have 0.1 each. Problem?
Correlated Features
When two features carry the same information, such as height in centimeters and in inches, any split on one could be made just as well on the other. The tree picks whichever is marginally better, or the first one examined when they tie, and the other receives little or no credit. Importance is then concentrated on one feature or split between them arbitrarily, so a zero score does not mean a feature is uninformative. Permutation importance has a related weakness: shuffling one copy barely hurts, since the other remains. Group correlated features, or drop and refit to measure their joint value.
When features and are highly correlated (), the tree picks whichever creates a slightly better split at each node. Across bootstrap samples (in Random Forests), the choice fluctuates randomly. The importance of each correlated feature is approximately where is the number of correlated copies. This means correlated features split the importance among them, each appearing less important than they actually are.
Height_cm and height_inches both important predictors. Tree shows height_cm=0.3, height_inches=0.0. Why?
Permutation Importance
Permutation importance measures how much a fitted model's score drops when one feature's values are randomly shuffled, breaking its link with the target while keeping its distribution. A large drop means the model relied on the feature. Computed on a held-out set, it reveals reliance that generalizes, so noise features such as IDs score near zero. It works for any model, needs no retraining, and should be repeated over several shuffles to show variance. Costs and caveats: one prediction pass per feature per repeat, and shuffling creates unrealistic combinations when features are correlated. Scikit-learn provides permutation_importance.
Permutation importance measures the increase in prediction error when feature 's values are randomly shuffled: . Shuffling breaks the association between and while preserving the marginal distribution of . A large increase in error means the model relied heavily on that feature. Unlike impurity-based importance, permutation importance is model-agnostic, can be computed on test data, and does not suffer from cardinality bias.
Original accuracy: 85%. Shuffle age: 70%. Shuffle income: 83%. Permutation importances?
SHAP Values
SHAP values explain a single prediction by assigning each feature a signed contribution, based on Shapley values from cooperative game theory. A feature's value is its average marginal effect on the prediction across all orders of adding features. The contributions add up exactly: base value plus the sum of all equals the prediction, where the base value is the average prediction over the data. Signs show direction, so SHAP answers what importance cannot. For trees, the TreeSHAP algorithm computes them exactly in polynomial time. Averaging absolute SHAP values over many samples gives a global importance ranking.
SHAP (SHapley Additive exPlanations) assigns each feature a contribution to each individual prediction using the Shapley value from cooperative game theory: . For trees, SHAP values can be computed exactly in time per sample (where = leaves, = depth) using the TreeSHAP algorithm. SHAP values sum to the prediction: , providing a complete additive decomposition.
For customer X: SHAP(age)=-0.2, SHAP(income)=+0.3. Base prediction=0.5. Explanation?
Theory Exercise
Problem:
A decision tree uses feature X for 3 splits: at the root (1000 samples, ΔGini=0.15), middle (400 samples, ΔGini=0.08), and leaf level (50 samples, ΔGini=0.20). Calculate the raw importance of X.
Hints:
- Weight each split by number of samples
- Sum up weighted impurity reductions
- This is before normalization
Coding Exercise
Problem:
On a make_classification dataset containing informative, redundant, and noise features, compare impurity-based feature_importances_ from a random forest against permutation_importance on a held-out test set, and note where they disagree.
Hints:
- Use make_classification with n_informative and n_redundant set and a fixed random_state so feature roles are reproducible.
- Read feature_importances_ directly off the fitted RandomForestClassifier (impurity-based, computed on training data).
- Call permutation_importance(model, X_test, y_test, n_repeats=10, random_state=42) and compare the top-ranked features from each method.
Related Problems on PixelBank
A loan officer must tell a rejected applicant why, and a regulator may require the bank to document that reason. A random forest or neural network can be accurate yet offer no direct answer. Decision trees can: the model itself is a readable diagram, and each prediction is a short chain of conditions. The previous topic, Feature Importance, summarized which features a tree uses overall; this final topic turns to reading the tree itself.
We start with the visualization tools in scikit-learn, plot_tree and export_text, and how to keep a diagram readable. We then trace the decision path behind one prediction, turn paths into if-then rules that can be reviewed or deployed elsewhere, and learn to read the statistics shown inside each node. Next we separate global interpretation, how the model behaves overall, from local interpretation, why it made one decision. Finally we ask when a single interpretable tree is the right choice over a more accurate ensemble, a question that leads into the next chapter.
Definition
Tree visualization renders a fitted tree's structure, its split tests, node statistics, and leaf predictions, so people can inspect it. Interpretation uses that structure globally, to see which features and thresholds drive the model overall, and locally, to explain one prediction through the path of conditions it satisfied from root to leaf.
In this topic
Tree Visualization
Scikit-learn offers three main ways to view a tree. plot_tree draws it with matplotlib, export_graphviz writes a Graphviz file for higher-quality layouts, and export_text prints indented if-then rules that fit in a log or document. Each node shows its split test, impurity, sample count, and class counts or mean value; filled=True colors nodes by majority class and purity. Readability limits what is useful: a diagram of more than about 15 to 30 nodes overwhelms a reader. Use max_depth in plot_tree to show only the top levels, or prune the model itself if the whole tree must be explained.
A visual tree diagram maps directly to the mathematical structure: each internal node shows the split rule , the impurity value, sample count, and class distribution. The visual layout has nodes at depth , so deep trees become unwieldy — a tree with depth 20 has up to leaf nodes. In practice, only the top 3-5 levels are visualized to show the most important splits. sklearn's export_graphviz and plot_tree render the full or truncated structure.
Need to present model to business stakeholders. 50-node tree. Approach?
Decision Path
Every prediction a tree makes follows one root-to-leaf path, and the conditions along it are a complete explanation of that prediction: no other features or weights are involved. In scikit-learn, decision_path returns the nodes visited by each sample and apply returns the leaf it reached, so explanations can be generated automatically. Because each condition names a feature, a threshold, and a direction, the explanation is concrete and checkable. Two caveats: a path shows what the model did, not what would change the decision, and features tested near the root apply to everyone in that branch, not just this applicant.
For a sample , the decision path is the sequence of nodes from root to leaf: where at each node , the model evaluates to choose left or right. The path length equals the tree depth for that sample (at most ). The conjunction of all split conditions along the path gives a complete rule: if AND AND — a fully transparent explanation for the prediction.
Customer denied loan. Path: income>50K?→No, credit>700?→Yes, debt>30K?→Yes→Denied. Explanation?
Rule Extraction
Each root-to-leaf path converts directly into an if-then rule: the conjunction of the conditions on the path, followed by the leaf's prediction. A tree with leaves yields rules that are mutually exclusive and exhaustive, so every input matches exactly one rule. Rules can be reviewed by domain experts, checked against policy, or translated into SQL, spreadsheet logic, or a business rules engine, with no ML library at prediction time. The rule list grows with leaves, so prune first. Thresholds are midpoints chosen from training data, so round them sensibly before presenting them as policy.
Every root-to-leaf path defines a classification rule: where each is an interval. A tree with leaves produces rules that partition the input space. These rules are mutually exclusive (every matches exactly one rule) and exhaustive (every matches some rule). Rules can be exported and deployed without the tree model itself — they are human-readable if-then-else statements.
Path: age≤30 AND income>70K AND score>750 → Approve. Convert to rule.
Interpreting Nodes
Each node in a scikit-learn diagram lists four things. The split test, such as age <= 35, sends samples where it is true to the left child. The impurity, gini or entropy, gives the node's purity. Samples counts the training rows reaching the node, and value lists their class counts, or the mean for regression. Leaves show the same statistics without a test, and their predicted class is the majority in value. Reading down a path, impurity should fall and samples shrink; a leaf with few samples or high impurity is a weak rule. With class_weight set, value may show weighted totals, not raw counts.
Each node contains: (1) split feature and threshold , (2) impurity value (Gini or entropy), (3) sample count , and (4) class distribution . The impurity decreases from root to leaves as splits create purer groups. Sample counts decrease because each split divides samples between children. Nodes with high sample count and high impurity are the most informative splits — they affect the most samples and create the largest purity improvement.
Node: 'age≤35, gini=0.42, samples=200, value=[120,80]'. Interpret.
Global vs Local Interpretation
Interpretability questions come in two kinds. Global questions ask how the model behaves overall: which features matter most, what thresholds it uses, and how complex it is. Tools are feature importance, the top levels of the diagram, and partial dependence plots. Local questions ask why the model made one prediction: tools are the decision path for trees, or SHAP values for any model. The two can disagree: a feature with low global importance can decide a particular case, and vice versa. Match the tool to the question; regulatory explanations of individual decisions require local explanations.
Global interpretation examines the overall tree structure: which features appear near the root (most important), how deep the tree is (complexity), and what regions are created. Local interpretation examines a single prediction: which path was followed, which features mattered, and what the leaf statistics are. Trees provide both naturally. Feature importance is a global summary; the decision path is a local explanation. The gap between global and local matches the gap between average and instance-level behavior.
Boss asks: 'Why did we deny this customer?' vs 'What features matter most overall?'
When Trees Are Best
A single tree is the right model when transparency is a requirement, not a preference: credit decisions, medical triage, and other settings where each decision must be explained, audited, or legally justified. It also fits when the true structure is a handful of thresholds and interactions, when a fast baseline is needed, and when the model will be handed to non-engineers as rules. Elsewhere, single trees usually lose to ensembles in accuracy because of their high variance. Rudin argues that for high-stakes decisions an interpretable model is preferable to explaining a black box after the fact, especially when the accuracy gap is small.
Trees are optimal when: (1) the true boundary is axis-aligned or piecewise constant, (2) feature interactions are hierarchical (can be captured by sequential splits), (3) interpretability is required (medical, legal, financial domains), (4) the dataset has mixed types (numerical + categorical), and (5) no feature engineering budget exists. Trees struggle with smooth diagonal boundaries (need splits), additive relationships (better captured by linear models), and high-variance settings (ensembles are better).
Bank must explain loan denials by law. Random Forest: 92% accuracy. Single tree: 88%. Use which?
Coding Exercise
Problem:
Visualize a decision tree trained on Iris dataset and extract the decision path for a sample.
Hints:
- Use sklearn.tree.plot_tree for visualization
- Use decision_path() method to get the path
- export_text() gives readable rules