Explaining one prediction#

Ask a soft decision tree why it predicted what it predicted for a single sample: which leaf got the mass, how each gate on the way leaned and why, and what single change would have flipped the class.

Run with:

python examples/05_explain_prediction.py

--- test sample 0, true class 0 ---
predicted 0 with probability 0.825
dominant leaf 9 received 0.999 of the sample's mass; its distribution is 0: 0.825, 1: 0.089, 2: 0.086
path:
  gate 0: went left with p=1.000  (-2.503[proline] -1.391[alcohol] -1.314[magnesium])
  gate 1: went right with p=1.000  (+2.603[proline] +1.511[ash] +1.214[alcohol])
  gate 4: went left with p=1.000  (-3.697[proline] -1.693[alcohol] -1.222[alcalinity_of_ash])
largest contributions: proline 8.800, alcohol 4.296, ash 2.832, alcalinity_of_ash 2.604, flavanoids 1.750
counterfactual: set proline from 1.906 to -3.025 and the prediction becomes 1 (p=0.482)

--- test sample 1, true class 1 ---
predicted 1 with probability 0.836
dominant leaf 14 received 0.969 of the sample's mass; its distribution is 0: 0.082, 1: 0.840, 2: 0.078
path:
  gate 0: went right with p=0.972  (+1.632[alcohol] +1.614[proline] -1.386[hue])
  gate 2: went right with p=0.998  (+3.320[hue] +1.558[alcohol] +1.014[color_intensity])
  gate 6: went right with p=0.999  (+2.082[proline] +1.446[hue] +1.215[alcohol])
largest contributions: hue 6.014, alcohol 4.323, proline 4.266, color_intensity 1.873, malic_acid 1.668
counterfactual: set proline from -1.229 to 2.787 and the prediction becomes 0 (p=0.543)

--- test sample 2, true class 0 ---
predicted 0 with probability 0.824
dominant leaf 9 received 0.999 of the sample's mass; its distribution is 0: 0.825, 1: 0.089, 2: 0.086
path:
  gate 0: went left with p=1.000  (-2.563[alcohol] -2.160[proline] -2.084[alcalinity_of_ash])
  gate 1: went right with p=1.000  (+2.247[proline] +2.235[alcohol] +0.881[od280/od315_of_diluted_wines])
  gate 4: went left with p=1.000  (-3.190[proline] -3.118[alcohol] -2.353[alcalinity_of_ash])
largest contributions: alcohol 7.913, proline 7.594, alcalinity_of_ash 5.013, od280/od315_of_diluted_wines 2.674, flavanoids 1.099
counterfactual: set alcohol from 1.647 to -3.315 and the prediction becomes 1 (p=0.606)

from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

from neural_trees import SoftDecisionTree

data = load_wine()
X_train, X_test, y_train, y_test = train_test_split(
    data.data, data.target, test_size=0.3, stratify=data.target, random_state=0
)
scaler = StandardScaler().fit(X_train)
model = SoftDecisionTree(depth=3, max_epochs=60, random_state=0)
model.fit(scaler.transform(X_train), y_train)

# Explain the first three test samples. Values are in standardised units,
# because that is what the model was fitted on.
explanations = model.explain(scaler.transform(X_test[:3]), feature_names=list(data.feature_names))
for i, e in enumerate(explanations):
    print(f"--- test sample {i}, true class {y_test[i]} ---")
    print(e.to_text())
    print()

Total running time of the script: (0 minutes 0.187 seconds)

Gallery generated by Sphinx-Gallery