ML Atlas

Decision Trees

Split data. Ask questions. Reach a conclusion.

BeginnerSupervised
32 min read
Basic probability (conditional probability, entropy concept)Understanding of classification vs. regressionLogarithms (for entropy calculation)
  • Credit risk scoring at banks — explainability requirements make trees mandatory by regulation
  • Medical diagnosis decision support systems (e.g., sepsis alert rules in ICUs)
  • Fraud detection pre-filters before expensive neural network scoring
  • Customer churn classification at telecom and SaaS companies
  • Base learner inside every gradient boosting and random forest model in production
01

In Plain English

A decision tree is a flowchart-like model that repeatedly splits the training data using simple yes/no questions on individual features until each resulting group is as pure as possible (all one class or close to one value).

Why It Exists

Rule-based systems required experts to hand-craft every decision rule — expensive and slow to update. Decision trees automate rule discovery directly from data while preserving full human-readable transparency: you can print the entire model as an if-else chain.

Problem It Solves

Given labeled training data, find an interpretable sequence of feature-based binary splits that partitions the feature space into regions, each assigned a class label (classification) or a predicted value (regression).

Real-Life Analogy

"Think of the game '20 Questions': you ask yes/no questions to narrow down possibilities ('Is it an animal?' → 'Does it have four legs?' → 'Is it a pet?'). Decision trees play this game automatically, choosing each question to maximally reduce uncertainty about the answer."

When To Use

  • You need a fully interpretable, auditable model (regulatory or legal requirements)
  • Data has mixed feature types (numeric and categorical) without extensive preprocessing
  • You need to explain individual predictions to non-technical stakeholders
  • Relationships between features and target are non-linear but can be approximated by axis-aligned splits
  • As a first model before trying ensemble methods — establishes interpretable baseline
  • Feature importance analysis is needed as a quick diagnostic step

When NOT To Use

  • You need the highest possible predictive accuracy — single trees are outclassed by ensembles
  • Data has strong linear relationships — linear regression will generalize better
  • Very high-dimensional data where tree splits become sparse and noisy
  • You need well-calibrated probability estimates — tree leaf probabilities are poorly calibrated
  • Time series prediction where temporal structure must be preserved
02

Imagine you want to classify whether an email is spam. A decision tree might first ask: 'Does the subject line contain the word FREE?' If yes, it routes to the right branch and asks 'Does it come from an unknown sender?' Each question partitions the remaining data into purer groups, reducing uncertainty at every step.

The key insight is how to choose which question to ask and at what threshold. The algorithm evaluates every possible split on every feature and picks the one that produces the most 'pure' child nodes — where pure means all (or mostly) one class. It measures this purity using Gini impurity or entropy from information theory.

Once fully grown, a decision tree memorizes the training data perfectly — every leaf can be a single sample. This is overfitting. The practical power of trees comes from pruning: removing branches that improve training purity only marginally, forcing the model to generalize. Depth control (max_depth), minimum samples per split, and minimum leaf size are the primary levers.

The Metaphor

"A decision tree is a librarian who sorts books by increasingly specific shelves. First by genre, then by author's last name initial, then by year. At each step, the librarian picks the sorting criterion that creates the most uniform groups. Eventually each shelf contains very similar books — that's a pure leaf node."

Beginner Mental Model

Picture the feature space as a rectangular room. Each split cuts the room with a straight line parallel to one axis. After several cuts, you have rectangular regions. Every training point in the same region gets the same prediction. A deeper tree makes more cuts, creating smaller, purer rooms — but eventually you're cutting just for one person, which doesn't generalize.

03

A decision tree T partitions the input space ℝᵈ into M disjoint rectangular regions {R₁, R₂, ..., Rₘ} via a sequence of axis-aligned binary splits. For classification, each region Rₘ is assigned the majority class label cₘ = argmax_k |{i: xᵢ ∈ Rₘ, yᵢ = k}|. For regression, each region is assigned the mean cₘ = (1/|Rₘ|)Σᵢ∈Rₘ yᵢ. The tree is built greedily by CART: at each node, choose feature j and threshold t to minimize the weighted impurity of the two child nodes.

