test_that("error with custom model without providing predict_model", {
set.seed(123)
expect_snapshot(
{
# Custom model with no predict_model
model_custom_lm_mixed <- model_lm_mixed
class(model_custom_lm_mixed) <- "whatever"
explain(
testing = TRUE,
model = model_custom_lm_mixed,
x_train = x_train_mixed,
x_explain = x_explain_mixed,
approach = "independence",
phi0 = p0
)
},
error = TRUE
)
})
test_that("messages with missing detail in get_model_specs", {
set.seed(123)
model_custom_lm_mixed <- model_lm_mixed
class(model_custom_lm_mixed) <- "whatever"
custom_predict_model <- function(x, newdata) {
beta <- coef(x)
X <- model.matrix(~., newdata)
return(as.vector(beta %*% t(X)))
}
expect_snapshot({
# Custom model with no get_model_specs
explain(
testing = TRUE,
model = model_custom_lm_mixed,
x_train = x_train_mixed,
x_explain = x_explain_mixed,
approach = "independence",
phi0 = p0,
predict_model = custom_predict_model,
get_model_specs = NA
)
})
expect_snapshot({
# Custom model where get_model_specs gives NA-labels
custom_get_model_specs_no_lab <- function(x) {
feature_specs <- list(labels = NA, classes = NA, factor_levels = NA)
}
explain(
testing = TRUE,
model = model_custom_lm_mixed,
x_train = x_train_mixed,
x_explain = x_explain_mixed,
approach = "independence",
phi0 = p0,
predict_model = custom_predict_model,
get_model_specs = custom_get_model_specs_no_lab
)
})
expect_snapshot({
# Custom model where get_model_specs gives NA-classes
custom_gms_no_classes <- function(x) {
feature_specs <- list(labels = labels(x$terms), classes = NA, factor_levels = NA)
}
explain(
testing = TRUE,
model = model_custom_lm_mixed,
x_train = x_train_mixed,
x_explain = x_explain_mixed,
approach = "independence",
phi0 = p0,
predict_model = custom_predict_model,
get_model_specs = custom_gms_no_classes
)
})
expect_snapshot({
# Custom model where get_model_specs gives NA-factor levels
custom_gms_no_factor_levels <- function(x) {
feature_specs <- list(
labels = labels(x$terms),
classes = attr(x$terms, "dataClasses")[-1],
factor_levels = NA
)
}
explain(
testing = TRUE,
model = model_custom_lm_mixed,
x_train = x_train_mixed,
x_explain = x_explain_mixed,
approach = "independence",
phi0 = p0,
predict_model = custom_predict_model,
get_model_specs = custom_gms_no_factor_levels
)
})
})
test_that("erroneous input: `x_train/x_explain`", {
set.seed(123)
expect_snapshot(
{
# not matrix or data.table 1
x_train_wrong_format <- c(a = 1, b = 2)
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_wrong_format,
approach = "independence",
phi0 = p0
)
},
error = TRUE
)
expect_snapshot(
{
# not matrix or data.table 2
x_explain_wrong_format <- c(a = 1, b = 2)
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_wrong_format,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0
)
},
error = TRUE
)
expect_snapshot(
{
# not matrix or data.table 3
x_train_wrong_format <- c(a = 1, b = 2)
x_explain_wrong_format <- c(a = 3, b = 4)
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_wrong_format,
x_train = x_train_wrong_format,
approach = "independence",
phi0 = p0
)
},
error = TRUE
)
expect_snapshot(
{
# missing column names x_train
x_train_no_column_names <- as.data.frame(x_train_numeric)
names(x_train_no_column_names) <- NULL
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_no_column_names,
approach = "independence",
phi0 = p0
)
},
error = TRUE
)
expect_snapshot(
{
# missing column names x_explain
x_explain_no_column_names <- as.data.frame(x_explain_numeric)
names(x_explain_no_column_names) <- NULL
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_no_column_names,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0
)
},
error = TRUE
)
expect_snapshot(
{
# missing column names in both x_train and x_explain
x_train_no_column_names <- as.data.frame(x_train_numeric)
x_explain_no_column_names <- as.data.frame(x_explain_numeric)
names(x_explain_no_column_names) <- NULL
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_no_column_names,
x_train = x_train_no_column_names,
approach = "independence",
phi0 = p0
)
},
error = TRUE
)
})
test_that("erroneous input: `model`", {
# R versions earlier than 4.3 gives assigns the error to the internal function instead of the explain_forecast,
# and therefore marks this as an error (which it is not)
Rversion_number <- as.numeric(paste0(R.version$major, R.version$minor))
skip_if_not(Rversion_number >= 43)
set.seed(123)
expect_snapshot(
{
# no model passed
explain(
testing = TRUE,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0
)
},
error = TRUE
)
})
test_that("erroneous input: `approach`", {
set.seed(123)
expect_snapshot(
{
# not a character (vector)
approach_non_character <- 1
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = approach_non_character,
phi0 = p0
)
},
error = TRUE
)
expect_snapshot(
{
# incorrect length
approach_incorrect_length <- c("empirical", "gaussian")
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = approach_incorrect_length,
phi0 = p0
)
},
error = TRUE
)
expect_snapshot(
{
# incorrect character
approach_incorrect_character <- "bla"
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = approach_incorrect_character,
phi0 = p0
)
},
error = TRUE
)
})
test_that("erroneous input: `phi0`", {
set.seed(123)
expect_snapshot(
{
# non-numeric 1
p0_non_numeric_1 <- "bla"
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0_non_numeric_1
)
},
error = TRUE
)
expect_snapshot(
{
# non-numeric 2
p0_non_numeric_2 <- NULL
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0_non_numeric_2
)
},
error = TRUE
)
expect_snapshot(
{
# length > 1
p0_too_long <- c(1, 2)
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0_too_long
)
},
error = TRUE
)
expect_snapshot(
{
# NA-numeric
p0_is_NA <- as.numeric(NA)
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0_is_NA
)
},
error = TRUE
)
})
test_that("erroneous input: `max_n_coalitions`", {
set.seed(123)
expect_snapshot(
{
# non-numeric 1
max_n_comb_non_numeric_1 <- "bla"
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
max_n_coalitions = max_n_comb_non_numeric_1
)
},
error = TRUE
)
expect_snapshot(
{
# non-numeric 2
max_n_comb_non_numeric_2 <- TRUE
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
max_n_coalitions = max_n_comb_non_numeric_2
)
},
error = TRUE
)
expect_snapshot(
{
# non-integer
max_n_coalitions_non_integer <- 10.5
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
max_n_coalitions = max_n_coalitions_non_integer
)
},
error = TRUE
)
expect_snapshot(
{
# length > 1
max_n_coalitions_too_long <- c(1, 2)
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
max_n_coalitions = max_n_coalitions_too_long
)
},
error = TRUE
)
expect_snapshot(
{
# NA-numeric
max_n_coalitions_is_NA <- as.numeric(NA)
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
max_n_coalitions = max_n_coalitions_is_NA
)
},
error = TRUE
)
expect_snapshot(
{
# Non-positive
max_n_comb_non_positive <- 0
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
max_n_coalitions = max_n_comb_non_positive
)
},
error = TRUE
)
expect_snapshot({
# Too low max_n_coalitions (smaller than # features
max_n_coalitions <- ncol(x_explain_numeric) - 1
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
phi0 = p0,
approach = "gaussian",
max_n_coalitions = max_n_coalitions
)
})
expect_snapshot({
# Too low max_n_coalitions (smaller than # groups
groups <- list(
A = c("Solar.R", "Wind"),
B = c("Temp", "Month"),
C = "Day"
)
max_n_coalitions <- length(groups) - 1
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
phi0 = p0,
approach = "gaussian",
group = groups,
max_n_coalitions = max_n_coalitions
)
})
})
test_that("erroneous input: `group`", {
set.seed(123)
expect_snapshot(
{
# not a list
group_non_list <- "bla"
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
group = group_non_list
)
},
error = TRUE
)
expect_snapshot(
{
# non-characters in list
group_with_non_characters <- list(A = 1, B = 2)
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
group = group_with_non_characters
)
},
error = TRUE
)
expect_snapshot(
{
# group features not in data
group_with_non_data_features <- list(
A = c("Solar.R", "Wind", "not_a_data_feature"),
B = c("Temp", "Month", "Day")
)
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
group = group_with_non_data_features
)
},
error = TRUE
)
expect_snapshot(
{
# missing feature in group
group_missing_data_features <- list(
A = c("Solar.R"),
B = c("Temp", "Month", "Day")
)
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
group = group_missing_data_features
)
},
error = TRUE
)
expect_snapshot(
{
# missing feature in group
group_dup_data_features <- list(
A = c("Solar.R", "Solar.R", "Wind"),
B = c("Temp", "Month", "Day")
)
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
group = group_dup_data_features
)
},
error = TRUE
)
expect_snapshot(
{
# a single group only
single_group <- list(A = c("Solar.R", "Wind", "Temp", "Month", "Day"))
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
group = single_group
)
},
error = TRUE
)
})
test_that("erroneous input: `n_MC_samples`", {
set.seed(123)
expect_snapshot(
{
# non-numeric 1
n_samples_non_numeric_1 <- "bla"
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
n_MC_samples = n_samples_non_numeric_1
)
},
error = TRUE
)
expect_snapshot(
{
# non-numeric 2
n_samples_non_numeric_2 <- TRUE
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
n_MC_samples = n_samples_non_numeric_2
)
},
error = TRUE
)
expect_snapshot(
{
# non-integer
n_samples_non_integer <- 10.5
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
n_MC_samples = n_samples_non_integer
)
},
error = TRUE
)
# length > 1
expect_snapshot(
{
n_samples_too_long <- c(1, 2)
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
n_MC_samples = n_samples_too_long
)
},
error = TRUE
)
# NA-numeric
expect_snapshot(
{
n_samples_is_NA <- as.numeric(NA)
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
n_MC_samples = n_samples_is_NA
)
},
error = TRUE
)
# Non-positive
expect_snapshot(
{
n_samples_non_positive <- 0
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
n_MC_samples = n_samples_non_positive
)
},
error = TRUE
)
})
test_that("erroneous input: `seed`", {
set.seed(123)
# Not interpretable as integer
expect_snapshot(
{
seed_not_integer_interpretable <- "bla"
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
seed = seed_not_integer_interpretable
)
},
error = TRUE
)
})
test_that("erroneous input: `keep_samp_for_vS`", {
set.seed(123)
# non-logical 1
expect_snapshot(
{
keep_samp_for_vS_non_logical_1 <- "bla"
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
output_args = list(keep_samp_for_vS = keep_samp_for_vS_non_logical_1)
)
},
error = TRUE
)
# non-logical 2
expect_snapshot(
{
keep_samp_for_vS_non_logical_2 <- NULL
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
output_args = list(keep_samp_for_vS = keep_samp_for_vS_non_logical_2)
)
},
error = TRUE
)
# length > 1
expect_snapshot(
{
keep_samp_for_vS_too_long <- c(TRUE, FALSE)
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
output_args = list(keep_samp_for_vS = keep_samp_for_vS_too_long)
)
},
error = TRUE
)
})
test_that("erroneous input: `MSEv_uniform_comb_weights`", {
set.seed(123)
# non-logical 1
expect_snapshot(
{
MSEv_uniform_comb_weights_nl_1 <- "bla"
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
output_args = list(MSEv_uniform_comb_weights = MSEv_uniform_comb_weights_nl_1)
)
},
error = TRUE
)
# non-logical 2
expect_snapshot(
{
MSEv_uniform_comb_weights_nl_2 <- NULL
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
output_args = list(MSEv_uniform_comb_weights = MSEv_uniform_comb_weights_nl_2)
)
},
error = TRUE
)
# length > 1
expect_snapshot(
{
MSEv_uniform_comb_weights_long <- c(TRUE, FALSE)
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
output_args = list(MSEv_uniform_comb_weights = MSEv_uniform_comb_weights_long)
)
},
error = TRUE
)
})
test_that("erroneous input: `predict_model`", {
set.seed(123)
# not a function
expect_snapshot(
{
predict_model_nonfunction <- "bla"
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
predict_model = predict_model_nonfunction
)
},
error = TRUE
)
expect_snapshot(
{
# non-numeric output
predict_model_non_num_output <- function(model, x) {
"bla"
}
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
predict_model = predict_model_non_num_output
)
},
error = TRUE
)
expect_snapshot(
{
# incorrect output length
predict_model_wrong_output_len <- function(model, x) {
rep(1, nrow(x) + 1)
}
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
predict_model = predict_model_wrong_output_len
)
},
error = TRUE
)
expect_snapshot(
{
# invalid function format
predict_model_invalid_argument <- function(model) {
rep(1, nrow(x))
}
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
predict_model = predict_model_invalid_argument
)
},
error = TRUE
)
expect_snapshot(
{
# error within function
predict_model_error <- function(model, x) {
1 + "bla"
}
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
predict_model = predict_model_error
)
},
error = TRUE
)
})
test_that("erroneous input: `get_model_specs`", {
set.seed(123)
expect_snapshot(
{
# not a function
get_model_specs_nonfunction <- "bla"
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
get_model_specs = get_model_specs_nonfunction
)
},
error = TRUE
)
expect_snapshot(
{
# wrong output (not list)
get_ms_output_not_list <- function(x) {
"bla"
}
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
get_model_specs = get_ms_output_not_list
)
},
error = TRUE
)
expect_snapshot(
{
# wrong output (wrong length)
get_ms_output_too_long <- function(x) {
list(1, 2, 3, 4)
}
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
get_model_specs = get_ms_output_too_long
)
},
error = TRUE
)
expect_snapshot(
{
# wrong output (wrong length)
get_ms_output_wrong_names <- function(x) {
list(
labels = 1,
classes = 2,
not_a_name = 3
)
}
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
get_model_specs = get_ms_output_wrong_names
)
},
error = TRUE
)
expect_snapshot(
{
# wrong output (wrong length)
get_model_specs_error <- function(x) {
1 + "bla"
}
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "independence",
phi0 = p0,
get_model_specs = get_model_specs_error
)
},
error = TRUE
)
})
test_that("incompatible input: `data/approach`", {
set.seed(123)
expect_snapshot(
{
# factor model/data with approach gaussian
non_factor_approach_1 <- "gaussian"
explain(
testing = TRUE,
model = model_lm_mixed,
x_explain = x_explain_mixed,
x_train = x_explain_mixed,
approach = non_factor_approach_1,
phi0 = p0
)
},
error = TRUE
)
expect_snapshot(
{
# factor model/data with approach empirical
non_factor_approach_2 <- "empirical"
explain(
testing = TRUE,
model = model_lm_mixed,
x_explain = x_explain_mixed,
x_train = x_explain_mixed,
approach = non_factor_approach_2,
phi0 = p0
)
},
error = TRUE
)
expect_snapshot(
{
# factor model/data with approach copula
non_factor_approach_3 <- "copula"
explain(
testing = TRUE,
model = model_lm_mixed,
x_explain = x_explain_mixed,
x_train = x_explain_mixed,
approach = non_factor_approach_3,
phi0 = p0
)
},
error = TRUE
)
})
test_that("Correct dimension of S when sampling combinations", {
max_n_coalitions <- 10
res <- explain(
testing = TRUE,
model = model_lm_mixed,
x_explain = x_explain_mixed,
x_train = x_explain_mixed,
phi0 = p0,
approach = "ctree",
max_n_coalitions = max_n_coalitions
)
expect_equal(nrow(res$internal$objects$S), max_n_coalitions)
})
test_that("Message with too low `max_n_coalitions`", {
max_n_coalitions <- ncol(x_explain_numeric) - 1
expect_snapshot(
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_explain_numeric,
phi0 = p0,
approach = "gaussian",
max_n_coalitions = max_n_coalitions
)
)
# Same for groups
groups <- list(
A = c("Solar.R", "Wind"),
B = c("Temp", "Month"),
C = "Day"
)
max_n_coalitions <- length(groups) - 1
expect_snapshot(
explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_explain_numeric,
phi0 = p0,
approach = "gaussian",
group = groups,
max_n_coalitions = max_n_coalitions
)
)
})
test_that("Shapr with `max_n_coalitions` >= 2^m uses exact Shapley kernel weights", {
# Check that the `explain()` function enters the exact mode when max_n_coalitions
# is larger than or equal to 2^m.
# Create three explainer object: one with exact mode, one with
# `max_n_coalitions` = 2^m, and one with `max_n_coalitions` > 2^m
# No message as n_combination = NULL sets exact mode
expect_snapshot(
explanation_exact <- explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "gaussian",
phi0 = p0,
n_MC_samples = 2, # Low value for fast computations
seed = 123,
max_n_coalitions = NULL,
iterative = FALSE
)
)
expect_snapshot(
explanation_equal <- explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "gaussian",
phi0 = p0,
n_MC_samples = 2, # Low value for fast computations
seed = 123,
extra_computation_args = list(compute_sd = FALSE),
max_n_coalitions = 2^ncol(x_explain_numeric),
iterative = FALSE
)
)
# We should get a message saying that we are using the exact mode.
# The `regexp` format match the one written in `create_coalition_table()`.
expect_snapshot(
explanation_larger <- explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "gaussian",
phi0 = p0,
n_MC_samples = 2, # Low value for fast computations
seed = 123,
extra_computation_args = list(compute_sd = FALSE),
max_n_coalitions = 2^ncol(x_explain_numeric) + 1,
iterative = FALSE
)
)
# Test that returned objects are identical (including all using the exact option and having the same Shapley weights)
expect_equal(
explanation_exact,
explanation_equal
)
expect_equal(
explanation_exact,
explanation_larger
)
# Explicitly check that exact mode is set and that max_n_coalitions equals 2^ncol(x_explain_numeric) (32)
# Since all 3 explanation objects are equal (per the above test) it suffices to do this for explanation_exact
expect_true(
explanation_exact$internal$parameters$exact
)
expect_equal(
explanation_exact$internal$objects$X[, .N],
2^ncol(x_explain_numeric)
)
})
test_that("Correct dimension of S when sampling combinations with groups", {
max_n_coalitions <- 6
groups <- list(
A = c("Solar.R", "Wind"),
B = c("Temp", "Month_factor"),
C = "Day"
)
res <- explain(
testing = TRUE,
model = model_lm_mixed,
x_explain = x_explain_mixed,
x_train = x_explain_mixed,
phi0 = p0,
approach = "ctree",
group = groups,
max_n_coalitions = max_n_coalitions
)
expect_equal(nrow(res$internal$objects$S), max_n_coalitions)
})
test_that("data feature ordering is output_lm_numeric_column_order", {
explain.original <- explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "empirical",
phi0 = p0
)
ex.new_data_feature_order <- explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = rev(x_explain_numeric),
x_train = rev(x_train_numeric),
approach = "empirical",
phi0 = p0
)
explain.new_model_feat_order <- explain(
testing = TRUE,
model = model_lm_numeric_col_order,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "empirical",
phi0 = p0
)
# Same Shapley values, but different order
expect_false(identical(
explain.original$shapley_values_est,
ex.new_data_feature_order$shapley_values_est
))
expect_equal(
explain.original$shapley_values_est[, mget(sort(names(explain.original$shapley_values_est)))],
ex.new_data_feature_order$shapley_values_est[, mget(sort(names(ex.new_data_feature_order$shapley_values_est)))]
)
# Same Shapley values in same order
expect_equal(explain.original, explain.new_model_feat_order)
})
test_that("parallelization gives same output for any approach", {
testthat::skip_on_cran() # Avoiding CRAN Note: Running R code in ‘testthat.R’ had CPU time 3.6 times elapsed time
# Empirical is seed independent
explain.empirical_sequential <- explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "empirical",
phi0 = p0
)
future::plan("multisession", workers = 2) # Parallelized with 2 cores
explain.empirical_multisession <- explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "empirical",
phi0 = p0
)
future::plan("sequential") # Resetting to sequential computation
# Identical results
expect_equal(
explain.empirical_sequential,
explain.empirical_multisession
)
# ctree is seed NOT independent
explain.ctree_sequential <- explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "ctree",
phi0 = p0
)
future::plan("multisession", workers = 2) # Parallelized with 2 cores
explain.ctree_multisession <- explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "ctree",
phi0 = p0
)
future::plan("sequential") # Resetting to sequential computation
# Identical results also for seed dependent methods.
expect_equal(
explain.ctree_sequential,
explain.ctree_multisession
)
})
test_that("gaussian approach use the user provided parameters", {
# approach "gaussian" with default parameter estimation, i.e., sample mean and covariance
e.gaussian_samp_mean_cov <- explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "gaussian",
phi0 = p0,
)
# Expect that gaussian.mu is the sample mean when no values are provided
expect_equal(
e.gaussian_samp_mean_cov$internal$parameters$gaussian.mu,
colMeans(unname(x_train_numeric))
)
# Expect that gaussian.cov_mat is the sample covariance when no values are provided
expect_equal(
e.gaussian_samp_mean_cov$internal$parameters$gaussian.cov_mat,
cov(x_train_numeric)
)
# Provide parameter values for the Gaussian approach
gaussian.provided_mu <- seq_len(ncol(x_train_numeric)) # 1,2,3,4,5
gaussian.provided_cov_mat <- diag(ncol(x_train_numeric))
# approach "gaussian" with provided parameters
e.gaussian_provided_mean_cov <- explain(
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "gaussian",
phi0 = p0,
gaussian.mu = gaussian.provided_mu,
gaussian.cov_mat = gaussian.provided_cov_mat
)
# Expect that the gaussian.mu parameter is the same as the provided gaussian.provided_mu
expect_equal(
e.gaussian_provided_mean_cov$internal$parameters$gaussian.mu,
gaussian.provided_mu
)
# Expect that gaussian.cov_mat is the same as the provided gaussian.provided_cov_mat
expect_equal(
e.gaussian_provided_mean_cov$internal$parameters$gaussian.cov_mat,
gaussian.provided_cov_mat
)
})
test_that("setting the seed for combined approaches works", {
# Check that setting the seed works for a combination of approaches
explanation_combined_1 <- explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = c("independence", "empirical", "gaussian", "copula"),
phi0 = p0,
seed = 1
)
explanation_combined_2 <- explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = c("independence", "empirical", "gaussian", "copula"),
phi0 = p0,
seed = 1
)
# Check that they are equal
expect_equal(explanation_combined_1, explanation_combined_2)
})
test_that("counting the number of unique approaches", {
# Test several combinations of combined approaches and check that the number of
# counted unique approaches is correct.
# Recall that the last approach is not counted in `n_unique_approaches` as
# we do not use it as we then condition on all features.
explanation_combined_1 <- explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = c("independence", "empirical", "gaussian", "copula"),
phi0 = p0,
seed = 1
)
expect_equal(explanation_combined_1$internal$parameters$n_approaches, 4)
expect_equal(explanation_combined_1$internal$parameters$n_unique_approaches, 4)
explanation_combined_2 <- explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = c("empirical"),
phi0 = p0,
seed = 1
)
expect_equal(explanation_combined_2$internal$parameters$n_approaches, 1)
expect_equal(explanation_combined_2$internal$parameters$n_unique_approaches, 1)
explanation_combined_3 <- explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = c("gaussian", "gaussian", "gaussian", "gaussian"),
phi0 = p0,
seed = 1
)
expect_equal(explanation_combined_3$internal$parameters$n_approaches, 4)
expect_equal(explanation_combined_3$internal$parameters$n_unique_approaches, 1)
explanation_combined_4 <- explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = c("independence", "empirical", "independence", "empirical"),
phi0 = p0,
seed = 1
)
expect_equal(explanation_combined_4$internal$parameters$n_approaches, 4)
expect_equal(explanation_combined_4$internal$parameters$n_unique_approaches, 2)
# Check that the last one is not counted
explanation_combined_5 <- explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = c("independence", "empirical", "independence", "empirical"),
phi0 = p0,
seed = 1
)
expect_equal(explanation_combined_5$internal$parameters$n_approaches, 4)
expect_equal(explanation_combined_5$internal$parameters$n_unique_approaches, 2)
})
test_that("vaeac_set_seed_works", {
skip_if_not(torch::torch_is_installed())
# Train two vaeac models with the same seed
explanation_vaeac_1 <- explain(
testing = TRUE,
model = model_lm_mixed,
x_explain = x_explain_mixed,
x_train = x_train_mixed,
approach = "vaeac",
phi0 = p0,
n_MC_samples = 10,
seed = 1,
vaeac.epochs = 4,
vaeac.n_vaeacs_initialize = 2,
vaeac.extra_parameters = list(
vaeac.epochs_initiation_phase = 2
),
iterative = FALSE
)
explanation_vaeac_2 <- explain(
testing = TRUE,
model = model_lm_mixed,
x_explain = x_explain_mixed,
x_train = x_train_mixed,
approach = "vaeac",
phi0 = p0,
n_MC_samples = 10,
seed = 1,
vaeac.epochs = 4,
vaeac.n_vaeacs_initialize = 2,
vaeac.extra_parameters = list(
vaeac.epochs_initiation_phase = 2
),
iterative = FALSE
)
# Check for equal Shapley values
expect_equal(explanation_vaeac_1$shapley_values_est, explanation_vaeac_2$shapley_values_est)
})
test_that("vaeac_pretreained_vaeac_model", {
skip_if_not(torch::torch_is_installed())
# Test that we can skip training a new vaeac model if we already
# have trained it in a previous shapr::explain object.
explanation_vaeac_1 <- explain(
testing = TRUE,
model = model_lm_mixed,
x_explain = x_explain_mixed,
x_train = x_train_mixed,
approach = "vaeac",
phi0 = p0,
n_MC_samples = 10,
seed = 1,
vaeac.epochs = 4,
vaeac.n_vaeacs_initialize = 2,
vaeac.extra_parameters = list(
vaeac.epochs_initiation_phase = 2
),
iterative = FALSE
)
#### We can do this by reusing the vaeac model OBJECT
# Get the pretrained vaeac model object
vaeac.pretrained_vaeac_model <- explanation_vaeac_1$internal$parameters$vaeac
# send the pre-trained vaeac model to the explain function
explanation_pretrained_vaeac <- explain(
testing = TRUE,
model = model_lm_mixed,
x_explain = x_explain_mixed,
x_train = x_train_mixed,
approach = "vaeac",
phi0 = p0,
n_MC_samples = 10,
seed = 1,
vaeac.extra_parameters = list(
vaeac.pretrained_vaeac_model = vaeac.pretrained_vaeac_model
),
iterative = FALSE
)
# Check for equal Shapley values
expect_equal(explanation_vaeac_1$shapley_values_est, explanation_pretrained_vaeac$shapley_values_est)
#### We can also do this by reusing the vaeac model PATH
# Get the pre-trained vaeac model path
vaeac.pretrained_vaeac_path <- explanation_vaeac_1$internal$parameters$vaeac$models$best
# send the pre-trained vaeac model to the explain function
explanation_pretrained_vaeac <- explain(
testing = TRUE,
model = model_lm_mixed,
x_explain = x_explain_mixed,
x_train = x_train_mixed,
approach = "vaeac",
phi0 = p0,
n_MC_samples = 10,
seed = 1,
vaeac.extra_parameters = list(
vaeac.pretrained_vaeac_model = vaeac.pretrained_vaeac_path
),
iterative = FALSE
)
# Check for equal Shapley values
expect_equal(explanation_vaeac_1$shapley_values_est, explanation_pretrained_vaeac$shapley_values_est)
})
test_that("feature wise and groupwise computations are identical", {
groups <- list(
Solar.R = "Solar.R",
Wind = "Wind",
Temp = "Temp",
Month = "Month",
Day = "Day"
)
expl_feat <- explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "gaussian",
phi0 = p0
)
expl_group <- explain(
testing = TRUE,
model = model_lm_numeric,
x_explain = x_explain_numeric,
x_train = x_train_numeric,
approach = "gaussian",
group = groups,
phi0 = p0
)
# Checking equality in the list with all final and intermediate results
expect_equal(expl_feat$shapley_values_est, expl_group$shapley_values_est)
})
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.