Passed
Pull Request — master (#110)
by
unknown
01:40
created

OptCV.score()   A

Complexity

Conditions 1

Size

Total Lines 27
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 27
rs 10
c 0
b 0
f 0
cc 1
nop 4
1
# copyright: hyperactive developers, MIT License (see LICENSE file)
2
3
from collections.abc import Callable
4
from typing import Union
5
6
from sklearn.base import BaseEstimator, clone
7
from sklearn.utils.validation import indexable, _check_method_params
8
9
from hyperactive.experiment.integrations.sklearn_cv import SklearnCvExperiment
10
from hyperactive.integrations.sklearn.best_estimator import (
11
    BestEstimator as _BestEstimator_
12
)
13
from hyperactive.integrations.sklearn.checks import Checks
14
15
16
class OptCV(BaseEstimator, _BestEstimator_, Checks):
17
    """Tuning via any optimizer in the hyperactive API.
18
19
    Parameters
20
    ----------
21
    estimator : SklearnBaseEstimator
22
        The estimator to be tuned.
23
    optimizer : hyperactive BaseOptimizer
24
        The optimizer to be used for hyperparameter search.
25
    estimator : sklearn estimator
26
        The estimator to be used for the experiment.
27
    cv : int or cross-validation generator, default = KFold(n_splits=3, shuffle=True)
28
        The number of folds or cross-validation strategy to be used.
29
        If int, the cross-validation used is KFold(n_splits=cv, shuffle=True).
30
    scoring : callable or str, default = accuracy_score or mean_squared_error
31
        sklearn scoring function or metric to evaluate the model's performance.
32
        Default is determined by the type of estimator:
33
        ``accuracy_score`` for classifiers, and
34
        ``mean_squared_error`` for regressors, as per sklearn convention
35
        through the default ``score`` method of the estimator.
36
37
    Example
38
    -------
39
    Tuning sklearn SVC via grid search
40
41
    1. defining the tuned estimator:
42
    >>> from sklearn.svm import SVC
43
    >>> from hyperactive.integrations.sklearn import OptCV
44
    >>> from hyperactive.opt import GridSearch
45
    >>>
46
    >>> param_grid = {"kernel": ["linear", "rbf"], "C": [1, 10]}
47
    >>> tuned_svc = OptCV(SVC(), GridSearch(param_grid))
48
49
    2. fitting the tuned estimator:
50
    >>> from sklearn.datasets import load_iris
51
    >>> from sklearn.model_selection import train_test_split
52
    >>> X, y = load_iris(return_X_y=True)
53
    >>> X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
54
    >>>
55
    >>> tuned_svc.fit(X_train, y_train)
56
    OptCV(...)
57
    >>> y_pred = tuned_svc.predict(X_test)
58
59
    3. obtaining best parameters and best estimator
60
    >>> best_params = tuned_svc.best_params_
61
    >>> best_estimator = tuned_svc.best_estimator_
62
    """
63
64
    _required_parameters = ["estimator", "optimizer"]
65
66
    def __init__(
67
        self,
68
        estimator,
69
        optimizer,
70
        *,
71
        scoring: Union[Callable, str, None] = None,
72
        cv=None,
73
    ):
74
        super().__init__()
75
76
        self.estimator = estimator
77
        self.optimizer = optimizer
78
        self.scoring = scoring
79
        self.cv = cv
80
81
    def _refit(self, X, y=None, **fit_params):
82
        self.best_estimator_ = clone(self.estimator).set_params(
83
            **clone(self.best_params_, safe=False)
84
        )
85
86
        self.best_estimator_.fit(X, y, **fit_params)
87
        return self
88
89
    def _check_data(self, X, y):
90
        X, y = indexable(X, y)
91
        if hasattr(self, "_validate_data"):
92
            validate_data = self._validate_data
93
        else:
94
            from sklearn.utils.validation import validate_data
95
96
        return validate_data(X, y)
97
98
    @Checks.verify_fit
99
    def fit(self, X, y, **fit_params):
100
        """Fit the model.
101
102
        Parameters
103
        ----------
104
        X : {array-like, sparse matrix} of shape (n_samples, n_features)
105
            Training data.
106
107
        y : array-like of shape (n_samples,) or (n_samples, n_targets)
108
            Target values. Will be cast to X's dtype if necessary.
109
110
        Returns
111
        -------
112
        self : object
113
            Fitted Estimator.
114
        """
115
116
        X, y = self._check_data(X, y)
117
118
        fit_params = _check_method_params(X, params=fit_params)
119
120
        experiment = SklearnCvExperiment(
121
            estimator=self.estimator,
122
            scoring=self.scoring,
123
            cv=self.cv,
124
            X=X,
125
            y=y,
126
        )
127
        self.scorer_ = experiment.scorer_
128
129
        optimizer = self.optimizer.clone()
130
        optimizer.set_params(experiment=experiment)
131
        best_params = optimizer.run()
132
133
        self.best_params_ = best_params
134
        self.best_estimator_ = clone(self.estimator).set_params(**best_params)
135
136
        if self.refit:
137
            self._refit(X, y, **fit_params)
138
139
        return self
140
141
    def score(self, X, y=None, **params):
142
        """Return the score on the given data, if the estimator has been refit.
143
144
        This uses the score defined by ``scoring`` where provided, and the
145
        ``best_estimator_.score`` method otherwise.
146
147
        Parameters
148
        ----------
149
        X : array-like of shape (n_samples, n_features)
150
            Input data, where `n_samples` is the number of samples and
151
            `n_features` is the number of features.
152
153
        y : array-like of shape (n_samples, n_output) \
154
            or (n_samples,), default=None
155
            Target relative to X for classification or regression;
156
            None for unsupervised learning.
157
158
        **params : dict
159
            Parameters to be passed to the underlying scorer(s).
160
161
        Returns
162
        -------
163
        score : float
164
            The score defined by ``scoring`` if provided, and the
165
            ``best_estimator_.score`` method otherwise.
166
        """
167
        return self.scorer_(self.best_estimator_, X, y, **params)
168
169
    @property
170
    def fit_successful(self):
171
        self._fit_successful
172