Skip to contents

Compute SHAP-based feature contributions to the concentration index of a predicted outcome. The SHAP table can be supplied either in wide format (one row per observation, one column per feature) or in DALEX-like long format and reshaped internally.

Usage

shap_conc_decomp(
  shap,
  rank,
  type = c("CI", "CIg", "CIc", "L"),
  prediction = NULL,
  baseline = NULL,
  weights = NULL,
  from_dalex = FALSE,
  dalex_id_col = NULL,
  dalex_variable_col = NULL,
  dalex_value_col = NULL,
  na_rm = FALSE,
  sort = TRUE,
  tolerance = sqrt(.Machine$double.eps)
)

Arguments

shap

A rectangular SHAP table. By default this should be a wide table with one numeric feature column per SHAP contributor. If from_dalex = TRUE, shap should instead be a long DALEX-like table containing observation IDs, feature names, and SHAP values.

rank

A numeric vector giving the socioeconomic ranking variable for each observation. When type = "L", this is interpreted as the observed socioeconomic level variable.

type

One of "CI", "CIg", "CIc", or "L" selecting the decomposition target. The first three are rank-dependent concentration indices scored consistently with ci_factory(). "L" uses the Erreygers–Kessels level-dependent bivariate index based on observed socioeconomic levels.

prediction

Optional numeric vector of model predictions. If omitted, predictions are reconstructed as baseline + rowSums(shap).

baseline

Optional scalar baseline prediction. Required when prediction is not supplied.

weights

Optional numeric vector of non-negative case weights. If omitted, equal weights are used. Observations with non-positive weights do not contribute to the decomposition.

from_dalex

Logical scalar. If TRUE, reshape a DALEX-like long SHAP table to wide format before decomposition.

dalex_id_col

Optional column name identifying observations in the DALEX-like input.

dalex_variable_col

Optional column name containing feature names in the DALEX-like input.

dalex_value_col

Optional column name containing SHAP values in the DALEX-like input.

na_rm

Logical scalar. If TRUE, drop rows with missing values in required inputs before computing the decomposition.

sort

Logical scalar. If TRUE, order output features by decreasing absolute SHAP contribution.

tolerance

Numeric tolerance used to detect numerically zero mean predictions or concentration indices.

Value

A list of class "shap_ci_decomposition" with two components: diagnostics, a one-row data.table of decomposition diagnostics, and contributions, a data.table containing one row per SHAP feature with columns feature, D_k_SHAP, pct_contribution, and abs_contribution.

Details

The total concentration_index reported in diagnostics is the non-negative score returned by ci_factory(type). Feature contributions are computed on the signed linear scale for the selected index and then oriented so they sum to the non-negative factory score when the SHAP values reconstruct the prediction.

Percentage contributions are computed as 100 * D_k_SHAP / sum(D_k_SHAP), matching the rineq convention of dividing each CI contribution by the sum of all CI contributions. When SHAP values reconstruct the prediction, this denominator is the total concentration-index score; otherwise, additivity_gap records the difference.

For rank-dependent types, weighted fractional ranks and the same unbiased weighted covariance convention used by ci_factory() are used. "CI" divides feature covariances by the weighted mean prediction, "CIg" uses the generalized covariance form, and "CIc" applies the prediction-range correction.

For type = "L", rank is treated as an observed socioeconomic level s_i. The decomposition uses the weighted mean of ((s_i - mu_s) / mu_s) * phi_ik for each feature, where mu_s is the weighted mean socioeconomic level.

Examples

shap <- data.frame(
  education = c(1, 0, -1),
  water = c(0, 1, 1)
)
rank <- c(1, 2, 3)

res <- shap_conc_decomp(
  shap = shap,
  rank = rank,
  baseline = 2
)
res$diagnostics
#>        n weight_sum   type mean_prediction concentration_index
#>    <int>      <num> <char>           <num>               <num>
#> 1:     3          3     CI        2.666667          0.08333333
#>    signed_concentration_index score_direction   shap_sum additivity_gap
#>                         <num>           <num>      <num>          <num>
#> 1:                -0.08333333              -1 0.08333333   1.387779e-17
#>    centered_rank_sum        prediction_source
#>                <num>                   <char>
#> 1:      4.626155e-17 baseline + rowSums(shap)
res$contributions
#>      feature    D_k_SHAP pct_contribution abs_contribution
#>       <char>       <num>            <num>            <num>
#> 1: education  0.16666667              200       0.16666667
#> 2:     water -0.08333333             -100       0.08333333

dalex_like <- data.frame(
  "_id_" = rep(1:3, each = 3),
  "_vname_" = rep(c("_baseline_", "education", "water"), times = 3),
  "_attribution_" = c(2, 1, 0, 2, 0, 1, 2, -1, 1),
  check.names = FALSE
)

shap_conc_decomp(
  shap = dalex_like,
  rank = rank,
  baseline = 2,
  from_dalex = TRUE
)$contributions
#>      feature    D_k_SHAP pct_contribution abs_contribution
#>       <char>       <num>            <num>            <num>
#> 1: education  0.16666667              200       0.16666667
#> 2:     water -0.08333333             -100       0.08333333