39  Interpretation in rtemis

get_varimp() returns the variable importance measures of a fitted model, each with a description of what it measures, and plot_varimp() draws them. explain() computes Shapley values for new cases with a configuration from setup_SHAP(). This chapter applies both to the heart failure data, and computes partial dependence from a model’s predictions.

hf <- read_heart_failure()
x <- features(hf)
ex <- setup_SerialExecution(seed = 2026L)

39.1 Importance measures

Every fitted model carries the importance measures its algorithm provides. For a random forest with permutation importance:

mod_rf <- train(
  hf,
  hyperparameters = setup_Ranger(
    min_node_size = 20L,
    importance = "permutation",
    seed = 2026L
  ),
  execution_config = ex,
  question = hf_question,
  verbosity = 0L
)
get_varimp(mod_rf)
<VariableImportance>
  importance (permutation, 11 entries): Increase in prediction error on each tree's out-of-bag cases when the predictor's values are permuted, averaged over trees (ranger).
plot_varimp(mod_rf)

The printed object states what the measure is and how it was computed: here, the increase in prediction error on each tree’s out-of-bag cases when the feature is permuted. For a logistic regression, the measure is the coefficient, on the scale of the log odds per unit of the feature:

mod_glm <- train(
  hf,
  hyperparameters = setup_GLM(),
  execution_config = ex,
  verbosity = 0L
)
get_varimp(mod_glm)
<VariableImportance>
  Coefficient (coefficient, 12 entries): Estimated coefficient of each model term, including the intercept, on the scale of the linear predictor, per unit of the term as the model received it.

The two measures are different quantities in different units, and their rankings are compared, not their values.

39.2 Partial dependence

Partial dependence (Equation 38.1) requires only predictions. The function below sets one feature to each value of a grid for every patient, and averages the predicted probabilities:

partial_dependence <- function(mod, x, feature, grid) {
  vapply(grid, function(v) {
    x_v <- copy(x)
    set(x_v, j = feature, value = v)
    mean(predict(mod, x_v))
  }, numeric(1))
}
grid_cr <- seq(0.5, 4, by = 0.1)
draw_line(
  grid_cr,
  list(
    `Random forest` = partial_dependence(mod_rf, x, "serum_creatinine", grid_cr),
    `Logistic regression` = partial_dependence(mod_glm, x, "serum_creatinine", grid_cr)
  ),
  points = FALSE,
  xlab = "Serum creatinine (mg/dL)",
  ylab = "Mean predicted probability of death"
)

The logistic regression’s partial dependence follows the logistic curve of a linear effect on the log odds. The random forest’s changes little below about 1.8 mg/dL, rises sharply between 1.8 and 2 mg/dL, and changes little above, a threshold-like dependence that the forest’s splits represent and the linear model does not. The threshold is close to the first split of the CART tree of Section 29.1. The grid extends to 4 mg/dL; 7 of the 290 patients have higher values, so beyond the bulk of the data both curves rest on few cases.

39.3 Shapley values

explain() takes a fitted model, the cases to explain, a background dataset, and a SHAP configuration. With estimator = "auto", the default, it uses an exact algorithm where the model class has one. explanation_methods() lists the estimator for each algorithm:

explanation_methods()[, c("name", "estimator", "exact")]
                      name  estimator exact
1                     BART KernelSHAP FALSE
2                     CART   TreeSHAP  TRUE
3  ConditionalSuperLearner ExpertSHAP    NA
4                      GAM   GAMTerms  TRUE
5                      GLM LinearSHAP  TRUE
6                   GLMNET LinearSHAP  TRUE
7                  GLMTree KernelSHAP FALSE
8                      HAL   HALBasis    NA
9                 Isotonic   Isotonic  TRUE
10            MonotonicHAL   HALBasis    NA
11                     KNN KernelSHAP FALSE
12               LightCART   TreeSHAP  TRUE
13                LightGBM   TreeSHAP  TRUE
14                 LightRF   TreeSHAP  TRUE
15            LightRuleFit KernelSHAP FALSE
16                   LINAD KernelSHAP FALSE
17             LINADForest KernelSHAP FALSE
18                    MARS  MARSBasis    NA
19                     MLP KernelSHAP FALSE
20        ModalityStacking KernelSHAP FALSE
21                    NNLS LinearSHAP  TRUE
22                  Ranger KernelSHAP FALSE
23            SuperLearner KernelSHAP FALSE
24               LinearSVM LinearSHAP    NA
25               RadialSVM KernelSHAP FALSE
26                    SPLS LinearSHAP    NA
27                  TabNet KernelSHAP FALSE