Node
A decision point in the tree that applies a single feature threshold test (xⱼ ≤ t). Root node is the first split; internal nodes are intermediate splits; leaf nodes produce predictions.
Splitting Criterion
The metric used to evaluate the quality of a split — Gini impurity for CART classification, entropy for ID3/C4.5, variance reduction for regression. The best split minimizes the weighted criterion of child nodes.
Gini Impurity
G(node) = 1 − Σₖ pₖ². Measures the probability that two randomly drawn samples from a node have different labels. G=0 means pure (one class), G=0.5 max impurity for binary problems.
Entropy
H(node) = −Σₖ pₖ log₂(pₖ). Measures uncertainty/randomness in a node. H=0 means pure, H=1 means maximum uncertainty for a 2-class problem. Base-2 logarithm gives units of bits.
Information Gain
IG = H(parent) − [n_L/n · H(left) + n_R/n · H(right)]. Reduction in entropy from parent to weighted average of children. ID3/C4.5 maximize this at each split.
Pruning
Removing nodes from a grown tree to reduce overfitting. Pre-pruning stops growth early via constraints (max_depth, min_samples_split). Post-pruning grows fully then removes nodes that don't improve generalization (cost-complexity pruning).
CART
Classification And Regression Trees — Breiman's 1984 algorithm that builds binary trees using Gini impurity for classification and MSE for regression. The basis of sklearn's DecisionTreeClassifier.
Cost-Complexity Pruning (ccp_alpha)
Post-pruning method: R_α(T) = R(T) + α|T|, where R(T) is misclassification rate and |T| is number of leaves. Increasing α prunes more aggressively. Cross-validate over α values.
  1. 1. Start at the root with all training data.
  2. 2. For every feature j and every possible split threshold t, compute the weighted impurity of the resulting left (xⱼ ≤ t) and right (xⱼ > t) child nodes.
  3. 3. Select the (j*, t*) pair that yields the lowest weighted impurity (largest information gain).
  4. 4. Split the node: create left child with samples satisfying xⱼ* ≤ t* and right child with the rest.
  5. 5. Recursively repeat steps 2–4 on each child node.
  6. 6. Stop when a stopping criterion is met: max_depth reached, node has fewer than min_samples_split samples, or all samples in the node have the same label.
  7. 7. Assign each leaf: majority class (classification) or mean target value (regression).
  8. 8. Optionally: apply cost-complexity pruning by sweeping over ccp_alpha values with cross-validation.

Feature matrix X ∈ ℝⁿˣᵈ with numeric or categorical features (after encoding). Target y ∈ {0,...,K-1}ⁿ for classification or y ∈ ℝⁿ for regression.

Classification: predicted class label ŷ ∈ {0,...,K-1} and class probabilities from leaf node class frequencies. Regression: predicted real value ŷ ∈ ℝ from leaf node mean.

01No distribution assumptions: decision trees are non-parametric — they make no assumption about the shape of the data distribution.
02Splits are axis-aligned: the model can only make cuts perpendicular to feature axes. Diagonal decision boundaries require many splits or feature engineering.
03Greedy optimality: the locally optimal split at each node is not guaranteed to produce the globally optimal tree (NP-hard problem). CART's greedy approach is an approximation.
04Features are informative: if all features are noise, the tree will still grow but capture only random patterns.
  • All features constant: no split improves impurity. Tree degenerates to a root node predicting majority class.
  • Single sample per leaf: perfectly pure leaves, R²=1.0 on training, complete overfit. Control with min_samples_leaf.
  • Features with missing values: CART handles missing values via surrogate splits (sklearn does not; impute first).
  • Highly imbalanced classes: tree tends to predict majority class. Use class_weight='balanced' to adjust split criterion.
  • Identical feature values, different labels: irreducible error — node cannot be further purified by any split on that feature.
04

