classbound is an R package for exploring and comparing classification decision boundaries. It provides a unified interface for fitting classifiers, computing 2D boundary grids, and visualizing how different models partition the feature space.
What you can do with classbound:
- Visualize decision boundaries for any R classifier
- Compare multiple classifiers side by side
- Handle high-dimensional data via 2D slicing or projection (PCA, tourr)
- View probability surfaces for classifiers that provide them
- Explore data interactively using the built-in Shiny app (
explorapp()) - Integrate natively with
tidymodelsworkflows
Full documentation: https://natydasilva.github.io/classbound/
Installation
Install the released version from CRAN:
install.packages("classbound")Or the development version from GitHub:
devtools::install_github("natydasilva/classbound")Quick start
One-step wrapper
classbound() fits a model, computes its decision boundary, and plots the result in a single call.
library(classbound)
library(palmerpenguins)
penguins <- na.omit(palmerpenguins::penguins[
,
c("species", "bill_length_mm", "bill_depth_mm")
])
classbound(
data = penguins,
formula = species ~ bill_length_mm + bill_depth_mm,
classifier = rpart::rpart
)
Modular pipeline
For full control, use the three-step pipeline:
# 1. Fit
model <- fit_model(penguins, species ~ bill_length_mm + bill_depth_mm, rpart::rpart)
# 2. Compute boundary
model <- boundary_compute(model)
# 3. Plot
plot_boundary(
model,
obs_data = penguins,
x_col = "bill_length_mm",
y_col = "bill_depth_mm",
true_label = "species"
)
boundary_compute() returns the model with the grid attached, so you can replot with different settings without refitting.
Interactive workflow
Launch the built-in Shiny application for point-and-click exploration:
# Start with your own dataset
explorapp(data = penguins, target_col = "species")
# Or start empty and simulate/draw data
explorapp()In explorapp() you can: - Import real data or simulate synthetic datasets - Draw classification data by hand - Fit and compare multiple classifiers simultaneously - Switch between 2D Slice and Projection views for high-dimensional data - Inject outliers and observe how boundaries shift - Inspect probability surfaces (for supported classifiers) - Export data, models, plots, and a reproduce script
Two main workflows
Interactive
Use explorapp() to:
- Choose or create data
- Choose models
- Explore decision boundaries
- Navigate, zoom, and draw
- Compare models and export results
High-dimensional data
When a model is trained on more than two features, boundary_compute() supports:
- 2D Slice: two features are plotted; other features are fixed at their median/mode.
penguins3 <- na.omit(palmerpenguins::penguins[
,
c("species", "bill_length_mm", "bill_depth_mm", "flipper_length_mm")
])
m3 <- fit_model(penguins3, species ~ ., rpart::rpart)
m3_slice <- boundary_compute(m3,
feature_range = list(bill_length_mm = c(30, 60), bill_depth_mm = c(10, 25)),
resolution = 60
)
plot_boundary(m3_slice,
obs_data = penguins3,
x_col = "bill_length_mm", y_col = "bill_depth_mm",
true_label = "species"
)
- Projection: the axes are two linear combinations of all features (e.g., PCA). The regions are the model’s predictions on that plane through the data center, and the observations are projected onto it.
feat_cols <- c("bill_length_mm", "bill_depth_mm", "flipper_length_mm")
pca <- prcomp(penguins3[, feat_cols], scale. = TRUE)
basis <- pca$rotation[, 1:2]
x_std <- scale(penguins3[, feat_cols], center = pca$center, scale = pca$scale)
z_mat <- x_std %*% basis
m3_proj <- boundary_compute(m3,
feature_range = list(
PC1 = range(z_mat[, 1]) + c(-0.5, 0.5),
PC2 = range(z_mat[, 2]) + c(-0.5, 0.5)
),
resolution = 60,
projection = list(basis = basis, center = pca$center, scale = pca$scale)
)
plot_boundary(m3_proj,
obs_data = penguins3,
x_col = "PC1", y_col = "PC2", true_label = "species"
)
See the high-dimensional guide for a full explanation.
Multi-model comparison with tidymodels
library(parsnip)
library(workflowsets)
spec_tree <- decision_tree(mode = "classification") |> set_engine("rpart")
spec_rf <- rand_forest(mode = "classification") |> set_engine("randomForest")
wf_set <- workflow_set(
preproc = list(base = species ~ bill_length_mm + bill_depth_mm),
models = list(tree = spec_tree, forest = spec_rf)
)
bounds <- boundary_workflow_set(wf_set,
data = penguins,
response = "species", resolution = 60
)
plot_boundary(bounds,
obs_data = penguins,
x_col = "bill_length_mm", y_col = "bill_depth_mm",
true_label = "species"
)
Documentation
| Resource | Link |
|---|---|
| Getting Started | getting-started |
| High-Dimensional | high-dimensional |
| tidymodels | tidymodels-workflow |
| tourr | tourr-workflow |
| Explorapp Guide | explorapp-guide |
| Custom Adapters | custom_adapters |
| Reference | Function Reference |