Skip to content

ICE Explainer

interpretation.explainer.agnostic.ice.ICEExplainer

Bases: AgnosticExplainer

Source code in interpretation/explainer/agnostic/ice.py
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
class ICEExplainer(AgnosticExplainer):
    def __init__(self, input_model, input_data):
        super().__init__(input_model)
        self.data = input_data

    def explain(
        self, 
        X: npt.NDArray, 
        feature_idx: int = None, 
        n_grid: int = 50,
        centered: bool = True
    ) -> npt.NDArray:
        """Computes the ICE result for a single row

        Parameters
        ----------
        X : npt.NDArray
            Data point to explain.
        feature_idx : int
            Column index of the feature to explain.
        n_grid : int, optional
            Number of data points generated for the ICE explanation, by default 50.
        centered: bool, optional
            Centering so that all explanations start at the same point

        Returns
        -------
        npt.NDArray
            Model predictions for all ICE data points.

        Raises
        ------
        TypeError
            If X is not a numpy array.
        ValueError
            If X is not two-dimensional.
        """

        X = validate_input_2d(X)

        if feature_idx is not None:
            return self._compute_ice(X, feature_idx, n_grid, centered)
        else:
            ice_results = []
            for feature_idx in range(X.shape[-1]):
                result = self._compute_ice(X, feature_idx, n_grid, centered)
                ice_results.append(result)

            return np.array(ice_results)


    def plot(
        self, 
        X: npt.NDArray,
        feature_idx: int, 
        output_idx: int = 0, 
        n_grid: int = 50,
        ax: Axes = None,
        feature_name: str = None,
        centered: bool = True
    ) -> Axes:
        """Produce visual ICE plots for a given feature and output index

        Parameters
        ----------
        X : npt.NDArray
            All data points to explain.
        feature_idx : int
            Column index of the feature to explain.
        output_idx : int
            Since model may have multiple outputs (e.g. multi-class), an index of the output to explain can be specified.
        n_grid : int, optional
            Number of data points generated for the ICE explanation, by default 50.
        ax : Axes, optional
            Axes on which to draw the plot. If None, a new figure and axes are created., by default None
        feature_name : str, optional
            Name of the feature, used for labelling the x-axis, by default None
        centered: bool, optional
            Centering so that all explanations start at the same point

        Returns
        -------
        Axes
            The axes containing the ICE plot.

        Raises
        ------
        TypeError
            If X is not a numpy array.
        ValueError
            If X is not two-dimensional.
        """

        X = validate_input_2d(X)

        X_ice = self.explain(X, feature_idx, n_grid, centered)

        xj = self.data[:, feature_idx]
        min_xj, max_xj = xj.min(), xj.max()

        grid = np.linspace(min_xj, max_xj, n_grid, dtype=X.dtype)

        if ax is None:
            _, ax = plt.subplots()

        X_ice = X_ice[:, :, output_idx] if X_ice.ndim == 3 else X_ice

        ax.plot(grid, X_ice.T)
        ax.grid()
        ax.set_xlabel(feature_name)
        ax.set_ylabel("Prediction")
        ax.set_title("ICE Plot")

        return ax


    def _compute_ice(self, X, feature_idx, n_grid, centered):
        """Used for computing all model predictions for one varying feature for all data points"""
        xj = self.data[:, feature_idx]
        min_xj, max_xj = xj.min(), xj.max()

        grid = np.linspace(min_xj, max_xj, n_grid, dtype=X.dtype)

        n_samples = X.shape[0]
        X_ice = np.repeat(X, n_grid, axis=0)
        X_ice[:, feature_idx] = np.tile(grid, n_samples)

        pred = self.model(X_ice)

        if pred.ndim == 1:
            pred = pred.reshape(n_samples, n_grid)
        else:
            pred = pred.reshape(n_samples, n_grid, pred.shape[-1])

        if centered:
            if pred.ndim == 2:
                pred = pred - pred[:, [0]]
            else:
                pred = pred - pred[:, [0], :]

        return pred

explain(X, feature_idx=None, n_grid=50, centered=True)

Computes the ICE result for a single row

Parameters:

Name Type Description Default
X NDArray

