LIME and SHAP are interpretability techniques. Explanations for the same model prediction will be generated using both methods, and the results will be compared side-by-side. Comparing these techniques helps in understanding how each method attributes influence and the subtle differences that might arise from their distinct approaches.Setting the Stage: Model and DataImagine we have trained a RandomForestClassifier on the familiar Iris dataset to predict the species of iris based on sepal and petal measurements. We'll assume this model is already trained and available as model. Our features are 'sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', and 'petal width (cm)'.Let's select a specific iris flower from our test set for which the model predicts the species 'virginica' (class index 2). Suppose this instance has the following features:Sepal Length: 6.5 cmSepal Width: 3.0 cmPetal Length: 5.8 cmPetal Width: 2.2 cmOur goal is to explain why the model predicted 'virginica' for this specific flower using both LIME and SHAP.Generating the LIME ExplanationFirst, we use LIME. As covered in Chapter 2, LIME works by creating perturbations of the instance in question and fitting a simpler, interpretable model (like linear regression) to understand the black-box model's behavior locally around that instance.We'll use the LimeTabularExplainer for this task.import lime import lime.lime_tabular import numpy as np # Assume: # X_train: training data (numpy array or pandas DataFrame) # feature_names: list of feature names # class_names: list of target class names # model: trained scikit-learn classifier with predict_proba method # instance_to_explain: numpy array for the single instance (e.g., [6.5, 3.0, 5.8, 2.2]) explainer_lime = lime.lime_tabular.LimeTabularExplainer( training_data=X_train, feature_names=feature_names, class_names=class_names, mode='classification' ) # Explain the prediction for the specific instance (predicting class index 2) explanation_lime = explainer_lime.explain_instance( data_row=instance_to_explain, predict_fn=model.predict_proba, num_features=4, # Show importance for all features top_labels=1 # Focus on the predicted class ) # Displaying the explanation (representation) # The actual output might be visualized or accessed via explanation_lime.as_list(label=2) print("LIME Explanation for class 'virginica':") # Example Output: # [('petal width (cm) > 1.70', 0.35), # ('petal length (cm) > 4.90', 0.25), # ('sepal length (cm) <= 6.80', -0.08), # ('sepal width (cm) <= 3.10', 0.05)]Interpreting LIME: LIME often presents explanations as a list of feature contributions (weights) derived from its local surrogate model. The output above suggests that having a 'petal width' greater than 1.7 cm and a 'petal length' greater than 4.9 cm strongly pushed the prediction towards 'virginica' for this instance. The sepal measurements had a smaller, mixed impact according to LIME's local approximation. Note that LIME often discretizes continuous features for interpretability, resulting in rules like 'petal width (cm) > 1.70'.Generating the SHAP ExplanationNext, we apply SHAP. Since we have a RandomForest model, we can use the efficient TreeExplainer. If we didn't know the model type or it wasn't tree-based, we could use KernelExplainer. SHAP calculates Shapley values, representing the average marginal contribution of each feature across all possible feature combinations.import shap # Assume: # model: trained tree-based model (like RandomForestClassifier) # X_train: background data for the explainer (often the training set) # instance_to_explain_df: pandas DataFrame for the single instance explainer_shap = shap.TreeExplainer(model, data=X_train) # Use KernelExplainer for non-tree models # Calculate SHAP values for the instance # Note: SHAP explainers often expect DataFrame input if trained on one shap_values = explainer_shap.shap_values(instance_to_explain_df) # SHAP values are often returned per class. We need the values for the predicted class ('virginica', index 2) shap_values_for_class_2 = shap_values[2][0] # [class_index][instance_index] # Displaying SHAP values (representation) print("\nSHAP Values for class 'virginica':") # Example Output: # {'sepal length (cm)': -0.15, # 'sepal width (cm)': 0.05, # 'petal length (cm)': 0.40, # 'petal width (cm)': 0.60} # Visualizing with a force plot # shap.force_plot(explainer_shap.expected_value[2], shap_values_for_class_2, instance_to_explain_df)Interpreting SHAP: The SHAP values represent the contribution of each feature value towards pushing the model output away from the base value (average prediction over the training set) towards the final prediction for this specific instance. A positive SHAP value increases the prediction for 'virginica', while a negative value decreases it. Here, 'petal width' (0.60) and 'petal length' (0.40) are the primary drivers pushing the prediction towards 'virginica'. 'Sepal width' has a small positive contribution, while 'sepal length' has a moderate negative contribution.Comparing LIME and SHAP OutputsNow, let's compare the insights from both methods for our specific iris flower prediction:Most Important Features: Both LIME and SHAP identify 'petal width (cm)' and 'petal length (cm)' as the most significant features driving the prediction towards 'virginica'. This agreement provides confidence in the importance of these features.Ranking: The ranking of the top two features is consistent ('petal width' > 'petal length'). However, the ranking and perceived impact of the less important features ('sepal length', 'sepal width') might differ slightly. LIME showed 'sepal length' as slightly negative and 'sepal width' as slightly positive, while SHAP showed 'sepal length' as more clearly negative and 'sepal width' as slightly positive.Magnitude/Scale: The values themselves are not directly comparable. LIME provides weights from a local linear model, while SHAP provides additive contributions (Shapley values) measured on the scale of the model's output (e.g., log-odds for classification probability). The SHAP values add up to the difference between the model's output for this instance and the base expected value.Representation: LIME often uses discretized features or rules (e.g., 'petal width (cm) > 1.70'), which can be intuitive but depend on the discretization method. SHAP typically provides contributions for the raw feature values themselves.Consistency: SHAP values possess properties like local accuracy (values sum to the difference between prediction and base value) and consistency (feature importance doesn't counter-intuitively decrease when the model changes to rely more on that feature). LIME's explanations depend heavily on the perturbation strategy and the fidelity of the local linear approximation, which can sometimes lead to instability.Let's visualize the comparison using importance values derived from the examples above.{"layout": {"title": "Feature Importance Comparison (Single Prediction)", "xaxis": {"title": "Importance Score"}, "yaxis": {"title": "Feature", "categoryorder":"total ascending"}, "barmode": "group", "margin": {"l": 150, "r": 20, "t": 40, "b": 50}, "legend": {"title": {"text": "Method"}}}, "data": [{"type": "bar", "y": ["sepal length (cm)", "sepal width (cm)", "petal length (cm)", "petal width (cm)"], "x": [-0.08, 0.05, 0.25, 0.35], "name": "LIME Weight", "orientation": "h", "marker": {"color": "#339af0"}}, {"type": "bar", "y": ["sepal length (cm)", "sepal width (cm)", "petal length (cm)", "petal width (cm)"], "x": [-0.15, 0.05, 0.40, 0.60], "name": "SHAP Value", "orientation": "h", "marker": {"color": "#fd7e14"}}]}Comparison of LIME weights and SHAP values for the features contributing to the 'virginica' prediction for the selected instance. While absolute values differ, the relative importance of petal features is clear in both.Discussion PointsAgreement and Disagreement: When LIME and SHAP agree on the most influential features (as they often do for dominant features), it strengthens our confidence in the explanation. Disagreements, especially for less influential features, highlight the different perspectives offered: LIME's focus on local linearity versus SHAP's consideration of feature contributions across different combinations.Computational Cost: Generating this single LIME explanation was likely faster than calculating the exact SHAP values using TreeExplainer (though TreeExplainer is highly optimized). If we had used KernelSHAP, the computation would have been significantly more intensive than LIME, as it also relies on perturbation but requires many more samples for theoretical grounding.Use Case: LIME can be quicker for a fast local check. SHAP provides a more theoretically grounded measure of feature contribution and offers powerful global summary plots (as seen in Chapter 3) in addition to local explanations like the force plot.By running both methods on the same instance, you gain a richer understanding of why your model made a specific prediction, appreciating the nuances and potential differences between these two popular interpretability techniques. This comparative approach helps validate findings and provides a more comprehensive picture of feature influence.