Decision trees sit after data cleaning and encoding but require minimal preprocessing — no scaling needed. They serve as interpretable standalone models or as base learners in ensemble methods (Random Forest, Gradient Boosting). Feature importance from a single tree is a quick diagnostic before committing to complex pipelines.

  • 01.Encode categorical features: OrdinalEncoder for ordinal categories, or leave as integers if sklearn's tree can handle them. One-hot encoding works but increases dimensionality unnecessarily for trees.
  • 02.Handle missing values: sklearn's CART does not natively support missing values. Use SimpleImputer (mean/median for numeric, most_frequent for categorical) before fitting.
  • 03.Feature scaling: NOT required. Trees split on thresholds, not distances. StandardScaler has zero effect on tree structure.
  • 04.Outliers: trees are robust to outliers in numeric features — an extreme value simply shifts one split threshold. No winsorization needed.
  • 05.Class imbalance: set class_weight='balanced' or use sample_weight. Without this, the tree optimizes for majority class and ignores rare classes.
  • 01.Set initial hyperparameters conservatively: max_depth=5, min_samples_leaf=10 to avoid extreme overfitting.
  • 02.Fit on training data: model.fit(X_train, y_train). Training is O(n·d·log(n)) — fast even for large datasets.
  • 03.Inspect tree structure: use export_text or plot_tree to verify the tree makes domain sense.
  • 04.Evaluate on validation set: accuracy/F1 for classification, RMSE/R² for regression.
  • 05.Tune via cross-validation: grid search over max_depth, min_samples_split, min_samples_leaf, ccp_alpha.
  • 06.Apply cost-complexity pruning: compute ccp_alpha path with cost_complexity_pruning_path, cross-validate.
  • 07.Check feature importances: model.feature_importances_ gives Gini-based importance for each feature.

max_depth

Maximum depth of the tree. Each additional level exponentially increases the number of possible leaf nodes (2^depth leaves maximum).

3–10 for interpretability, None for ensemble base learners

min_samples_split

Minimum number of samples required to split an internal node. A node with fewer samples is declared a leaf.

2 (default) for ensembles, 20–50 for standalone use

min_samples_leaf

Minimum number of samples required to be at a leaf node. Both resulting child nodes must have at least this many samples after a split.

1 (default), 5–20 for real datasets

max_features

Number of features to consider when looking for the best split. Relevant when using as a standalone model (usually None = all features).

None for standalone, sqrt(d) for Random Forest usage

ccp_alpha

Complexity parameter for Minimal Cost-Complexity Pruning. Larger values prune more branches.

0.0 (no pruning, default), tune via cross-validation over the alpha path

  1. 1pip install scikit-learn numpy matplotlib
  2. 2Load and explore data: check class distribution, feature types, missing values
  3. 3Preprocess: impute missing values, encode categoricals (OrdinalEncoder or OHE)
  4. 4Train/test split: train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)
  5. 5Fit baseline: DecisionTreeClassifier(max_depth=5, random_state=42).fit(X_train, y_train)
  6. 6Visualize: plot_tree(model, feature_names=..., class_names=..., filled=True)
  7. 7Tune: GridSearchCV over max_depth, min_samples_leaf, ccp_alpha
  8. 8Evaluate: classification_report(y_test, y_pred) for classification
