hf <- read_heart_failure()
x <- features(hf)
ex <- setup_SerialExecution(seed = 2026L)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.
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:
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"