<jupyter_start><jupyter_text>Hands-on II :  Black Box Techniques ( ~ 30 minutes) Guideline:   - Prerequisites  : Data Preparation (Understand and load the data) - Train a ML models (black box and white box models)- LIME  - SHAP   Prerequisites: Data PreparationDuring the hands-on is proposed to use boston dataset from sklearn_datasets utilities  This dataset contains information about boston house prices. The objective of the task is to predict the value of a house.  (see : [sklearn.datasets.load_boston.html](https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_boston.htmlsklearn-datasets-load-boston) ) Attribute Information (in order):    - CRIM     per capita crime rate by town    - ZN       proportion of residential land zoned for lots over 25,000 sq.ft.    - INDUS    proportion of non-retail business acres per town    - CHAS     Charles River dummy variable (= 1 if tract bounds river; 0 otherwise)    - NOX      nitric oxides concentration (parts per 10 million)    - RM       average number of rooms per dwelling    - AGE      proportion of owner-occupied units built prior to 1940    - DIS      weighted distances to five Boston employment centres    - RAD      index of accessibility to radial highways    - TAX      full-value property-tax rate per \$10,000    - PTRATIO  pupil-teacher ratio by town    - B        1000(Bk - 0.63)^2 where Bk is the proportion of blacks by town    - LSTAT    % lower status of the populationTarget Variable     - MEDV     Median value of owner-occupied homes in $1000's<jupyter_code>from sklearn.model_selection import train_test_split
from sklearn.datasets import load_boston
import pandas as pd

# Load the Dataset
boston = load_boston()
boston_data_df = pd.DataFrame(boston.data, columns=boston.feature_names)

# Train and test split 
x_train, x_test, y_train, y_test = train_test_split(boston_data_df, boston.target, 
                                                    test_size=0.33, random_state=42)<jupyter_output><empty_output><jupyter_text>Prerequisites  : Train different ML models Build a High Accuracy and a High Explainability ML model.       TODO1. Train different models using previous dataset. Train at least two different models:         - Model a: High Accuracy model          - Model b: High Explainaiblity model  2. Calculate and compare the performance of the models __note__ For simplicity consider only working with models included in scikit library. __note__ We are working with Regression choose a good model/metric for this task.<jupyter_code># Define model a : High Explainability algorithm  (Suggested DecisionTree from sci-kit library)

# Define model b : High Accuracy algorithm (Suggested GradienBoosting from sci-kit library)<jupyter_output><empty_output><jupyter_text>POST-HOC Explainability  Post-Hoc techniques allows to train any Machine Learning model (model agnostic) as usual and provide explanations a posteriori. This technique tends to be more flexible and independent in comparison with WhiteBox techniques where the level of explainability is constrained by the nature of the algorithm.          LIME LIME is based on surrogate models. Surrogate models are used when the outcome of interest cannot be directly measured. Specifically,  LIME creates for each instance a local model to provide an explanation. For each point in the dataset, the surrogate model makes a perturbation (for instance, adding noise to continuous features, removing words or hiding parts of the image) and evaluates the changes in the output.       The figure above illustrates the intuition for this procedure. The model decision function is represented by the blue/pink background. The bright red cross is the instance being explained (let's call it X). We sample instances around X, and weight them according to their proximity to X (weight here is indicated by size). We then learn a linear model (dashed line) that approximates the model well in the vicinity of X, but not necessarily (source: https://github.com/marcotcr/lime)  How to interpret a LIME instance: The output of LIME is a list of features reflecting the contributions of each feature in the predicted observation. It works as follows, Imagine a classifier for Mushroom poisoning (Poisonous or Edible). Looking at the output, the predicted probability told us that the classifier predicts "poisonous".  The bar plot told which features are pushing the prediction as poisonous. The odor=foul, stalk-surface-above-ring=silky and spore-print-color=choloate are the features that contribute to building the observation as poisonous.        TODOA) Define a LimeTabularExplainer for your dataset (using LimeTabularExplainer)B) Explain an instance of the test set (using explain_instance function) C) Explain the instance with the lowest predicted value D) Explain the instance with the highest predicted value E) Compare both explanations**LimeTabularExplainer** object contain functions to explain predictions on tabular data ([link](https://lime-ml.readthedocs.io/en/latest/lime.html?highlight=explainer%20explain_instancelime.lime_tabular.LimeTabularExplainer.explain_instance)) ![Explain instance](https://github.com/albertcalv/Tellmewhy/blob/master/Data/img/lime_tabular_explainer.JPG?raw=true)Expected Parameters: - training_data – numpy 2d array- mode – “classification” or “regression”- feature_names – list of names (strings) corresponding to the columns in the training data.<jupyter_code>import lime
import lime.lime_tabular

