Observed since 20 Oct, 19:06 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
AGS (Adaptive Greedy Search): a surrogate-guided, multi-climber swarm search over discrete hyperparameter grids, with plateau escape and pruned cross-validation.
Surrogate-guided hyperparameter search over a discrete grid, using a swarm of independent greedy climbers that share one surrogate model, one evaluation cache, and one fold-level pruning engine.
from ags import AdaptiveGreedySearch
GridSearchCV evaluates every combination — correct, but wasteful once
the grid gets large. RandomizedSearchCV is cheap but has no memory:
it never uses what it already learned from earlier trials to pick the
next one. Bayesian approaches like Optuna's TPE fix that by modeling
which regions of the space look promising, but a general-purpose
sampler still spends full cross-validation budget on every trial, good
or bad, and searches from a single point of view.
AGS combines these ideas for the specific case of a discrete hyperparameter grid:
n_climbers climbers are seeded at
maximally distant starting points on the grid (Max-Min / farthest-point
sampling) and search concurrently. Each step, every active climber
proposes its best surrogate-scored neighbor; duplicate proposals are
resolved immediately (the lagging climber is retired, not evaluated
twice), and the whole batch is evaluated in parallel via joblib.max_neighbor_radius) and jumps to the best unvisited state it finds,
rather than falling back to scanning the whole grid.climber_patience steps is retired and replaced — while budget
remains — at the unvisited state with the highest surrogate
uncertainty, actively pulling the swarm toward unexplored territory."optimistic") or statistically ("percentile")
out of contention against the best result seen so far.The result: a fixed evaluation budget is spent exploring several basins of the hyperparameter space at once instead of committing early to one, while still cutting the inside of each evaluation (the CV folds), not just the number of evaluations.
Where it's not the right tool: landscapes where quality is scattered with no local structure (grid distance doesn't correlate with performance — the surrogate and the climbers' local steps both lose their signal), very small evaluation budgets (the surrogate needs a handful of points before it's useful, and a swarm needs enough budget to give each climber room to walk), or cases where you need the completeness guarantee of exhaustive grid search.
pip install adaptive-greedy-search
Or, from a cloned copy of this repository:
pip install -e .
Requires Python 3.8+, numpy, scikit-learn, and joblib (installed
automatically).
from ags import AdaptiveGreedySearch
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_classification
X, y = make_classification(n_samples=500, n_features=20, random_state=0)
param_grid = {
"n_estimators": [50, 100, 150, 200],
"max_depth": [3, 5, 7, 9, None],
"min_samples_split": [2, 4, 6, 8],
}
search = AdaptiveGreedySearch(
RandomForestClassifier(random_state=0),
param_grid,
cv=5, # pruning gives little benefit below cv=5; use 5-10
scoring="accuracy",
max_evaluations=30,
# n_climbers defaults to 75% of your CPU cores -- pass an int to override
# n_jobs defaults to -1 (use all cores for the parallel batch dispatch)
)
search.fit(X, y)
print(search.best_params)
print(search.best_score)
print(f"folds saved by pruning: {search.folds_saved}/{search.total_folds_possible}")
print(f"climbers spawned: {search.climbers_spawned}, merged: {search.climbers_merged}, "
f"plateau escapes: {search.plateau_escapes}")
| Parameter | Default | What it does |
|---|---|---|
cv | 5 | Number of CV folds. Pruning is far more effective at 5 or 10 -- with 3 there's barely a checkpoint before the last fold. |
scoring | "accuracy" | Any scikit-learn scorer string ("accuracy", "neg_mean_squared_error", "roc_auc", ...). |
n_climbers | None -> 75% of CPU cores (min 1) | Swarm size. Each climber is an independent greedy search sharing the same surrogate. Pass an int to override. |
climber_patience | 3 | Consecutive non-improving steps before a climber is retired as "stagnated". |
n_jobs | -1 | Passed to joblib.Parallel for the per-round batched evaluation dispatch. |
max_evaluations | 25 | Hard cap on the number of grid points evaluated, across the whole swarm. |
surrogate_type | "tpe" | "tpe" (Tree-structured Parzen Estimator, cheap to refit) or "gp" (Gaussian Process, better calibrated uncertainty but costlier as evaluations grow). |
pruning_strategy | "percentile" | "percentile" (aggressive), "optimistic" (safe -- only prunes when a candidate is mathematically unable to beat the current best), or "none" (exhaustive CV, no pruning). |
pruning_percentile | 25 | Lower = stricter pruning (fewer candidates survive) when using "percentile". |
max_neighbor_radius | 4 | How many rings outward a boxed-in climber's plateau escape is allowed to search before it's retired. 0 disables the escape entirely. |
early_stopping_patience | None | Optional global stop if the swarm's best score hasn't improved for this many evaluations. Per-climber climber_patience is the main stagnation mechanism; this is an extra, off-by-default cap on top. |
"percentile"."optimistic"."none" to fall back to plain exhaustive cross-validation.Fold-level percentile pruning compares a candidate's partial CV mean
against the historical distribution of other candidates at the same
fold index. Candidates evaluated in the same parallel batch run
concurrently in separate processes, so each one only sees a snapshot of
that history taken when the batch was dispatched -- it can't see its
batch-mates' partial folds as they happen. This doesn't affect the
"optimistic" rule's safety guarantee (it only compares against the
already-completed incumbent), but it very slightly softens
"percentile"'s aggressiveness within a single batch.
Parallel speedup depends on your machine and workload: on a
single-core machine, or when each candidate is cheap to evaluate,
n_jobs > 1 can be slower than n_jobs=1 due to process-spawn and
IPC overhead. It pays off once each fold's training is expensive enough
to amortize that cost. Worth sweeping n_jobs on your own hardware
rather than assuming more cores automatically wins.
.fit(X, y)best_params, best_score, best_state -- the winning configuration.history -- a list of dicts, one per evaluated candidate, including
n_folds_used, n_folds_total, climber_id, and whether/why it was pruned.climbers -- the final list of Climber objects (active, stagnated,
and merged), each with id, current_state, current_score,
steps_taken, stagnation_count, status.n_evaluations, total_time, stopped_early.n_pruned, total_folds_run, total_folds_possible, folds_saved
-- how much cross-validation work was actually skipped.climbers_spawned, climbers_merged, plateau_escapes -- swarm-specific
counters for how the search actually behaved.MIT (c) Mohammad Jawad Hasan
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 3.0.0 | 29 Sept 2026 | 3 |
This describes our collected data; it is not a security assessment.
Shared repository data · GitHub
Observed since 20 Oct, 19:06 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:7173eef2e24a8827e021917f394a63b7fd8cc801e19229c48e11cac78d2db709