A gradient boosting model, for which exact TreeSHAP values are available, explained for all 290 patients with the training data as background:

mod_lgb <- train(
  hf,
  hyperparameters = setup_LightGBM(),
  execution_config = ex,
  question = hf_question,
  verbosity = 0L
)
shap_lgb <- explain(
  mod_lgb,
  newdata = x,
  background = x,
  config = setup_SHAP(seed = 2026L)
)

shap_case() lists the contributions for one case, sorted by size, with the baseline and the prediction, all on the scale of the log odds:

case1 <- shap_case(shap_lgb, x, case = 1L)
case1
$steps
                     feature  value contribution
                      <char> <char>        <num>
 1:         serum_creatinine    1.9     0.559694
 2:        ejection_fraction     20     0.381493
 3:      high_blood_pressure    Yes     0.162436
 4:                      age     75     0.145537
 5:             serum_sodium    130     0.046876
 6:                 diabetes     No    -0.006771
 7: creatinine_phosphokinase    582    -0.003837
 8:                platelets    265    -0.002871
 9:                  smoking     No    -0.001710
10:                  anaemia     No     0.000000
11:                      sex   Male     0.000000

$baseline
[1] -1.603

$predicted
[1] -0.3218

$case
[1] "1"

$class
[1] "Yes"

The baseline, -1.603, plus the contributions, 1.281, equals the prediction, -0.322 (Equation 38.3). On the probability scale, this patient’s predicted probability of death is 0.420.

shap_long() returns the contributions of every feature for every case, with the feature values, as a table. Plotting a feature’s contributions against its values shows how the model uses it across patients:

shap_all <- shap_long(shap_lgb, x)
cr <- shap_all[feature == "serum_creatinine"]
draw_scatter(
  cr[["numeric_value"]], cr[["contribution"]],
  xlab = "Serum creatinine (mg/dL)",
  ylab = "Contribution to log odds of death"
)

The mean absolute contribution of each feature is a global importance measure, returned by get_varimp() on the explanation:

shap_importance <- varimp_table(get_varimp(shap_lgb))
draw_varimp(setNames(shap_importance[["Yes"]], shap_importance[["variable"]]))

39.4 Shapley values of a linear model

For a logistic regression, the exact Shapley value of a feature is its coefficient times its deviation from the background mean, on the log odds scale:

shap_glm <- explain(
  mod_glm,
  newdata = x,
  background = x,
  config = setup_SHAP(seed = 2026L)
)
phi_age <- shap_glm@phi[["Yes"]][1, "age"]
manual_age <- coef(mod_glm@model)[["age"]] * (x[1, age] - mean(x[["age"]]))
c(explain = phi_age, coefficient_times_deviation = manual_age)
                    explain coefficient_times_deviation 
                      0.754                       0.754 

39.5 Kernel SHAP

For a random forest, rtemis uses the model-agnostic Kernel SHAP estimator. Its cost grows with the number of cases explained and the size of the background, which background_n subsamples. For three patients:

shap_rf <- explain(
  mod_rf,
  newdata = x[1:3],
  background = x,
  config = setup_SHAP(background_n = 50L, seed = 2026L)
)
shap_case(shap_rf, x[1:3], case = 1L)
$steps
                     feature  value contribution
                      <char> <char>        <num>
 1:         serum_creatinine    1.9     0.156075
 2:        ejection_fraction     20     0.118621
 3:      high_blood_pressure    Yes     0.074035
 4:             serum_sodium    130     0.067019
 5:                      age     75     0.042709
 6:                platelets    265    -0.008403
 7:                  smoking     No    -0.006951
 8: creatinine_phosphokinase    582     0.005201
 9:                  anaemia     No    -0.004947
10:                      sex   Male     0.002905
11:                 diabetes     No    -0.002669

$baseline
[1] 0.1591

$predicted
[1] 0.6027

$case
[1] "1"

$class
[1] "Yes"

The random forest’s contributions are on the probability scale, the scale of its predictions, and the values are estimates whose precision depends on the number of feature subsets evaluated and the background sample. The explanation records its estimator, value function and scale:

c(
  estimator = shap_rf@estimator,
  perturbation = shap_rf@perturbation,
  scale = shap_rf@scale,
  exact = shap_rf@exact
)
       estimator     perturbation            scale            exact 
    "KernelSHAP" "interventional"    "probability"          "FALSE"