Data point to explain.

required
feature_idx int

Column index of the feature to explain.

None
n_grid int

Number of data points generated for the ICE explanation, by default 50.

50
centered bool

Centering so that all explanations start at the same point

True

Returns:

Type Description
NDArray

Model predictions for all ICE data points.

Raises:

Type Description
TypeError

If X is not a numpy array.

ValueError

If X is not two-dimensional.

Source code in interpretation/explainer/agnostic/ice.py
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
def explain(
    self, 
    X: npt.NDArray, 
    feature_idx: int = None, 
    n_grid: int = 50,
    centered: bool = True
) -> npt.NDArray:
    """Computes the ICE result for a single row

    Parameters
    ----------
    X : npt.NDArray
        Data point to explain.
    feature_idx : int
        Column index of the feature to explain.
    n_grid : int, optional
        Number of data points generated for the ICE explanation, by default 50.
    centered: bool, optional
        Centering so that all explanations start at the same point

    Returns
    -------
    npt.NDArray
        Model predictions for all ICE data points.

    Raises
    ------
    TypeError
        If X is not a numpy array.
    ValueError
        If X is not two-dimensional.
    """

    X = validate_input_2d(X)

    if feature_idx is not None:
        return self._compute_ice(X, feature_idx, n_grid, centered)
    else:
        ice_results = []
        for feature_idx in range(X.shape[-1]):
            result = self._compute_ice(X, feature_idx, n_grid, centered)
            ice_results.append(result)

        return np.array(ice_results)

plot(X, feature_idx, output_idx=0, n_grid=50, ax=None, feature_name=None, centered=True)

Produce visual ICE plots for a given feature and output index

Parameters:

Name Type Description Default
X NDArray

All data points to explain.

required
feature_idx int

Column index of the feature to explain.

required
output_idx int

Since model may have multiple outputs (e.g. multi-class), an index of the output to explain can be specified.

0
n_grid int

Number of data points generated for the ICE explanation, by default 50.

50
ax Axes

Axes on which to draw the plot. If None, a new figure and axes are created., by default None

None
feature_name str

Name of the feature, used for labelling the x-axis, by default None

None
centered bool

Centering so that all explanations start at the same point

True

Returns:

Type Description
Axes

The axes containing the ICE plot.

Raises:

Type Description
TypeError

If X is not a numpy array.

ValueError

If X is not two-dimensional.

Source code in interpretation/explainer/agnostic/ice.py
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
def plot(
    self, 
    X: npt.NDArray,
    feature_idx: int, 
    output_idx: int = 0, 
    n_grid: int = 50,
    ax: Axes = None,
    feature_name: str = None,
    centered: bool = True
) -> Axes:
    """Produce visual ICE plots for a given feature and output index

    Parameters
    ----------
    X : npt.NDArray
        All data points to explain.
    feature_idx : int
        Column index of the feature to explain.
    output_idx : int
        Since model may have multiple outputs (e.g. multi-class), an index of the output to explain can be specified.
    n_grid : int, optional
        Number of data points generated for the ICE explanation, by default 50.
    ax : Axes, optional
        Axes on which to draw the plot. If None, a new figure and axes are created., by default None
    feature_name : str, optional
        Name of the feature, used for labelling the x-axis, by default None
    centered: bool, optional
        Centering so that all explanations start at the same point

    Returns
    -------
    Axes
        The axes containing the ICE plot.

    Raises
    ------
    TypeError
        If X is not a numpy array.
    ValueError
        If X is not two-dimensional.
    """

    X = validate_input_2d(X)

    X_ice = self.explain(X, feature_idx, n_grid, centered)

    xj = self.data[:, feature_idx]
    min_xj, max_xj = xj.min(), xj.max()

    grid = np.linspace(min_xj, max_xj, n_grid, dtype=X.dtype)

    if ax is None:
        _, ax = plt.subplots()

    X_ice = X_ice[:, :, output_idx] if X_ice.ndim == 3 else X_ice

    ax.plot(grid, X_ice.T)
    ax.grid()
    ax.set_xlabel(feature_name)
    ax.set_ylabel("Prediction")
    ax.set_title("ICE Plot")

    return ax