Passed
Pull Request — master (#110)
by
unknown
02:46 queued 01:17
created

hyperactive.opt.gridsearch.GridSearch._run()   A

Complexity

Conditions 3

Size

Total Lines 22
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 16
nop 4
dl 0
loc 22
rs 9.6
c 0
b 0
f 0
1
"""Grid search optimizer."""
2
3
from collections.abc import Sequence
4
5
import numpy as np
6
7
from sklearn.model_selection import ParameterGrid, ParameterSampler, check_cv
8
9
from hyperactive.base import BaseOptimizer
10
11
12
class GridSearch(BaseOptimizer):
13
    """Grid search optimizer.
14
15
    Parameters
16
    ----------
17
    experiment : BaseExperiment, optional
18
        The experiment to optimize parameters for.
19
        Optional, can be passed later in ``add_search``.
20
    error_score : float, default=np.nan
21
        The score to assign if an error occurs during the evaluation of a parameter set.
22
    param_grid : dict[str, list]
23
        The search space to explore. A dictionary with parameter
24
        names as keys and a numpy array as values.
25
    """
26
27
    def __init__(
28
        self,
29
        experiment=None,
30
        error_score=np.nan,
31
        param_grid=None,
32
    ):
33
        self.experiment = experiment
34
        self.param_grid = param_grid
35
        self.error_score = error_score
36
37
        super().__init__()
38
39
    def _check_param_grid(self, param_grid):
40
        """_check_param_grid from sklearn 1.0.2, before it was removed."""
41
        if hasattr(param_grid, "items"):
42
            param_grid = [param_grid]
43
44
        for p in param_grid:
45
            for name, v in p.items():
46
                if isinstance(v, np.ndarray) and v.ndim > 1:
47
                    raise ValueError("Parameter array should be one-dimensional.")
48
49
                if isinstance(v, str) or not isinstance(v, (np.ndarray, Sequence)):
50
                    raise ValueError(
51
                        f"Parameter grid for parameter ({name}) needs to"
52
                        f" be a list or numpy array, but got ({type(v)})."
53
                        " Single values need to be wrapped in a list"
54
                        " with one element."
55
                    )
56
57
                if len(v) == 0:
58
                    raise ValueError(
59
                        f"Parameter values for parameter ({name}) need "
60
                        "to be a non-empty sequence."
61
                    )
62
63
    def _run(self, experiment, param_grid, error_score):
64
        """Run the optimization search process."""
65
        self._check_param_grid(param_grid)
66
        candidate_params = list(ParameterGrid(param_grid))
67
68
        scores = []
69
        for candidate_param in candidate_params:
70
            try:
71
                score = experiment(**candidate_param)
72
            except Exception:  # noqa: B904
73
                # Catch all exceptions and assign error_score
74
                score = error_score
75
            scores.append(score)
76
77
        best_index = np.argmin(scores)
78
        best_params = candidate_params[best_index]
79
80
        self.best_index_ = best_index
81
        self.best_params_ = best_params
82
        self.best_score_ = scores[best_index]
83
84
        return best_params
85