09 — Understand Your Features

Partial Dependence & ICE#

ExplainabilityStatistical 1 min read
◆ The PatternHow does changing one feature affect predictions? PDP shows the average, ICE shows every instance

Partial Dependence Plots (PDP) show the average effect of one feature on predictions, marginalising over all other features. ICE plots show the same for each individual instance — revealing heterogeneity the average hides.

PD(xs) = (1/n) · Σ f(xs, xc(i))
PD = average prediction when feature s is fixed at xs, averaging over all other features.
// Interactive — PDP line with individual ICE curves
Show ICE
Instances20
Interactions: If ICE lines cross each other, there's a feature interaction — the effect of this feature depends on other features' values. A flat PDP with scattered ICE means the average is misleading.
Pattern bridge: A partial-dependence average can hide individual curves pointing the other way — the same trap as Simpson’s paradox. A signal that works on average can likewise fail in exactly the regimes that matter, as correlation risk shows.
Worked example

A model that predicts x₁ × x₂, where x₂ is +1 for half the rows and −1 for the other half. The partial dependence on x₁ is nearly flat — 0.08 … −0.08 across the grid — as if x₁ did nothing. The individual (ICE) curves have slopes of +1 and −1: x₁ matters a lot, in opposite directions. Averages hide interactions; ICE shows them.

Where it misleads
  • PDPs evaluate the model on combinations that may never occur when features are correlated; ALE plots avoid this (Apley & Zhu 2020).
  • A flat PDP is not evidence that a feature is unimportant.
  • Many ICE lines become unreadable; centre them, or cluster them.
In code
rng = np.random.default_rng(5)
x2 = rng.choice([-1.0, 1.0], 1_000)                 # half the rows have x2 = -1, half +1
predict = lambda x1, x2: x1 * x2                     # a pure interaction
grid = np.linspace(-2, 2, 5)
pdp = [predict(g, x2).mean() for g in grid]          # average over the data
ice_slopes = sorted({float(predict(1, v) - predict(0, v)) for v in x2})
Python, in your browser — edit the code and run it again

Assumes import numpy as np and import pandas as pd (and SciPy where imported). Each snippet simulates or makes up its own data, as the comments say.

The same idea with a library
# Python — PDP & ICE
from sklearn.inspection import PartialDependenceDisplay

# PDP with ICE
PartialDependenceDisplay.from_estimator(
    model, X_train,
    features=['age', 'income'],
    kind='both',      # PDP + ICE
    ice_lines_kw={'alpha': 0.1}
)
Sources
  • J. H. Friedman, “Greedy Function Approximation: A Gradient Boosting Machine”, Annals of Statistics 29(5), 2001
  • A. Goldstein, A. Kapelner, J. Bleich & E. Pitkin, “Peeking Inside the Black Box: Visualizing Statistical Learning with Plots of Individual Conditional Expectation”, Journal of Computational and Graphical Statistics 24(1), 2015
  • D. W. Apley & J. Zhu, “Visualizing the Effects of Predictor Variables in Black Box Supervised Learning Models”, Journal of the Royal Statistical Society B 82(4), 2020

Last reviewed October 2026 · How this site checks its content · Report a mistake

Linked from 1
← Previous
Permutation Importance
Open in the full reader, with the topic sidebar