Build a tree by hand

Grow a decision tree on Quinlan's classic weather data one question at a time, with the information gain of every choice in front of you.

BeginnerExplained in Decision trees

Build a tree by hand

Quinlan's 14 weather records, each labeled P or N. Pick a node, then pick the question to ask there; the gain of each choice is computed for you.

  • P (play)
  • N (don't play)

Selected: all 14 records (14)

Mixed (9 P, 5 N). Gain from asking each question:

The 14 records (all)
#outlooktemperaturehumiditywindyclass
1sunnyhothighfalse N
2sunnyhothightrue N
3overcasthothighfalse P
4rainmildhighfalse P
5raincoolnormalfalse P
6raincoolnormaltrue N
7overcastcoolnormaltrue P
8sunnymildhighfalse N
9sunnycoolnormalfalse P
10rainmildnormalfalse P
11sunnymildnormaltrue P
12overcastmildhightrue P
13overcasthotnormalfalse P
14rainmildhightrue N
Impurity measure
Questions0
Leaves1
Leaves still mixed1
Records sorted correctly9 of 14

Challenges

0 of 3 complete

  1. Choose the root question with the largest gain. (not yet)
  2. Build a tree that sorts all 14 records into pure leaves using only 3 questions. (not yet)
  3. Put temperature at the root and still sort all 14 records into pure leaves. (not yet)

Try this

  • At the root, compare the four gains before choosing. Which question would you have guessed?
  • Choose outlook, then select the sunny branch: one question finishes it.
  • Switch to Gini. The numbers change, but does the ranking of questions?
  • Start over with temperature at the root and count how many questions you need.
Information gain on Quinlan's weather dataPython with NumPy
import numpy as np

# Quinlan's 14 weather records: outlook, temperature, humidity, windy, class.
rows = """sunny hot high false N
sunny hot high true N
overcast hot high false P
rain mild high false P
rain cool normal false P
rain cool normal true N
overcast cool normal true P
sunny mild high false N
sunny cool normal false P
rain mild normal false P
sunny mild normal true P
overcast mild high true P
overcast hot normal false P
rain mild high true N"""
data = np.array([r.split() for r in rows.splitlines()])
labels = data[:, 4]

def entropy(y):
    _, counts = np.unique(y, return_counts=True)
    p = counts / counts.sum()
    return -np.sum(p * np.log2(p))

def gain(column):
    # Entropy before the split minus the weighted entropy of each branch.
    after = sum(np.mean(column == v) * entropy(labels[column == v])
                for v in np.unique(column))
    return entropy(labels) - after

print(f"entropy of all 14: {entropy(labels):.3f} bits")
for i, name in enumerate(["outlook", "temperature", "humidity", "windy"]):
    print(f"gain({name}) = {gain(data[:, i]):.3f} bits")
entropy of all 14: 0.940 bits
gain(outlook) = 0.247 bits
gain(temperature) = 0.029 bits
gain(humidity) = 0.152 bits
gain(windy) = 0.048 bits

Try "embedding", "softmax", "overfitting", or "backpropagation".