---
title: "Individual conditional expectation (ICE) curves"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Individual conditional expectation (ICE) curves}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.width = 6,
  fig.height = 4.5,
  fig.align = "center",
  message = FALSE,
  warning = FALSE
)
```

A partial dependence plot shows the *average* effect of a predictor, which can
mask interesting heterogeneity: if a predictor affects different observations
in different ways (e.g., due to interactions), the average curve may not
represent any individual observation well. *Individual conditional
expectation* (ICE) curves (Goldstein et al., 2015) address this by drawing one
curve per observation; the PDP is just the average of the ICE curves.

## ICE curves

Set `ice = TRUE` in the call to `partial()` (ICE curves are only available for
a single predictor):

```{r ice}
library(pdp)
library(randomForest)

data(boston)
set.seed(101)
boston.rf <- randomForest(cmedv ~ ., data = boston, ntree = 250)

rm.ice <- partial(boston.rf, pred.var = "rm", ice = TRUE, train = boston)
head(rm.ice)  # one row per observation per grid point
```

The result contains a `yhat.id` column identifying which observation each
prediction belongs to. The `plot()` method draws the individual curves along
with their average (the PDP) in red:

```{r ice-plot}
plot(rm.ice, alpha = 0.1, rug = TRUE, train = boston)
```

## Centered ICE (c-ICE) curves

When the curves have very different starting points, it can be hard to judge
whether they are parallel (i.e., no interaction). *Centered* ICE curves force
every curve to start at zero, making heterogeneity in the *shape* of the
curves much easier to see. Either set `center = TRUE` in the call to
`partial()` or center at plotting time:

```{r cice-plot}
plot(rm.ice, center = TRUE, alpha = 0.1)
```

The divergence of the curves for `rm` above roughly 6.5 indicates an
interaction with at least one other predictor.

## User-supplied prediction functions

The `pred.fun` argument gives full control over how predictions are generated.
It must be a function of exactly two arguments---`object` and `newdata`---and
may return a single (aggregated) prediction or one prediction per row of
`newdata`. Whenever multiple predictions per grid point are returned, you get
ICE-style output automatically.

For example, a random forest is an ensemble, so we could display one curve per
*tree* rather than per observation, or compute a trimmed mean instead of the
usual average:

```{r pred-fun}
# 10% trimmed mean instead of the ordinary average
pred.trimmed <- function(object, newdata) {
  mean(predict(object, newdata = newdata), trim = 0.1)
}

pd.trimmed <- partial(boston.rf, pred.var = "rm", pred.fun = pred.trimmed,
                      train = boston)
plot(pd.trimmed)
```

Similarly, `pred.fun` is the natural way to handle models whose `predict()`
methods need special arguments or return unusual structures; see
`vignette("pdp", package = "pdp")` for the simpler built-in behavior.

## References

Goldstein, A., Kapelner, A., Bleich, J., and Pitkin, E. (2015). Peeking inside
the black box: Visualizing statistical learning with plots of individual
conditional expectation. *Journal of Computational and Graphical Statistics*,
**24**(1), 44--65.
