Преобразование значений SHAP из raw в собственные единицы с помощью lightgbm Tweedie objective?

#r #lightgbm #shap #tweedie

#python #r #lightgbm #shap #tweedie

Вопрос:

Полезность аддитивных объяснений Шепли (значений SHAP) заключается в понимании того, как каждая функция способствует прогнозированию модели. Для некоторых целей, таких как регрессия с использованием RMSE в качестве целевой функции, значения SHAP указаны в собственных единицах значений метки. Например, значения SHAP могут быть выражены в долларах США при оценке стоимости жилья. Как вы увидите ниже, это не относится ко всем целевым функциям. В частности, цели регрессии Tweedie не дают значений SHAP в собственных единицах. Это проблема для интерпретации, поскольку мы хотели бы знать, как на стоимость жилья влияют функции в пересчете на / -доллары.

Учитывая эту информацию, мой вопрос: как мы преобразуем значения SHAP каждой отдельной функции в пространство данных целевых меток при объяснении моделей с целью регрессии Tweedie?

Я не знаю ни о каких пакетах, которые в настоящее время реализуют такое преобразование. Это остается нерешенным в пакете, выпущенном самими авторами shap.

Я иллюстрирую более тонкие моменты этого вопроса с помощью R-реализации lightgbm следующим образом:

 library(tweedie)
library(lightgbm)

set.seed(123)

tweedie_variance_power <- 1.2

labels <- rtweedie(1000, mu = 1, phi = 1, power = tweedie_variance_power)
hist(labels)

feat1 <- labels   rnorm(1000) #good signal for label with some noise
feat2 <-rnorm(1000) #garbage feature 
feat3 <-rnorm(1000) #garbage feature 

features <- cbind(feat1, feat2, feat3)

dTrain <- lgb.Dataset(data = features,
                      label = labels)

params <- c(objective = 'tweedie',
            tweedie_variance_power = tweedie_variance_power)

mod <- lgb.train(data = dTrain,
                 params = params,
                 nrounds = 100)

#Predictions in the native units of the labels
predsNative <- predict(mod, features, rawscore = FALSE)
#Predictions in the raw format
predsRaw <- predict(mod, features, rawscore = TRUE)

#We do not expect these values to be equal
all.equal(predsTrans, predsRaw)
"Mean relative difference: 1.503072"

#We expect values to be equal if raw scores are exponentiated
all.equal(predsTrans, exp(predsRaw))
"TRUE" #... our expectations are correct

#SHAP values 
shapNative <- predict(mod, features, rawscore = FALSE, predcontrib = TRUE)
shapRaw <- predict(mod, features, rawscore = TRUE, predcontrib = TRUE )

#Are there differences between shap values when rawscore is TRUE or FALSE?
all.equal(shapNative, shapRaw)
"TRUE" #outputs are identical, that is surprising!

#So are the shap values in raw or native formats?
#To anwser this question we can sum them

#testing raw the raw case first
all.equal(rowSums(shapRaw), predsRaw)
"TRUE" 

#from this we can conclude that shap values are not in native units,
#regardless of whether rawscore is TRUE or FALSE

#Test native scores just to prove point
all.equal(rowSums(shapNative), predsNative)
"Mean relative difference: 1.636892" # reaffirms that shap values are not in native units

#However, we can perform this operation on the raw shap scores
#to get the prediction in the native value
all.equal(exp(rowSums(shapRaw)), predsNative)
'TRUE'

#reversing the operations does not yield the same result
all.equal(rowSums(exp(shapRaw)), predsNative)
"Mean relative difference: 0.7662481"

#The last line is relevant because it implies 
#The relationship between native predictions
#and exponentiated shap values is not linear

#So, given the point of SHAP is to understand how each 
#feature impacts the prediction in its native units
#the raw shap values are not as useful as they could be

#Thus, how how would we convert 
#each of these four raw shap value elements to native units,
#thus understanding their contributions to their predictions
#in currency of native units?
shapRaw[1,]
-0.15429227  0.04858757 -0.27715359 -0.48454457
  

ОРИГИНАЛЬНОЕ СООБЩЕНИЕ И РЕДАКТИРОВАНИЕ

Мое понимание значений SHAP заключается в том, что они находятся в собственных единицах меток / ответов при проведении регрессии и что сумма значений SHAP приближается к прогнозу модели.

Я пытаюсь извлечь значения SHAP в пакете LightGBM с целью регрессии Tweedie, но обнаружил, что значения SHAP не указаны в собственных единицах меток и что они не суммируются с прогнозируемыми значениями.

Похоже, что они должны быть возведены в степень, это правильно?

Примечание: я понимаю, что последний столбец матрицы значений SHAP представляет базовое предсказание и должен быть добавлен.

Воспроизводимый пример:

 library(tweedie)
library(caret)
library(lightgbm)

set.seed(123)

tweedie_variance_power <- 1.2

labels <- rtweedie(1000, mu = 1, phi = 1, power = tweedie_variance_power)
hist(labels)

feat1 <- labels   rnorm(1000) #good signal for label with some noise
feat2 <-rnorm(1000) #garbage feature 
feat3 <-rnorm(1000) #garbage feature 

features <- cbind(feat1, feat2, feat3)