05
06
python
1import numpy as np
2from collections import Counter
3
4class Node:
5    """A node in the decision tree."""
6    def __init__(self, feature=None, threshold=None, left=None, right=None, value=None):
7        self.feature = feature        # Feature index to split on
8        self.threshold = threshold    # Split threshold
9        self.left = left              # Left subtree (x[feature] <= threshold)
10        self.right = right            # Right subtree (x[feature] > threshold)
11        self.value = value            # Prediction (leaf nodes only)
12
13    def is_leaf(self):
14        return self.value is not None
15
16
17class DecisionTreeClassifier:
18    def __init__(self, max_depth=10, min_samples_split=2, criterion="gini"):
19        self.max_depth = max_depth
20        self.min_samples_split = min_samples_split
21        self.criterion = criterion    # "gini" or "entropy"
22        self.root = None
23
24    # ── Impurity Measures ──────────────────────────────────────────────────────
25    def _gini(self, y):
26        n = len(y)
27        if n == 0:
28            return 0.0
29        counts = np.bincount(y)
30        probs = counts / n
31        return 1.0 - np.sum(probs ** 2)
32
33    def _entropy(self, y):
34        n = len(y)
35        if n == 0:
36            return 0.0
37        counts = np.bincount(y)
38        probs = counts[counts > 0] / n          # Avoid log(0)
39        return -np.sum(probs * np.log2(probs))
40
41    def _impurity(self, y):
42        return self._gini(y) if self.criterion == "gini" else self._entropy(y)
43
44    def _information_gain(self, y, y_left, y_right):
45        """Impurity reduction from splitting y into y_left and y_right."""
46        n = len(y)
47        weighted_child = (len(y_left) / n) * self._impurity(y_left) +                          (len(y_right) / n) * self._impurity(y_right)
48        return self._impurity(y) - weighted_child
49
50    # ── Best Split Search ──────────────────────────────────────────────────────
51    def _best_split(self, X, y):
52        best_gain = -1
53        best_feature, best_threshold = None, None
54
55        for feature_idx in range(X.shape[1]):
56            thresholds = np.unique(X[:, feature_idx])
57            # Candidate thresholds: midpoints between consecutive unique values
58            candidates = (thresholds[:-1] + thresholds[1:]) / 2
59
60            for t in candidates:
61                mask_left = X[:, feature_idx] <= t
62                y_left, y_right = y[mask_left], y[~mask_left]
63
64                if len(y_left) == 0 or len(y_right) == 0:
65                    continue
66
67                gain = self._information_gain(y, y_left, y_right)
68                if gain > best_gain:
69                    best_gain = gain
70                    best_feature = feature_idx
71                    best_threshold = t
72
73        return best_feature, best_threshold, best_gain
74
75    # ── Tree Building ──────────────────────────────────────────────────────────
76    def _build_tree(self, X, y, depth=0):
77        n_samples = len(y)
78        n_classes = len(np.unique(y))
79
80        # Stopping conditions
81        if (depth >= self.max_depth or
82                n_samples < self.min_samples_split or
83                n_classes == 1):
84            # Leaf node: majority class vote
85            leaf_value = Counter(y).most_common(1)[0][0]
86            return Node(value=leaf_value)
87
88        # Find best split
89        feature, threshold, gain = self._best_split(X, y)
90
91        if gain <= 0 or feature is None:
92            leaf_value = Counter(y).most_common(1)[0][0]
93            return Node(value=leaf_value)
94
95        # Partition data
96        mask_left = X[:, feature] <= threshold
97        left_subtree = self._build_tree(X[mask_left], y[mask_left], depth + 1)
98        right_subtree = self._build_tree(X[~mask_left], y[~mask_left], depth + 1)
99
100        return Node(feature=feature, threshold=threshold,
101                    left=left_subtree, right=right_subtree)
102
103    def fit(self, X, y):
104        self.root = self._build_tree(np.array(X), np.array(y))
105        return self
106
107    def _traverse(self, x, node):
108        if node.is_leaf():
109            return node.value
110        if x[node.feature] <= node.threshold:
111            return self._traverse(x, node.left)
112        return self._traverse(x, node.right)
113
114    def predict(self, X):
115        return np.array([self._traverse(x, self.root) for x in np.array(X)])
116
117    def score(self, X, y):
118        return np.mean(self.predict(X) == np.array(y))
119
120
121# ── Demo ───────────────────────────────────────────────────────────────────────
122from sklearn.datasets import load_iris
123from sklearn.model_selection import train_test_split
124
125X, y = load_iris(return_X_y=True)
126X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
127
128tree = DecisionTreeClassifier(max_depth=4, criterion="gini")
129tree.fit(X_train, y_train)
130print(f"Train accuracy: {tree.score(X_train, y_train):.4f}")
131print(f"Test  accuracy: {tree.score(X_test, y_test):.4f}")
132# Expected: ~0.97 train, ~0.97 test on Iris
The from-scratch implementation shows the core recursive structure: _best_split iterates over all (feature, threshold) pairs computing information gain, _build_tree recursively partitions data stopping at depth/purity limits, and prediction traverses the built tree. The threshold candidates use midpoints between consecutive unique values — the standard CART approach.
X = [[2.5, 1.0], [3.0, 4.5], [1.0, 2.0], [4.0, 3.0]]  # 2 features
y = [0, 1, 0, 1]  # binary classes
Split: feature 0 <= 2.75 → left (class 0), right (feature 1 <= 3.75) → left (class 0), right (class 1)
Train accuracy: 1.0000
Test  accuracy: 0.9500 (typical Iris-scale dataset)
  • Feature importance from CART = sum of weighted Gini gain across all nodes where that feature is used. It measures 'how much each feature reduces impurity across the full tree', not how high the feature appears.
  • Cost-complexity pruning (ccp_alpha) is the most principled post-pruning method. Always compare pruned vs. unpruned on a held-out set — the improvement can be dramatic.
  • Decision trees are invariant to monotonic transformations of features (log, square root, standardization). A tree on X and log(X) makes identical splits — only threshold values change.
  • For imbalanced classes, set class_weight='balanced'. This upweights the impurity of the minority class in the splitting criterion, preventing the tree from ignoring rare classes.
  • The tree's predict_proba() outputs raw leaf class frequencies — often poorly calibrated. Use CalibratedClassifierCV if you need well-calibrated probability estimates.
  • Not pruning the tree — a fully grown tree always overfits. max_depth=3 is often a better starting point than max_depth=None.
  • Interpreting feature_importances_ without accounting for cardinality bias — features with many unique values appear more important because they have more split opportunities.
  • Using train accuracy to select depth — always use cross-validation or a held-out validation set.
  • Forgetting to stratify the train/test split for imbalanced datasets.
  • Using predict_proba() outputs as calibrated probabilities for downstream decisions — they are class frequencies, not calibrated probabilities.
