Decision Trees from scratch
A random forest is hundreds of decision trees voting together. So before we can understand the forest, we need to understand one tree: how it thinks, how to grow it in R, and the single flaw that makes a forest necessary.
By the end of this lesson you will be able to:
- Explain how a decision tree splits data to make a prediction
- Grow a tree in R and read what it learned
- See, live, why one deep tree overfits, the problem the whole forest exists to fix
Prerequisites: you can run R, and you know what a training and test set are.
A tree is a flowchart of questions
To predict whether a customer churns, a decision tree asks a sequence of yes/no questions and follows the answers down to a verdict. "Is tenure below 8 months? If yes, are monthly charges above 70? If yes, predict churn."
Each question splits the data into two cleaner groups. The tree keeps splitting until each final group (a leaf) is mostly one class, then it predicts that class. The art is choosing which question to ask at each split. The tree below shows exactly that path.
The best split is the purest split
At every node the tree tries every feature and every threshold, and keeps the split that makes the two resulting groups as pure as possible. Purity is measured by Gini impurity: 0 means a group is all one class, 0.5 means a 50/50 mix.
For a node with class proportions \(p_i\), Gini impurity is \(G = 1 - \sum_i p_i^2\). With two classes it simplifies to \(G = 2p(1-p)\): zero when the node is pure (\(p = 0\) or \(p = 1\)) and largest at \(p = 0.5\). A candidate split is scored by the size-weighted Gini of its two children, and the tree keeps the split with the biggest drop from the parent's Gini.
That greed is what makes trees fast to grow, and, as you will see in a moment, what makes a single tree dangerous.
Which split is better?
A node has 8 customers: 4 who churn and 4 who stay (Gini 0.5). Split A makes children {4 churn} and {4 stay}. Split B makes {3 churn, 1 stay} and {1 churn, 3 stay}. Which split does the greedy tree prefer?
Grow one in two lines
First, a small self-contained churn dataset to grow the tree on. Each lesson runs in a fresh R session, so we build the data right here (run this once):
Show answer
library(rpart)
deep <- rpart(churned ~ ., data = train,
control = rpart.control(cp = 0))Watch a tree overfit, live
Here is a real decision tree, fit in your browser on two overlapping groups. Drag the depth slider. Watch the training accuracy climb toward 100% while the test accuracy (the hollow points it never trained on) peaks and then falls as the boundary carves tiny islands around individual noise points.
A shallow tree underfits. A deep tree memorizes. Somewhere in the middle is a sweet spot, but it is narrow and you cannot see it without a test set.
One tree is unstable
A deep tree does not just overfit, it is also fragile. Change a handful of training rows and the greedy splits cascade differently, producing a completely different tree with completely different predictions.
Quick question
You grow a single deep tree and measure it: 100% accuracy on the training data, 71% on the held-out test data. What is happening?
So why ever use a tree?
Because of a beautiful trick. The errors of many different overfit trees tend to cancel out, while the real signal they all pick up reinforces. Average enough diverse trees and the variance collapses, leaving the low bias behind.
That ensemble of trees is the random forest, and building it properly, making the trees different on purpose, is exactly what Lesson 2 is about. Drag the slider below to feel it: average more overfit trees and watch the jagged boundary smooth out while accuracy climbs.
References
A few authoritative places to take this further:
- Breiman (2001), Random Forests, Machine Learning 45(1) - the original paper that defined the method.
- The Elements of Statistical Learning, ch. 9 and 15 (free PDF) - decision trees and forests, with the full math.
- An Introduction to Statistical Learning, ch. 8 (free PDF) - the gentler companion on tree methods.
- rpart vignette: recursive partitioning in R - the package you used to grow a tree here.
Lesson 1 complete
You understand the building block, and precisely why a single tree is not enough. That motivation is the whole point of a forest.
Next, Lesson 2: From one tree to a forest. You will watch averaging crush variance, see why bootstrap samples make trees differ, and meet the one trick that makes a forest beat plain bagging.