This is the R version of Python’s Techtonique/GPopt (https://docs.techtonique.net/GPopt/GPopt.html), a package for ‘Bayesian’ optimization of black-box functions (and machine learning hyperparameter tuning) using Gaussian Process Regression and other surrogate models.
Keep in mind that this package is for Machine Learning hyperparameter tuning. The global minimum won’t always be found, but it isn’t an issue, since it means you aren’t overfitting the training set.
It’s ported the same way as nnetsauce for R was: with uv to create an isolated Python virtual environment containing the Python GPopt package, and reticulate to call into it from R. Every function in this R package is a thin wrapper that returns the underlying Python object; the general rule is: object accesses with .’s in Python are replaced by $’s in R.
See this post for the technique: Finally figured out a way to port python packages to R using uv and reticulate.
uv
# pip install uv # if necessary
uv venv venv
source venv/bin/activate # on Windows: venv\Scripts\activate
uv pip install pip GPoptKeep track of where venv/ lives – you’ll pass its path as venv_path to every function in this package.
install.packages("remotes")
remotes::install_github("Techtonique/GPopt_r") # or wherever this package is hostedreticulate will be installed automatically as a dependency.
library(GPopt)
branin <- function(x) {
x1 <- x[1]; x2 <- x[2]
term1 <- (x2 - (5.1 * x1^2) / (4 * pi^2) + (5 * x1) / pi - 6)^2
term2 <- 10 * (1 - 1 / (8 * pi)) * cos(x1)
term1 + term2 + 10
}
opt <- GPOpt(
lower_bound = c(-5, 0),
upper_bound = c(10, 15),
objective_func = branin,
n_init = 10,
n_iter = 40,
venv_path = "./venv"
)
opt$optimize(verbose = 1L)
print(opt$x_min) # current best parameters
print(opt$y_min) # current best objective value
library(GPopt)
sklearn <- get_sklearn(venv_path = "./venv")
RandomForestClassifier <- sklearn$ensemble$RandomForestClassifier
X <- as.matrix(iris[, 1:4])
y <- as.integer(iris$Species) - 1L
mlopt <- MLOptimizer(scoring = "accuracy", cv = 5, venv_path = "./venv")
param_config <- list(
n_estimators = list(bounds = c(10, 300), dtype = "int"),
max_depth = list(bounds = c(1, 20), dtype = "int")
)
mlopt$optimize(
X_train = X, y_train = y,
estimator_class = RandomForestClassifier(),
param_config = param_config,
verbose = 1L
)
print(mlopt$get_best_parameters())
print(mlopt$get_best_score())
library(GPopt)
sklearn <- get_sklearn(venv_path = "./venv")
ns <- get_nnetsauce(venv_path = "./venv")
opt <- GPOpt(
lower_bound = c(-5, 0),
upper_bound = c(10, 15),
objective_func = branin,
acquisition="ucb",
method="splitconformal",
surrogate_obj = ns$PredictionInterval(sklearn$ensemble$RandomForestRegressor()),
venv_path = "./venv"
)
opt$optimize(verbose = 1L)GPOpt() – main Bayesian optimizer (wraps GPopt.GPOpt)MLOptimizer() – cross-validated hyperparameter tuning for scikit-learn estimators (wraps GPopt.MLOptimizer)GenericSurrogate() – wrap any scikit-learn-compatible regressor as a surrogate (wraps GPopt.GenericSurrogate)GeneralizationOpt() – diagnostics for the generalization gap of hyperparameters (wraps GPopt.GeneralizationOpt)BOstopping() – Bayesian optimization with early stopping (wraps GPopt.BOstopping)get_GPopt(), get_numpy(), get_sklearn() – access the raw Python modules for anything not (yet) covered abovevenv_path argument pointing at the uv-created virtual environment; this must be the same environment across a given script/session for object identity between calls to work correctly.objective_func (or f) are called from Python with a 1-D numpy array converted back to an R numeric vector – so index with x[1], x[2], … as usual in R, not x[0], x[1], …GPopt API is available – consult the Python package’s documentation and blog posts for anything not covered in this README.