07
📊

Small Tabular Dataset (< 1K rows)

Good

Trees work but risk overfitting without careful pruning. With small data, even min_samples_leaf=10 can leave leaves with few samples. Use cross-validation instead of hold-out.

💡 max_depth=3–5 and min_samples_leaf=5–10 are critical constraints for small datasets.
🗄️

Large Tabular Dataset (> 100K rows)

Good

Training is O(n·d·log(n)) — manageable even at 1M rows. The tree structure doesn't benefit much beyond a certain depth once leaves have many pure samples.

💡 For very large datasets, consider max_leaf_nodes instead of max_depth for a more budget-oriented constraint.
🔀

Mixed Feature Types (Numeric + Categorical)

Excellent

Decision trees handle mixed types natively better than most models. Numeric features get threshold splits; categorical features get subset splits. Minimal encoding needed.

💡 Use OrdinalEncoder for sklearn compatibility. True categorical support (like CatBoost or R's rpart) is even better.
⚖️

Imbalanced Dataset

Context-Dependent

Without class balancing, trees become majority-class predictors. With class_weight='balanced', they handle imbalance acceptably. Still outclassed by ensemble methods on severely imbalanced data.

💡 Combine class_weight='balanced' with F1 or AUC evaluation metrics, not accuracy.
📐

High-Dimensional Dataset (d >> 100 features)

Poor

Trees become unstable with many features — many random splits look equally good, and the chosen splits vary significantly with small data changes. High variance, poor generalization.

💡 Use Random Forest or feature selection first. Single trees in high dimensions are unreliable.
📉

Noisy Dataset

Poor

Unpruned trees memorize noise in training data. Even with pruning, trees are sensitive to label noise because noisy samples at key split points can redirect entire subtrees.

💡 Robust alternative: Random Forest averages out noise. Consider label noise cleaning before fitting a single tree.
08

Interactive: Split Boundary, Tree Depth, and Overfit Risk

Train error

0.37

Test error

0.23

Risk

Controlled

Classification Boundary: Decision Tree Regions

Decision tree classification boundaries are always axis-aligned rectangles in 2D feature space. Each color region is a leaf node. More depth = more rectangular subdivisions. Compare to a smooth boundary from logistic regression or SVM.

Render as 2D scatter plot with colored rectangular decision regions. Vertical line at x=2.6 represents the first split (root node). Horizontal line at y=2.5 (left region only) represents the second split. Each resulting rectangle is a leaf node — all points in it get the same prediction.

Impurity Decrease per Split (Node Importance)

Each bar represents one decision node in the tree. Height = weighted Gini impurity decrease from that split. Root node always shows the largest decrease. Leaf contributions are zero (they don't split). This is the raw signal behind feature_importances_.

Comparison visualization data is documented in this section.

Train vs. Test Accuracy by Tree Depth

Classic bias-variance trade-off curve for decision trees. Training accuracy monotonically increases with depth (can reach 100%). Test accuracy peaks at an intermediate depth then decreases as the tree overfits. The gap between curves shows the generalization gap.

Gradient descent convergence — MSE decreasing over iterations

09
  • Complete interpretability and transparency

    Every prediction can be traced through an explicit sequence of if-else rules. export_text() prints the entire model as human-readable rules. Regulators, auditors, and domain experts can verify the model's logic. No other high-performance ML model matches this level of transparency.

  • No feature preprocessing required

    Decision trees are invariant to feature scaling, monotonic transformations, and outliers in feature values. Raw features work as-is. Categorical features need minimal encoding. This dramatically reduces the data preprocessing pipeline compared to distance-based or gradient-based models.

  • Handles non-linear relationships natively

    Unlike linear regression, trees can model arbitrary non-linear decision boundaries by composing multiple splits. A 5-deep tree has up to 32 leaf regions, each with independent predictions — a powerful non-linear approximator without any feature engineering.

  • Built-in feature selection via importance scores

    feature_importances_ quantifies each feature's contribution to reducing impurity across the full tree. Features with zero importance can be safely removed. This is a free diagnostic for every tree fit.

  • Fast inference at prediction time

    Prediction requires traversing at most max_depth nodes: O(max_depth) = O(log n) for a balanced tree. A depth-10 tree takes at most 10 comparisons per prediction — microsecond latency even on embedded hardware.

  • Foundation for powerful ensembles

    Decision trees are the base learner for Random Forest and all gradient boosting variants (XGBoost, LightGBM, CatBoost). Understanding trees deeply is prerequisite to understanding these state-of-the-art methods.

  • High variance — unstable to small data changes

    A small change in training data (removing a few samples, changing a label) can completely restructure the tree. This instability is the fundamental motivation for bagging (Random Forests) — averaging many unstable trees to produce a stable prediction.

  • Prone to overfitting without pruning

    An unpruned tree will memorize every training sample, achieving 100% training accuracy while failing on test data. Effective pruning (depth constraints, ccp_alpha) is mandatory but requires careful cross-validation tuning.

  • Biased toward high-cardinality features

    Features with many unique values (or many levels) get more split opportunities and appear artificially important in feature_importances_. This affects both model structure (biased splits) and interpretation (misleading importance). Partial fix: use 'permutation importance' from sklearn.inspection.

  • Cannot extrapolate beyond training data range

    Decision trees predict the mean or majority class of a training leaf — they cannot predict values outside the range seen during training. A regression tree trained on house prices up to $1M will cap predictions at the highest-value leaf, regardless of features.

  • Poor probability calibration

    Leaf class probabilities are raw frequency counts from training data — systematically over-confident for pure leaves and poorly calibrated overall. Never use raw tree probabilities for risk-sensitive decisions without post-hoc calibration (Platt scaling or isotonic regression).

10
Finance / Banking

Credit scoring rules

Regulatory requirements (GDPR Article 22, US Equal Credit Opportunity Act) mandate that adverse lending decisions be explained to applicants. Decision trees produce human-readable rules: 'Denied because income < $35K AND debt-to-income ratio > 0.45.' Fully auditable, legally defensible.

Healthcare

Clinical decision support

Sepsis alert systems, ICU triage tools, and diagnostic pathways use decision trees because doctors can read and validate the if-else logic directly. A misclassification must be explainable, not just accurate.

E-Commerce

Customer segmentation for targeted offers

Tree-based rules segment customers: 'High-value AND repeat_purchases > 3 → Premium tier.' Business analysts can read and override the rules, enabling collaboration between data science and marketing without a black box.

Manufacturing

Fault diagnosis and root cause analysis

Decision trees trained on sensor readings identify which operating conditions lead to equipment failures. The resulting rules guide field engineers directly: 'If vibration > 12mm/s AND temperature > 85°C → bearing failure likely.'

Cybersecurity

Intrusion detection rule extraction

Security analysts train trees on network traffic features to identify attack patterns, then export the rules as firewall signatures or SIEM detection rules — converting ML into auditable, deployable security policy.

Insurance

Risk classification for underwriting

Underwriters use tree-derived rules to classify policies into risk tiers. The explicit rule structure allows human review, regulatory compliance, and easy updating when risk factors change (e.g., post-COVID reassessment).

11

Decision trees sit at the intersection of interpretable models and flexible non-linear classifiers. Here's how they compare to their most relevant alternatives:

Random Forest

Built entirely from decision trees; same splitting criteria

Averages hundreds of trees trained on bootstrap samples with random feature subsets. Dramatically reduces variance at the cost of interpretability — you can no longer read the model as rules.

When prediction accuracy matters more than individual rule interpretability. Random Forest is almost always more accurate than a single tree.

Logistic Regression

Both are binary classifiers; both produce class probabilities

Logistic regression produces a smooth linear decision boundary — better calibrated probabilities and better extrapolation, but cannot capture non-linear patterns without feature engineering.

When the relationship is approximately linear, you need well-calibrated probabilities, or regularization (L1/L2) is important. Trees win when features are mixed type or relationships are non-linear.

Gradient Boosting (XGBoost)

Ensemble of decision trees; uses same Gini/entropy criteria at each node

Fits trees sequentially on residuals of previous trees. Combines hundreds of weak (shallow) trees. Far more accurate than single trees, but slower to train and requires more hyperparameter tuning.

For maximum tabular data accuracy in production. A single decision tree when you need an interpretable, auditable model that can be exported as rules.

k-Nearest Neighbors (kNN)

Both are non-parametric, non-linear classifiers with no distributional assumptions

kNN uses all training data at prediction time (O(n) per prediction), stores no explicit model structure, and is sensitive to feature scaling. Trees use O(depth) per prediction and store explicit rules.

Trees when prediction speed matters or when rules need to be exported. kNN when you have very few training samples and a complex manifold structure.

PropertyDecision TreeRandom ForestLogistic Reg.XGBoost
Interpretable rules✓ Full✗ NoPartial✗ No
Handles non-linearity✓ Yes✓ Yes✗ No✓ Yes
Feature preprocessingNone neededNone neededRequiredNone needed
Overfitting riskHigh (prune!)LowLowMedium
Training speedFastModerateFastSlower
Prediction speed⚡ O(depth)Moderate⚡ O(d)Moderate
Handles imbalanceWith weightsWith weightsWith weightsWith weights

You need an interpretable, auditable model whose predictions can be expressed as explicit if-else rules, are working with mixed feature types, or need a strong baseline before trying ensembles.

12

Accuracy

Fraction of correctly classified samples. Misleading for imbalanced datasets — a model predicting all majority class can have 95% accuracy on a 95-5 split.

Target: Dataset-dependent; always compare to majority-class baseline

F1 Score (weighted)

Harmonic mean of precision and recall. Weighted F1 accounts for class imbalance by weighting each class by its support. Use this instead of accuracy for imbalanced datasets.

Target: > 0.85 for most production classification tasks

AUC-ROC

Area under the ROC curve. Measures the model's ability to discriminate between classes across all decision thresholds. AUC=0.5 means random, AUC=1.0 means perfect. Threshold-independent — useful for comparing models.

Target: > 0.85 for medical/finance applications; > 0.75 acceptable for many use cases

Gini Impurity of Leaves

Weighted average Gini impurity across all leaf nodes. A pure tree has 0.0 — every leaf is one class. Lower is better. Useful for monitoring during pruning.

Target: < 0.05 for well-pruned trees on clean data

  1. 01.1. Always use stratified train/test split (stratify=y) to preserve class distribution.
  2. 02.2. Evaluate accuracy AND F1/AUC — never just accuracy for imbalanced classes.
  3. 03.3. Use 5-fold stratified cross-validation for small datasets instead of a single split.
  4. 04.4. Plot the depth vs. test accuracy curve — identify the knee point for optimal depth.
  5. 05.5. Inspect the confusion matrix — understand which classes are confused and why.
  6. 06.6. Read the exported tree rules — verify they make domain sense before deployment.
  7. 07.7. Compare feature importances across multiple random seeds — stable importances are trustworthy; variable ones indicate collinear features.
  • Evaluating on training data — a fully grown tree always has 100% train accuracy, which is meaningless.
  • Using accuracy on imbalanced datasets — always report F1, AUC, and the confusion matrix.
  • Selecting max_depth based on a single train/test split — use k-fold CV, especially for small datasets.
  • Trusting feature importances from a single tree — they're unstable. Use permutation importance or Random Forest importance for reliability.

Breast cancer classifier: Accuracy=96.5%, F1=0.965, AUC=0.978. Confusion matrix shows 2 false negatives (malignant predicted as benign) — in this domain, false negatives are more dangerous than false positives. Consider lowering the decision threshold or using a higher-recall model variant. The tree's top split on 'worst radius ≤ 16.8' aligns with clinical knowledge that tumor size is a primary diagnostic indicator.

13
  • ×Not pruning the tree — a fully grown tree on any dataset achieves 100% training accuracy, which students mistake for a great model.
  • ×Confusing information gain with entropy — IG is the reduction in entropy, not entropy itself.
  • ×Thinking feature_importances_ is the same as correlation with the target — importance measures impurity reduction, not linear relationship strength.
  • ×Applying decision trees to time series without understanding that trees cannot model temporal order or trend.
  • ×Using the default DecisionTreeClassifier() without any depth/leaf constraints — always set max_depth or min_samples_leaf.
  • ×Relying on a single train/test split to select hyperparameters — leads to high-variance model selection; use GridSearchCV with cv=5.
  • ×Not checking class imbalance before fitting — trees silently predict majority class without class_weight='balanced'.
  • ×Deploying without checking that tree rules make domain sense — a tree may fit data statistically while violating known domain constraints.
  • ×Saying 'Gini is better than entropy' — in practice they produce nearly identical trees. The difference is rarely worth the debate.
  • ×Not knowing what information gain is biased toward — high-cardinality features appear more important even when they're not.
  • ×Saying trees 'require feature scaling' — they absolutely do not. This is a common confusion with gradient-based models.
  • ×Not explaining the bias-variance trade-off in depth control — deeper trees have lower bias but higher variance; shallower trees generalize better.
  • ×Using a single decision tree in production when an ensemble would give dramatically better accuracy with minimal added complexity.
  • ×Not handling missing values before fitting — sklearn's tree will throw errors or produce incorrect results with NaN features.
  • ×Ignoring the cardinality bias in feature_importances_ when selecting features for downstream engineering.
  • ×Not recalibrating predict_proba() outputs — leaf class frequencies are not calibrated probabilities and can cause poor decisions in probabilistic pipelines.
14

What kind of bias does this model have?

Shallow trees show moderate-to-high bias. Deeper trees reduce bias quickly.

What kind of variance does it have?

Single deep trees can have high variance; ensembles reduce this variance.

How does it overfit?

Overfitting usually appears as strong train performance but weaker validation/test behavior.

How do we regularize it?

Use depth limits, min-samples constraints, and ensemble averaging.

What kind of data does it like?

Prefers representative, low-leakage data with stable feature definitions.

What kind of data breaks it?

Breaks under leakage, severe distribution drift, noisy labels, and poorly engineered features.

14

Quick Revision Reference

  • Greedily splits data on the feature+threshold that maximally reduces impurity (Gini or entropy)
  • CART uses Gini impurity and produces binary splits; ID3/C4.5 use entropy/information gain
  • Gini = 1 − Σpₖ²; Entropy = −Σpₖlog₂(pₖ); Information Gain = H(parent) − weighted H(children)
  • Without pruning, trees perfectly overfit training data (100% train accuracy, poor test accuracy)
  • Pruning methods: pre-pruning (max_depth, min_samples_leaf) and post-pruning (ccp_alpha/cost-complexity pruning)
  • Feature importances = sum of weighted Gini gain across all nodes where feature is used
  • Trees are invariant to feature scaling, outliers in feature values, and monotonic transformations
  • Foundation for Random Forest (bagging) and Gradient Boosting (sequential residual fitting)
Gini Impurity
Entropy
Information Gain
Gini Gain (CART)
Pruning Criterion
  • Interpretable models that must be audited or explained
  • Mixed feature types without preprocessing overhead
  • Quick feature importance diagnostics
  • Base learner for Random Forest and Gradient Boosting
  • Maximum predictive accuracy is needed (use Random Forest or GBM)
  • Data is high-dimensional with many noise features
  • Well-calibrated probabilities are required without post-hoc calibration
  • Extrapolation beyond the training data range is needed (regression)
Derive Gini impurity and entropy — know their formulas and interpretation
Explain information gain and why it's biased toward high-cardinality features
Compare CART vs. ID3 vs. C4.5 — splitting criteria and tree structure differences
Explain pre-pruning vs. post-pruning with cost-complexity pruning (ccp_alpha)
Why are single decision trees high-variance? How does Random Forest fix this?
15
16

These questions are designed to break assumptions and expose weak understanding. Most people will answer them wrong on their first attempt. Work through each one carefully.