Source code for ogboost.utils

import numpy as np
from sklearn.base import clone

[docs] def generate_heterogeneous_learners( templates, # list of pre-initialized base learner instances (templates) overrides, # list of dicts, one per template mapping parameter names to sampling callables total_samples, # total number of learner instances to generate template_probs=None, # if "round_robin", then round-robin selection is used; otherwise, an array-like probability distribution random_state=None # seed or RandomState for reproducibility ): """ Generate a flat list of heterogeneous base learner instances by applying independent hyperparameter sampling to each template. Each generated learner is created by cloning a template (using scikit-learn's `clone`) and then updating its hyperparameters based on independently sampled values provided via the `overrides` dictionaries. Parameters ---------- templates : list A list of pre-initialized scikit-learn estimator instances that serve as templates. overrides : list of dict A list of dictionaries (one per template). Each dictionary maps hyperparameter names (as strings) to callables that accept a random state (`rng`) and return a sampled value. All override values must be callable. total_samples : int The total number of new base learner instances to generate. template_probs : array-like or str or None, optional If array-like, a probability distribution over the templates. Must sum to 1 and have the same length as `templates`. If the string "round_robin" (case-insensitive) is provided, then round-robin selection is used. If None, a uniform random distribution is used. random_state : int, np.random.RandomState, or None, optional A seed or RandomState instance for reproducibility in sampling hyperparameters. Returns ------- list A flat list of newly generated base learner instances with updated hyperparameters. Raises ------ ValueError If an override value is not callable, or if the lengths of `templates` and `overrides` do not match, or if `template_probs` is provided with the wrong length. """ # Set up a RandomState instance for reproducibility. if random_state is None: rng = np.random.RandomState() elif isinstance(random_state, (int, np.integer)): rng = np.random.RandomState(random_state) else: rng = random_state n_templates = len(templates) if len(overrides) != n_templates: raise ValueError("Length of overrides must match the number of templates.") use_round_robin = False if template_probs is None: # Use uniform random probabilities if none provided. template_probs = np.ones(n_templates) / n_templates elif isinstance(template_probs, str): if template_probs.lower() == "round_robin": use_round_robin = True else: raise ValueError("If template_probs is a string, it must be 'round_robin'.") else: template_probs = np.asarray(template_probs) if template_probs.shape[0] != n_templates: raise ValueError("Length of template_probs must match the number of templates.") generated_learners = [] for i in range(total_samples): # Choose a template index. if use_round_robin: chosen_index = i % n_templates else: chosen_index = rng.choice(n_templates, p=template_probs) base_template = templates[chosen_index] override_dict = overrides[chosen_index] # Create a new learner instance by cloning the template. new_learner = clone(base_template) # Sample new hyperparameter values using the provided callables. sampled_params = {} for param, sampler in override_dict.items(): if not callable(sampler): raise ValueError(f"Override for parameter '{param}' must be callable.") sampled_params[param] = sampler(rng) # Update the learner with the new hyperparameter values. new_learner.set_params(**sampled_params) generated_learners.append(new_learner) return generated_learners