shap / shap

A game theoretic approach to explain the output of any machine learning model.
https://shap.readthedocs.io
MIT License
22.72k stars 3.27k forks source link

KeyError: 'objective' with LGBMRegressor Model #1042

Open shaddyab opened 4 years ago

shaddyab commented 4 years ago

When executing the following code to find the features importance of a LGBMRegressor model I get a KeyError: 'objective' error. The model's objective was specified as 'mean_squared_error'.

Code:

explainer = shap.TreeExplainer(Final_Model)
shap_values = explainer.shap_values(X_Predict, check_additivity=True)

Error:

    714     explainer = shap.TreeExplainer(Final_Model)
--> 715     shap_values = explainer.shap_values(X_Predict, check_additivity=check_additivity)

~/.local/lib/python3.5/site-packages/shap/explainers/tree.py in shap_values(self, X, y, tree_limit, approximate, check_additivity)
    229                 phi = self.model.original_model.predict(X, num_iteration=tree_limit, pred_contrib=True)
    230                 # Note: the data must be joined on the last axis
--> 231                 if self.model.original_model.params['objective'] == 'binary':
    232                     warnings.warn('LightGBM binary classifier with TreeExplainer shap values output has changed to a list of ndarray')
    233                     phi = np.concatenate((0-phi, phi), axis=-1)

KeyError: 'objective'

Versions: shap version = 0.34.0 LightGBM version = 2.3.1

Model:

LGBMRegressor(boosting_type='gbdt', class_weight=None,
              colsample_bytree=0.8294233848166401, importance_type='split',
              learning_rate=0.1, max_depth=6, min_child_samples=20,
              min_child_weight=0.001, min_split_gain=0.0, n_estimators=110,
              n_jobs=-1, num_leaves=15, objective='mean_squared_error',
              random_state=111, reg_alpha=0.000873705633371746,
              reg_lambda=0.02583081135738517, silent=False,
              subsample=0.5277279927337998, subsample_for_bin=200000,
              subsample_freq=0)

Update: I can plot the shap values if they are predicted directly. Final_Model.predict(X_Predict, pred_contrib=True)

imatiach-msft commented 4 years ago

@shaddyab this looks like something that I should take a look at as I recently wrote that code

mu-wang commented 4 years ago

Can be fixed by adding the following before passing the model to TreeExplainer, if your booster name is gbm.

gbm.params['objective'] = 'binary' # or whatever is appropriate
imatiach-msft commented 4 years ago

@shaddyab I've sent a preliminary PR but I'm not able to reproduce this issue. Also I noticed someone sent a similar PR as well.

https://github.com/slundberg/shap/pull/1062

can you provide the code for how you built Final_Model?

shaddyab commented 4 years ago

@mu-wang I recall trying this trick and it didn't resolve the problem. In any case, I have a regression model not a classification model, would not setting the objective function to binary affect the Shap values?

timothyrenner commented 4 years ago

I ran into this issue, also with a regression target. This fixed it for me:

model.params["objective"] = "regression"
explainer = shap.TreeExplainer(model)
chen371502 commented 4 years ago

Hi, I ran into this problem today, I find if I directly use result from lgb.train, there would be no problem, but if I reload a lightgbm model from file, likelgbmodel=lgb.Booster(model_file='a.lgb'), then explainer.shap_values would raise this exception, I think maybe this exception is caused because lightgbm doesn't correctly reload 'binary' or 'regression' into model.params["objective"], so adding lgbmodel.params["objective"] = "binary" would fix this problem.

imatiach-msft commented 4 years ago

thank you for the details, I was able to reproduce the issue with non-sklearn API, so I think this PR does fix the issue:

https://github.com/slundberg/shap/pull/1063

Perello-Mckinsey commented 2 years ago

I fixed this issue by running this:

explainer = shap.TreeExplainer(model)
if isinstance(model, lgb.LGBMClassifier):
     explainer.model.original_model.params['objective'] = 'binary'
github-actions[bot] commented 1 day ago

This issue has been inactive for two years, so it's been automatically marked as 'stale'.

We value your input! If this issue is still relevant, please leave a comment below. This will remove the 'stale' label and keep it open.

If there's no activity in the next 90 days the issue will be closed.