I am building an NLP model to predict language type (C/C++/C#/Python...) for a given code. Now I need to provide an explanation for my model prediction. For example the following user_input is written in Java and the model is predicting that, but I need to show the users why it predicts so.
I am using shap_values to achieve this. For some reason, the following code results in an error (I have added the error at the bottom). Please advise how can I get shap_values and plots for my model predictions.
Link to data: https://sharetext.me/bd68ryvzi0
Code:
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.preprocessing import FunctionTransformer
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.pipeline import Pipeline
# Loading Data:
DATA_PATH = r"sample.csv"
data = pd.read_csv(DATA_PATH, dtype='object')
data = data.convert_dtypes()
data = data.dropna()
data = data.drop_duplicates()
# Train/Test split
X, y = data.content, data.language
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, stratify=y)
# Model params to match:
# 1. Variable and module names, words in a string, keywords: [A-Za-z_]\w*\b
# 2. Operators: [!\#\\\$%\&\*\+:\-\./<=>\?@\\\^_\|\~]+
# 3. Tabs, spaces and Brackets: [ \t\(\),;\{\}\[\]`"']
# with the following regex:
token_pattern = r"""(\b[A-Za-z_]\w*\b|[!\#\\\$%\&\*\+:\-\./<=>\?@\\\^_\|\~]+|[ \t\(\),;\{\}\[\]`"'])"""
def preprocess(x):
""" Clean up single-character variable names or ones constituted of a sequence of the same character """
return pd.Series(x).replace(r'\b([A-Za-z])\1+\b', '', regex=True)\
.replace(r'\b[A-Za-z]\b', '', regex=True)
# Pipe steps:
# Define a transformer:
transformer = FunctionTransformer(preprocess)
# Perform TF-IDF vectorization with our token pattern:
vectorizer = TfidfVectorizer(token_pattern=token_pattern, max_features=3000)
# Create Random Forest Classifier:
clf = RandomForestClassifier(n_jobs=4)
pipe_RF = Pipeline([
('preprocessing', transformer),
('vectorizer', vectorizer),
('clf', clf)]
)
# Setting best params (after performing GridSearchCV)
best_params = {
'clf__criterion': 'gini',
'clf__max_features': 'sqrt',
'clf__min_samples_split': 3,
'clf__n_estimators': 300
}
pipe_RF.set_params(**best_params)
# Fitting
pipe_RF.fit(X_train, y_train)
# Evaluation
print(f'Accuracy: {pipe_RF.score(X_test, y_test)}')
user_input = [""" public class Fibonacci {
public static void main(String[] args) {
int n = 10;
System.out.println(fib(n));
}
public static int fib(int n) {
if (n <= 1) {
return n;
}
return fib(n - 1) + fib(n - 2);
}
} """]
import shap
shap.initjs()
explainer = shap.TreeExplainer(pipe_RF.named_steps['clf'])
observation = pipe_RF[:-1].transform(user_input).toarray()
shap_values = explainer.shap_values(observation)
Load the data and run it to get the following error:
ExplainerError: Additivity check failed in TreeExplainer! Please ensure the data matrix you passed to the explainer is the same shape that the model was trained on. If your data shape is correct then please report this on GitHub. Consider retrying with the feature_perturbation='interventional' option. This check failed because for one of the samples the sum of the SHAP values was 46609069202029743624438153216.000000, while the model output was 0.004444. If this difference is acceptable you can set check_additivity=False to disable this check.