Rocketq
Rocketq

Reputation: 5791

How to get SHAP values of the model averaged by folds?

This is way I can values from single fold trained model

clf.fit(X_train, y_train, 
        eval_set=[(X_train, y_train), (X_test, y_test)], 
        eval_metric='auc', verbose=100, early_stopping_rounds=200)
import shap  # package used to calculate Shap values
# Create object that can calculate shap values
explainer = shap.TreeExplainer(clf)
# Calculate Shap values
shap_values = explainer.shap_values(X_test)
shap.summary_plot(shap_values, X_test)

As you know result from different fold might be different - how to average this shap_values?

Upvotes: 2

Views: 942

Answers (1)

Rocketq
Rocketq

Reputation: 5791

Because we have such rule:

It is fine to average the SHAP values from models with the same output trained on the same input features, just make sure to also average the expected_value from each explainer. However, if you have non-overlapping test sets then you can't average the SHAP values from the test sets since they are for different samples. You could just explain the SHAP values for the whole dataset using each of your models and then average that into a single matrix. (It's fine to explain examples in your training set, just remember you may be overfit to them)

So we need here some holdout dataset to follow that rule. I did something like this to get erything to work as expected:

shap_values = None
from sklearn.model_selection import cross_val_score, StratifiedKFold
(X_train, X_test, y_train, y_test) = train_test_split(df[feat], df['target'].values, 
                                     test_size=0.2, shuffle  = True,stratify =df['target'].values,
                                     random_state=42) 

folds = StratifiedKFold(n_splits=10, shuffle=True, random_state=42)
folds_idx = [(train_idx, val_idx) 
                 for train_idx, val_idx in folds.split(X_train, y=y_train)]
auc_scores = []
oof_preds = np.zeros(df[feat].shape[0])
test_preds = []

for n_fold, (train_idx, valid_idx) in enumerate(folds_idx):
    train_x, train_y = df[feat].iloc[train_idx], df['target'].iloc[train_idx]
    valid_x, valid_y = df[feat].iloc[valid_idx], df['target'].iloc[valid_idx]    
    clf = lgb.LGBMClassifier(nthread=4,            boosting_type= 'gbdt', is_unbalance= True,random_state = 42,
            learning_rate= 0.05, max_depth= 3,
            reg_lambda=0.1 , reg_alpha= 0.01,min_child_samples= 21,subsample_for_bin= 5000,
            metric= 'auc', n_estimators= 5000    )
    clf.fit(train_x, train_y, 
            eval_set=[(train_x, train_y), (valid_x, valid_y)], 
            eval_metric='auc', verbose=False, early_stopping_rounds=100)
    explainer = shap.TreeExplainer(clf)
    if shap_values is None:
        shap_values = explainer.shap_values(X_test)
    else:
        shap_values += explainer.shap_values(X_test)       
    oof_preds[valid_idx] = clf.predict_proba(valid_x)[:, 1]   
    auc_scores.append(roc_auc_score(valid_y, oof_preds[valid_idx]))
print( 'AUC: ', np.mean(auc_scores))
shap_values /= 10 # number of folds
shap.summary_plot(shap_values, X_test)

Upvotes: 1

Related Questions