dTrain <- lgb.Dataset(data = features,
                      label = labels)

params <- c(objective = 'tweedie',
            tweedie_variance_power = tweedie_variance_power)

mod <- lgb.train(data = dTrain,
                 params = params,
                 nrounds = 100)

preds <- predict(mod, features)

plot(preds, labels,
     main = paste('RMSE =', 
                  RMSE(pred = preds, obs = labels)))

#shap values are summing to negative values?
shap_vals <- predict(mod, features, predcontrib = TRUE, rawscore = FALSE)
shaps_sum <- rowSums(shap_vals)
plot(shaps_sum, labels, 
     main = paste('RMSE =', 
                  RMSE(pred = shaps_sum, obs = labels)))

#maybe we need to exponentiate?
shap_vals_exp <- exp(shap_vals)
shap_vals_exp_sum <- rowSums(shap_vals_exp)
#still looks a little weird, overpredicting 
plot(shap_vals_exp_sum, labels,
     main = paste('RMSE =',
                  RMSE(pred = shap_vals_exp_sum, obs = labels)))
  

Редактировать

Порядок операций заключается в том, чтобы сначала суммировать, а затем возводить в степень значения SHAP, что даст вам прогнозы в собственных единицах измерения. Хотя мне все еще неясно, как преобразовать значения уровня функции в собственные единицы измерения ответа.

 shap_vals_sum_exp <- exp(shaps_sum)
plot(shap_vals_sum_exp, labels,
     main = paste('RMSE =',
                  RMSE(pred = shap_vals_sum_exp, obs = labels)))
  

Ответ №1:

Я покажу, как согласовать значения shap и прогнозы модели в Python, как в исходных оценках, так и в исходных единицах. Надеюсь, это поможет вам понять, где вы находитесь в R.

Шаг 1. Сгенерируйте набор данных

 # pip install tweedie
import tweedie
y = tweedie.tweedie(1.2,1,1).rvs(size=1000)
X = np.random.randn(1000,3)
  

Шаг 2. Подходящая модель

 from lightgbm.sklearn import LGBMRegressor
lgb = LGBMRegressor(objective = 'tweedie')
lgb.fit(X,y)
  

Шаг 3. Поймите, что такое значения shap.

Значения Shap для 0-й точки данных

 shap_values = lgb.predict(X, pred_contrib=True)
shap_values[0]
array([ 0.36841812, -0.15985678,  0.28910617, -0.27317984])
  

Первые 3 — это вклад модели в базовый уровень, то есть сами значения shap:

 shap_values[0,:3].sum()
0.4976675073764354
  

4-й — базовый уровень в необработанных оценках:

 shap_values[0,3]
-0.2731798364061747
  

Их сумма складывается в прогноз модели в необработанных оценках:

 shap_values[0,:3].sum()   shap_values[0,3]
0.22448767097026068
  

Давайте проверим прогнозы модели raw:

 preds = lgb.predict(X, raw_score=True)
preds[0]
0.2244876709702609
  

Редактировать. Преобразование между необработанными оценками и исходными значениями utit

Для преобразования между необработанными оценками и исходными единицами для распределения Tweedie (а также для Poisson и для Gamma) вам необходимо знать 2 факта:

  1. Оригинал exp из raw
  2. exp of sum — это product из exps

ДЕМОНСТРАЦИЯ:

  1. 0-е предсказание в исходных единицах:
 lgb.predict([X[0,:]])
array([0.39394102])
  
  1. Значения формы для 0-й строки в пространстве необработанных оценок:
 shap_values = lgb.predict(X, pred_contrib=True, raw_score=True)
shap_values[0]
array([-0.77194274, -0.08343294,  0.22740536, -0.30358374])
  
  1. Преобразование значений shap в исходные единицы (произведение показателей):
 np.prod(np.exp(shap_values[0]))
0.3939410249402226
  

Снова похоже на меня.

Комментарии:

1. Спасибо за вклад. Хотя метод, который вы предоставляете, описывает, как извлечь значения SHAP для единиц целевой функции (логарифмическая вероятность), эти значения не указаны в собственных единицах метки. С тех пор я узнал, что преобразование обратно в собственные единицы не является простым, дальнейшее обсуждение здесь: github.com/slundberg/shap/pull/1041

2. Не могли бы вы уточнить, в чем именно заключается ваша проблема? Я думал, у вас возникли трудности с согласованием значений shap с прогнозами. И я показал вам, как это сделать в пространстве необработанных оценок. Но вы не принимаете ответ. Почему? У вас возникли трудности с преобразованием необработанных значений в исходные единицы? Также обратите внимание, что это регрессия. Логарифмическая вероятность не имеет значения.

3. Проблема в том, что необработанное пространство оценок не находится в единицах y (которые я называю родными), которые вы описываете в своем ответе. Цель состоит в том, чтобы извлечь значения SHAP для каждой функции в единицах y, которые вы описали на шаге 1, таким образом, чтобы они суммировались с прогнозируемым значением в единицах y .

4. @kdoherty Пожалуйста, посмотрите РЕДАКТИРОВАНИЕ

5. Я показал вам 2 способа сделать это: в необработанных оценках и в оригинале. Цифры одинаковы до 15-го знака после запятой