# Define a LimeTabularExplainer object for train data
explainer = lime.lime_tabular.LimeTabularExplainer(training_data=,
                                                   mode='regression',
                                                   feature_names=  )<jupyter_output><empty_output><jupyter_text>Use the funtion **explain_instance** to generate an explanation for a single point (2d numpy array correspoing to a row).Expected Parameters: - data_row – 1d numpy array, corresponding to a row- predict_fn – prediction function.     For classifiers, this should be a function that takes a numpy array and outputs prediction probabilities. For regressors, this takes a numpy array and returns the    predictions. For ScikitClassifiers, this is classifier.predict_proba(). For ScikitRegressors, this is regressor.predict().- num_features - int, maximum number of features present in explanation<jupyter_code># Explain a random instance of the test set
idx_instance = 15
exp = explainer.explain_instance(data_row = , 
                                 predict_fn = , 
                                 num_features= )
exp.show_in_notebook(show_all=False)
# Explain the instance with higher predicted value


# Explain the instance with lowest predicted value<jupyter_output><empty_output><jupyter_text>SHAP SHAP (SHapley Additive exPlanations) explain instances using Shapley values a game theory method. Shapley value is a solution concept in cooperative game theory. To each cooperative game it assigns a unique distribution (among the players) of a total surplus generated by the coalition of all players.  The Shapley value is one way to distribute the total gains to the players, assuming that they all collaborate. It is a "fair" distribution in the sense that it is the only distribution with certain desirable properties listed below. According to the Shapley value, the amount that player i gets given in a coalitional game (v,N).  N is the total number of players and the sum extends over all subsets S of N not containing player (Source: [link](https://en.wikipedia.org/wiki/Shapley_value)) SHAP explain each prediction (point in the dataset) by computing the contribution of each feature to the prediction. For each point is presented a consistent and locally feature atributon based on expectations.      Related Information : [Interpretable Machine Learning](https://christophm.github.io/interpretable-ml-book/)  How to interpret SHAP ValuesShap force plot shows the contributions of each feature to the final output. Features pushing the prediction higher are shown in red, pushing the prediction lower are in blue. In this case, the model ouput is 24.41 and the average value 22.34 so this prediction is higher than the average values. A high LSTAT and a low RM and NOX contributes to make the prediction.        How to interpret a SHAP Summary plots: The summary plot gives an overview of which features are the most important in the prediction. In the plot are represented the SHAP values showing the distribution of the impacts.Each dot has three characteristics:- Vertical location shows what feature it is representing- Color shows whether that feature was high or low for that row of the dataset (red = high, blue = low)- Horizontal location shows whether the effect of that value caused a higher or lower prediction      A high level of LSTAT (% lower status of the population) lowers the predicted home price. On the other hand, a high level of RM (Rooms per Dwelling, Room of the house)  indicates a high level in home price. How to interpret SHAP Dependence Contributions plots SHAP contribution plot shows the distributions of effects. In this case coloring RAD (index of accessibility to radial highways) highlights that the average number of rooms per house (RM) has less impact on home price for areas with a high RAD value.      SHAP Documentation: [shap.readthedocs.io](https://shap.readthedocs.io/en/latest/) TODOA) Build an Explainer object (KernelExplainer or TreeExplainer) and obtain shap values using the HighAccuracy algorithm using the test set B) Explain a Random Instance from test C) Explain the instance with higher predicted value D) Explain the instance with lower predicted value F) Summary PlotG) Dependence plotH) Repeat the previous steps (A-G) with the low accuracy algorithm, can you spot the diference in the explanations ? Kernel SHAP is a method that uses a special weighted linear regression and computes the importance of each feature. TreeExplainer is an optimization for Tree models.  Use the method shap_values to estimate the SHAP values for a set of points (This function returns a matrix indicating for each observation the set of weights). Sections B to G explain different function to plot and interpret SHAP values previously calculated. Expected parameters: - model :model object    The tree based machine learning model that we want to explain. XGBoost, LightGBM, CatBoost, and most tree-based scikit-learn models are supported.- data :numpy.array or pandas.DataFrame    The background dataset to use for integrating out features. This argument is optional when feature_dependence=”tree_path_dependent”,     since in that case we can use the number of training samples that went down each tree path as our background     dataset (this is recorded in the model object).<jupyter_code>import shap

