We are working with a regression problem, where we want to apply log transform to target variable. After model training, we want to obtain SHAP values in native units, that they would be suitable for end-user.
When trying to create an explainer by using SHAP library, we receive the following error:
shap.utils._exceptions.InvalidModelError: Model type not yet supported by TreeExplainer: <class 'sklearn.compose._target.TransformedTargetRegressor'>
I can manually apply reverse transformation to obtain final prediction correctly, however, I want to receive each SHAP value for individual features in native units. How could I do it?
LightGBM prediction with target transform: [24.23973864] SHAP explainer estimated value with manual reverse_tranform of final value: 24.23973864452016 SHAP explainer estimated value with manual reverse_tranform of intermediate values: 21.04059855102976
Reproducible example:
import numpy as np
from lightgbm import LGBMRegressor
import shap
from sklearn.pipeline import make_pipeline
from sklearn.compose import TransformedTargetRegressor
#get data set
X, y = shap.datasets.boston()
#Create model with target transform
pipeline = make_pipeline(
LGBMRegressor()
)
model_with_target_transform = TransformedTargetRegressor(regressor=pipeline, func=np.log1p, inverse_func=np.expm1)
model_with_target_transform.fit(X, y)
#Create model without target transform, but with transform
y = np.log1p(y)
model_without_target_trasnsform = LGBMRegressor()
model_without_target_trasnsform.fit(X, y)
#Select observation for testing purpose
test = X.iloc[:1]
# Calculate prediction with target transform
lightgbm_prediction_with_target_transform = model_with_target_transform.predict(test)
# Create explainer
# Explainer with target transform is not supported
# explainer = shap.TreeExplainer(model_with_target_transform)
# shap.utils._exceptions.InvalidModelError: Model type not yet supported by TreeExplainer: <class 'sklearn.compose._target.TransformedTargetRegressor'>
explainer = shap.TreeExplainer(model_without_target_trasnsform)
explained = explainer(test)
# Manualy inverse transform shap values
shap_prediction_all_transform = np.expm1(explained.base_values[0] + sum(explained.values[0]))
shap_prediction_seperate_transform = np.expm1(explained.base_values[0]) + sum(np.expm1(explained.values[0]))
print(f"LightGBM prediction with target transform: {lightgbm_prediction_with_target_transform}")
# Manual conversion of shap values to estimation, reverse transformation of shap values + base values is correct.
# Seperate values reverse transformation and than sum is incorrect
print(f"SHAP explainer estimated value with manual reverse_tranform of final value: {shap_prediction_all_transform}")
print(f"SHAP explainer estimated value with manual reverse_tranform of intermediate values: {shap_prediction_seperate_transform}")