The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
{effectplots} is an R package for calculating and plotting feature effects of any model. It is very fast thanks to {collapse}.
The main function feature_effects()
crunches these
statistics per feature X over values/bins:
Furthermore, it calculates counts, weight sums, average residuals, and standard deviations of observed y and residuals. All statistics respect optional case weights.
We highly recommend Christoph Molnar’s book [3] for more info on feature effects.
It takes 1 second on a normal laptop to get all statistics for 10 features on 10 Mio rows (+ prediction time).
Workflow
feature_effects()
or
the little helpers average_observed()
,
partial_dependence()
etc.update()
:
Combine rare levels of categorical features, sort results by importance,
turn values of discrete features to factor etc.plot()
: Choose
between ggplot2/patchwork and plotly.You can install the development version of {effectplots} from GitHub with:
# install.packages("pak")
::pak("mayer79/effectplots", dependencies = TRUE) pak
We use a 1 Mio row dataset on Motor TPL insurance. The aim is to model claim frequency. Before modeling, we want to study the association between features and response.
library(effectplots)
library(OpenML)
library(lightgbm)
set.seed(1)
<- getOMLDataSet(data.id = 45106L)$data
df
<- c("year", "town", "driver_age", "car_weight", "car_power", "car_age")
xvars
# 0.1s on laptop
average_observed(df[xvars], y = df$claim_nb) |>
update(to_factor = TRUE) |>
plot(share_y = "all")
A shared y axis helps to compare the strength of the association across features.
Next, let’s fit a boosted trees model.
<- sample(nrow(df), 0.8 * nrow(df))
ix <- df[ix, ]
train <- df[-ix, ]
test <- data.matrix(train[xvars])
X_train <- data.matrix(test[xvars])
X_test
# Training, using slightly optimized parameters found via cross-validation
<- list(
params learning_rate = 0.05,
objective = "poisson",
num_leaves = 7,
min_data_in_leaf = 50,
min_sum_hessian_in_leaf = 0.001,
colsample_bynode = 0.8,
bagging_fraction = 0.8,
lambda_l1 = 3,
lambda_l2 = 5,
num_threads = 7
)
<- lgb.train(
fit params = params,
data = lgb.Dataset(X_train, label = train$claim_nb),
nrounds = 300
)
Let’s crunch all statistics on the test data. Sorting is done by weighted variance of partial dependence, a main-effect importance measure related to [4].
The average predictions closely follow the average observed, i.e., the model seems to do a good job. Comparing partial dependence/ALE with average predicted gives insights on whether an effect mainly comes from the feature on the x axis or from other, correlated, features.
# 0.1s + 0.15s prediction time
feature_effects(fit, v = xvars, data = X_test, y = test$claim_nb) |>
update(sort_by = "pd") |>
plot()
What about combining training and test results? Or comparing different models or subgroups? No problem:
<- feature_effects(fit, v = xvars, data = X_train, y = train$claim_nb)
m_train <- feature_effects(fit, v = xvars, data = X_test, y = test$claim_nb)
m_test
# Pick top 3 based on train
<- m_train |>
m_train update(sort_by = "pd") |>
head(3)
<- m_test[names(m_train)]
m_test
# Concatenate train and test results and plot them
c(m_train, m_test) |>
plot(
share_y = "rows",
ncol = 2,
byrow = FALSE,
stats = c("y_mean", "pred_mean"),
subplot_titles = FALSE,
# plotly = TRUE,
title = "Left: Train - Right: Test",
)
To look closer at bias, let’s select the statistic “resid_mean” along with pointwise 95% confidence intervals for the true conditional bias.
c(m_train, m_test) |>
update(drop_below_n = 50) |>
plot(
ylim = c(-0.07, 0.08),
ncol = 2,
byrow = FALSE,
stats = "resid_mean",
subplot_titles = FALSE,
title = "Left: Train - Right: Test",
# plotly = TRUE,
interval = "ci"
)
Most models work out-of-the box, including DALEX explainers and Tidymodels models. If not, a tailored prediction function can be specified.
library(effectplots)
library(DALEX)
library(ranger)
set.seed(1)
<- ranger(Sepal.Length ~ ., data = iris)
fit <- DALEX::explain(fit, data = iris[, -1], y = iris[, 1])
ex
feature_effects(ex, breaks = 5) |>
plot(share_y = "all")
Note that ALE plots are only available for continuous variables.
library(effectplots)
library(tidymodels)
set.seed(1)
<- c("carat", "color", "clarity", "cut")
xvars
<- initial_split(diamonds)
split <- training(split)
train <- testing(split)
test
<- train |>
dia_recipe recipe(reformulate(xvars, "price"))
<- rand_forest(trees = 100) |>
mod set_engine("ranger") |>
set_mode("regression")
<- workflow() |>
dia_wf add_recipe(dia_recipe) |>
add_model(mod)
<- dia_wf |>
fit fit(train)
<- feature_effects(fit, v = xvars, data = train, y = "price")
M_train <- feature_effects(fit, v = xvars, data = test, y = "price")
M_test
plot(
+ M_test,
M_train byrow = FALSE,
ncol = 2,
share_y = "rows",
rotate_x = rep(45 * xvars %in% c("clarity", "cut"), each = 2),
subplot_titles = FALSE,
# plotly = TRUE,
title = "Left: train - Right: test"
)
We focus on a single class.
library(effectplots)
library(ranger)
set.seed(1)
<- ranger(Species ~ ., data = iris, probability = TRUE)
fit
<- partial_dependence(
M
fit,v = colnames(iris[1:4]),
data = iris,
which_pred = 1 # "setosa" is the first class
)plot(M, bar_height = 0.33, ylim = c(0, 0.7))
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.