# Load JS Visualization code to notebook 
shap.initjs()

# Consider use shap.kmeans(X, k) to summarize the x_train 
# X : Train Dataframe to summarize 
# k : Number of means to use for approximation 

# Use KernelExplainer for compute shap values of any model
explainer_xgb = shap.KernelExplainer(model_xgb.predict, x_train)
shap_values_model_xgb = explainer_xgb.shap_values(x_test,  l1_reg = "num_features(10)")

# Use TreExplainer method if you use a Tree model (Decision Tree) 
explainer_dtr = shap.TreeExplainer(model_dtr)
shap_values_model_dtr = explainer_dtr.shap_values(x_test)<jupyter_output><empty_output><jupyter_text>The function force_plot allows to visualize the SHAP values for a single instance   Expected parameters: - base_value :float         This is the reference value that the feature contributions start from. For SHAP values it should be the value of explainer.expected_value.- shap_values :numpy.array         Matrix of SHAP values ( features) or ( samples x  features). If this is a 1D array then a single force plot will be drawn, if it is a 2D array  then a stacked force plot will be drawn.- features  :numpy.array        Matrix of feature values ( features) or ( samples x  features). This provides the values of all the features, and should be the same shape as the shap_values argument.<jupyter_code># Explain a random instance

idx_instance = 15
shap.force_plot(base_value = , 
                shap_values = , 
                features = ) 
# Explain the instance with lowest predicted value

# Explain the instance with higher predicted value

# Force plot also allows to explain multiple points in the plot. When the argument is a dataframe consisting in several observations 
# it will print the entire shap values rotating them 90 degres and stacking them horizontally. 

shap.force_plot(explainer_xgb.expected_value, shap_values_model_xgb, x_test)<jupyter_output><empty_output><jupyter_text>The function summary_plot summarizes all shap values. Use plot_type="bar" to get a standard bar plot Expected Parameters: - shap_values : numpy.array        For single output explanations this is a matrix of SHAP values ( samples x  features).        For multi-output explanations this is a list of such matrices of SHAP values.- features : numpy.array or pandas.DataFrame or list        Matrix of feature values ( samples x  features) or a feature_names list as shorthand The function dependence plot print the interaction effects Expected Parameters: - ind :int or string      If this is an int it is the index of the feature to plot. If this is a string it is either the name of the feature to plot, or it can have the form “rank(int)” to specify the feature with that rank (ordered by mean absolute SHAP value over all the samples)- shap_values :numpy.array         Matrix of SHAP values ( samples x  features).- features :numpy.array or pandas.DataFrame        Matrix of feature values ( samples x  features).<jupyter_code># Print Depence plot, the plot shows how the model depends on the given feature. 


# Repeat the previous steps (A-G) with the low accuracy algorithm<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.04761564309716165, 'fraction_numerical': 0.004504182455136913, 'mean_word_length': 4.174990751017388, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 29, 'https://': 7, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '7', 'dir': 'jupyter-structured-clean-dedup', 'id': '235054', 'license': 'MIT', 'n_tokens_mistral': 3607, 'n_tokens_neox': 3407, 'n_words': 1790, 'path': 'Hands-on II - Black Box.ipynb', 'repo_name': 'albertcalv/Tellmewhy', 'size': '13987'}