Pick hyperparameters by trying every combination and scoring each with k-fold cross-validation.
Implement:
param_grid(grid): expand a dict of lists into a list of dicts covering every combination. Keys are iterated in sorted order and values in the given order, with the last key varying fastest.kfold_indices(n, k): a list of (train_idx, val_idx) NumPy arrays, using contiguous folds where the first n % k folds get one extra itemgrid_search(fit_score, grid, X, y, k=5): fit_score(params, X_tr, y_tr, X_val, y_val) returns a score (higher is better). Return (best_params, results), where results is a list of (params, mean_score) in grid order. Ties go to the earliest combination.