Passed
Pull Request — master (#110)
by
unknown
11:00 queued 09:30
created

HillClimbing.__init__()   A

Complexity

Conditions 2

Size

Total Lines 30
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 26
nop 11
dl 0
loc 30
rs 9.256
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
"""Hill climbing optimizer from gfo."""
2
3
from gradient_free_optimizers import HillClimbingOptimizer
4
from hyperactive.base import BaseOptimizer
5
6
7
class HillClimbing(BaseOptimizer):
8
    """Hill climbing optimizer.
9
10
    Parameters
11
    ----------
12
    experiment : BaseExperiment, optional
13
        The experiment to optimize parameters for.
14
        Optional, can be passed later in ``add_search``.
15
    random_state : None, int, default=None
16
        If None, create a new random state. If int, create a new random state
17
        seeded with the value.
18
    rand_rest_p : float, default=0.1
19
        The probability of a random iteration during the the search process.
20
    epsilon : float, default=0.01
21
        The step-size for the climbing.
22
    distribution : str, default="normal"
23
        The type of distribution to sample from.
24
    n_neighbours : int, default=10
25
        The number of neighbours to sample and evaluate before moving to the best
26
        of those neighbours.
27
    search_space : dict[str, list]
28
        The search space to explore. A dictionary with parameter
29
        names as keys and a numpy array as values.
30
        Optional, can be passed later in ``add_search``.
31
    initialize : dict[str, int], default={"grid": 4, "random": 2, "vertices": 4}
32
        The method to generate initial positions. A dictionary with
33
        the following key literals and the corresponding value type:
34
        {"grid": int, "vertices": int, "random": int, "warm_start": list[dict]}
35
    constraints : list[callable], default=[]
36
        A list of constraints, where each constraint is a callable.
37
        The callable returns `True` or `False` dependend on the input parameters.
38
    n_iter : int, default=100
39
        The number of iterations to run the optimizer.
40
41
    Examples
42
    --------
43
    Hill climbing applied to scikit-learn parameter tuning:
44
45
    1. defining the experiment to optimize:
46
    >>> from hyperactive.experiment.integrations import SklearnCvExperiment
47
    >>> from sklearn.datasets import load_iris
48
    >>> from sklearn.svm import SVC
49
    >>>
50
    >>> X, y = load_iris(return_X_y=True)
51
    >>>
52
    >>> sklearn_exp = SklearnCvExperiment(
53
    ...     estimator=SVC(),
54
    ...     X=X,
55
    ...     y=y,
56
    ... )
57
58
    2. setting up the hill climbing optimizer:
59
    >>> from hyperactive.opt import HillClimbing
60
    >>> import numpy as np
61
    >>> 
62
    >>> hillclimbing_config = {
63
    ...     "search_space": {
64
    ...         "C": np.array([0.01, 0.1, 1, 10]),
65
    ...         "gamma": np.array([0.0001, 0.01, 0.1, 1, 10]),
66
    ...     },
67
    ...     "n_iter": 100,
68
    ... }
69
    >>> hillclimbing = HillClimbing(sklearn_exp, **hillclimbing_config)
70
71
    3. running the hill climbing search:
72
    >>> best_params = hillclimbing.run()
73
74
    Best parameters can also be accessed via the attributes:
75
    >>> best_params = hillclimbing.best_params_
76
    """
77
78
    def __init__(
79
        self,
80
        experiment=None,
81
        random_state=None,
82
        rand_rest_p=0.1,
83
        epsilon=0.01,
84
        distribution="normal",
85
        n_neighbours=10,
86
        search_space=None,
87
        initialize=None,
88
        constraints=None,
89
        n_iter=100,
90
    ):
91
        self.random_state = random_state
92
        self.rand_rest_p = rand_rest_p
93
        self.epsilon = epsilon
94
        self.distribution = distribution
95
        self.n_neighbours = n_neighbours
96
        self.search_space = search_space
97
        self.initialize = initialize
98
        self.constraints = constraints
99
        self.n_iter = n_iter
100
        self.experiment = experiment
101
102
        super().__init__()
103
104
        if initialize is None:
105
            self._initialize = {"grid": 4, "random": 2, "vertices": 4}
106
        else:
107
            self._initialize = initialize
108
109
    def get_search_config(self):
110
        """Get the search configuration.
111
112
        Returns
113
        -------
114
        dict with str keys
115
            The search configuration dictionary.
116
        """
117
        search_config = super().get_search_config()
118
        search_config["initialize"] = self._initialize
119
        return search_config
120
121
    def _run(self, experiment, **search_config):
122
        """Run the optimization search process."""
123
        n_iter = search_config.pop("n_iter", 100)
124
        max_time = search_config.pop("max_time", None)
125
126
        hcopt = HillClimbingOptimizer(**search_config)
127
128
        hcopt.search(
129
            objective_function=experiment.score,
130
            n_iter=n_iter,
131
            max_time=max_time,
132
        )
133
        self.best_params_ = hcopt.best_params()
134
135
        return self.best_params_
136