Skip to content

[WIP] API specify test parameters via classmethod #11324

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
23 changes: 23 additions & 0 deletions sklearn/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,29 @@ def __setstate__(self, state):
except AttributeError:
self.__dict__.update(state)

@classmethod
def _generate_test_params(cls):
"""Generates estimator initialization parameters for check_estimator

To be overridden where parameters are required or specific settings are
helpful for testing.

Yields
------
param_dict : dict
Should yield at least one dict that can be passed to cls's
constructor as kwargs
"""
try:
yield {}
except TypeError as exc:
raise TypeError('TypeError %s raised when constructing %r.'
'Scikit-learn compatible estimators should '
'usually be constructible without any required '
'parameters. If this is not possible, '
'classmethod _generate_test_params should be '
'overridden.' % (exc, cls))


###############################################################################
class ClassifierMixin(object):
Expand Down
4 changes: 4 additions & 0 deletions sklearn/cluster/affinity_propagation_.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,10 @@ def __init__(self, damping=.5, max_iter=200, convergence_iter=15,
self.preference = preference
self.affinity = affinity

@classmethod
def _generate_test_params(cls):
yield dict(max_iter=5)

@property
def _pairwise(self):
return self.affinity == "precomputed"
Expand Down
12 changes: 12 additions & 0 deletions sklearn/cluster/bicluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ def __init__(self, n_clusters=3, svd_method="randomized",
self.n_jobs = n_jobs
self.random_state = random_state

@classmethod
def _generate_test_params(cls):
yield dict(n_init=2)

def _check_parameters(self):
legal_svd_methods = ('randomized', 'arpack')
if self.svd_method not in legal_svd_methods:
Expand Down Expand Up @@ -278,6 +282,10 @@ def __init__(self, n_clusters=3, svd_method='randomized',
n_jobs,
random_state)

@classmethod
def _generate_test_params(cls):
yield dict(n_init=2)

def _fit(self, X):
normalized_data, row_diag, col_diag = _scale_normalize(X)
n_sv = 1 + int(np.ceil(np.log2(self.n_clusters)))
Expand Down Expand Up @@ -413,6 +421,10 @@ def __init__(self, n_clusters=3, method='bistochastic',
self.n_components = n_components
self.n_best = n_best

@classmethod
def _generate_test_params(cls):
yield dict(n_init=2)

def _check_parameters(self):
super(SpectralBiclustering, self)._check_parameters()
legal_methods = ('bistochastic', 'scale', 'log')
Expand Down
8 changes: 8 additions & 0 deletions sklearn/cluster/k_means_.py
Original file line number Diff line number Diff line change
Expand Up @@ -918,6 +918,10 @@ def __init__(self, n_clusters=8, init='k-means++', n_init=10,
self.n_jobs = n_jobs
self.algorithm = algorithm

@classmethod
def _generate_test_params(cls):
yield dict(max_iter=5, n_init=2)

def _check_test_data(self, X):
X = check_array(X, accept_sparse='csr', dtype=FLOAT_DTYPES)
n_samples, n_features = X.shape
Expand Down Expand Up @@ -1424,6 +1428,10 @@ def __init__(self, n_clusters=8, init='k-means++', max_iter=100,
self.init_size = init_size
self.reassignment_ratio = reassignment_ratio

@classmethod
def _generate_test_params(cls):
yield dict(max_iter=5, n_init=2)

def fit(self, X, y=None, sample_weight=None):
"""Compute the centroids on X by chunking it into mini-batches.

Expand Down
4 changes: 4 additions & 0 deletions sklearn/cluster/spectral.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,10 @@ def __init__(self, n_clusters=8, eigen_solver=None, random_state=None,
self.kernel_params = kernel_params
self.n_jobs = n_jobs

@classmethod
def _generate_test_params(cls):
yield dict(n_init=2)

def fit(self, X, y=None):
"""Creates an affinity matrix for X using the selected affinity,
then applies spectral clustering to this affinity matrix.
Expand Down
16 changes: 16 additions & 0 deletions sklearn/covariance/graph_lasso_.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,10 @@ def __init__(self, alpha=.01, mode='cd', tol=1e-4, enet_tol=1e-4,
self.max_iter = max_iter
self.verbose = verbose

@classmethod
def _generate_test_params(cls):
yield dict(max_iter=5)

def fit(self, X, y=None):
"""Fits the GraphicalLasso model to X.

Expand Down Expand Up @@ -574,6 +578,10 @@ def __init__(self, alphas=4, n_refinements=4, cv=None, tol=1e-4,
self.cv = cv
self.n_jobs = n_jobs

@classmethod
def _generate_test_params(cls):
yield dict(max_iter=5)

@property
@deprecated("Attribute grid_scores was deprecated in version 0.19 and "
"will be removed in 0.21. Use ``grid_scores_`` instead")
Expand Down Expand Up @@ -861,6 +869,10 @@ class GraphLasso(GraphicalLasso):
graph_lasso, GraphLassoCV
"""

@classmethod
def _generate_test_params(cls):
yield dict(max_iter=5)


@deprecated("The 'GraphLassoCV' was renamed to 'GraphicalLassoCV' "
"in version 0.20 and will be removed in 0.22.")
Expand Down Expand Up @@ -965,3 +977,7 @@ class GraphLassoCV(GraphicalLassoCV):
values of alpha then come out as missing values, but the optimum may
be close to these missing values.
"""

@classmethod
def _generate_test_params(cls):
yield dict(max_iter=5)
4 changes: 4 additions & 0 deletions sklearn/cross_decomposition/cca_.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,7 @@ def __init__(self, n_components=2, scale=True,
deflation_mode="canonical", mode="B",
norm_y_weights=True, algorithm="nipals",
max_iter=max_iter, tol=tol, copy=copy)

@classmethod
def _generate_test_params(cls):
yield dict(max_iter=5)
8 changes: 8 additions & 0 deletions sklearn/cross_decomposition/pls_.py
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,10 @@ def __init__(self, n_components=2, scale=True,
norm_y_weights=False, max_iter=max_iter, tol=tol,
copy=copy)

@classmethod
def _generate_test_params(cls):
yield dict(max_iter=5)


class PLSCanonical(_PLS):
""" PLSCanonical implements the 2 blocks canonical PLS of the original Wold
Expand Down Expand Up @@ -741,6 +745,10 @@ def __init__(self, n_components=2, scale=True, algorithm="nipals",
norm_y_weights=True, algorithm=algorithm,
max_iter=max_iter, tol=tol, copy=copy)

@classmethod
def _generate_test_params(cls):
yield dict(max_iter=5)


class PLSSVD(BaseEstimator, TransformerMixin):
"""Partial Least Square SVD
Expand Down
8 changes: 8 additions & 0 deletions sklearn/decomposition/dict_learning.py
Original file line number Diff line number Diff line change
Expand Up @@ -1071,6 +1071,10 @@ def __init__(self, n_components=None, alpha=1, max_iter=1000, tol=1e-8,
self.verbose = verbose
self.random_state = random_state

@classmethod
def _generate_test_params(cls):
yield dict(max_iter=5)

def fit(self, X, y=None):
"""Fit the model from data in X.

Expand Down Expand Up @@ -1243,6 +1247,10 @@ def __init__(self, n_components=None, alpha=1, n_iter=1000,
self.split_sign = split_sign
self.random_state = random_state

@classmethod
def _generate_test_params(cls):
yield dict(n_iter=5)

def fit(self, X, y=None):
"""Fit the model from data in X.

Expand Down
4 changes: 4 additions & 0 deletions sklearn/decomposition/factor_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,10 @@ def __init__(self, n_components=None, tol=1e-2, copy=True, max_iter=1000,
self.iterated_power = iterated_power
self.random_state = random_state

@classmethod
def _generate_test_params(cls):
yield dict(max_iter=5)

def fit(self, X, y=None):
"""Fit the FactorAnalysis model to X using EM

Expand Down
4 changes: 4 additions & 0 deletions sklearn/decomposition/fastica_.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,10 @@ def __init__(self, n_components=None, algorithm='parallel', whiten=True,
self.w_init = w_init
self.random_state = random_state

@classmethod
def _generate_test_params(cls):
yield dict(max_iter=5)

def _fit(self, X, compute_sources=False):
"""Fit the model

Expand Down
4 changes: 4 additions & 0 deletions sklearn/decomposition/nmf.py
Original file line number Diff line number Diff line change
Expand Up @@ -1203,6 +1203,10 @@ def __init__(self, n_components=None, init=None, solver='cd',
self.verbose = verbose
self.shuffle = shuffle

@classmethod
def _generate_test_params(cls):
yield dict(max_iter=100)

def fit_transform(self, X, y=None, W=None, H=None):
"""Learn a NMF model for the data X and returns the transformed data.

Expand Down
4 changes: 4 additions & 0 deletions sklearn/decomposition/online_lda.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,10 @@ def __init__(self, n_components=10, doc_topic_prior=None,
self.random_state = random_state
self.n_topics = n_topics

@classmethod
def _generate_test_params(cls):
yield dict(max_iter=5)

def _check_params(self):
"""Check model parameters."""
if self.n_topics is not None:
Expand Down
8 changes: 8 additions & 0 deletions sklearn/decomposition/sparse_pca.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ def __init__(self, n_components=None, alpha=1, ridge_alpha=0.01,
self.verbose = verbose
self.random_state = random_state

@classmethod
def _generate_test_params(cls):
yield dict(max_iter=5)

def fit(self, X, y=None):
"""Fit the model from data in X.

Expand Down Expand Up @@ -265,6 +269,10 @@ def __init__(self, n_components=None, alpha=1, ridge_alpha=0.01,
self.batch_size = batch_size
self.shuffle = shuffle

@classmethod
def _generate_test_params(cls):
yield dict(n_iter=5)

def fit(self, X, y=None):
"""Fit the model from data in X.

Expand Down
8 changes: 8 additions & 0 deletions sklearn/ensemble/bagging.py
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,10 @@ def __init__(self,
random_state=random_state,
verbose=verbose)

@classmethod
def _generate_test_params(cls):
yield dict(n_estimators=5)

def _validate_estimator(self):
"""Check the estimator and set the base_estimator_ attribute."""
super(BaggingClassifier, self)._validate_estimator(
Expand Down Expand Up @@ -941,6 +945,10 @@ def __init__(self,
random_state=random_state,
verbose=verbose)

@classmethod
def _generate_test_params(cls):
yield dict(n_estimators=5)

def predict(self, X):
"""Predict regression target for X.

Expand Down
20 changes: 20 additions & 0 deletions sklearn/ensemble/forest.py
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,10 @@ def __init__(self,
self.min_impurity_decrease = min_impurity_decrease
self.min_impurity_split = min_impurity_split

@classmethod
def _generate_test_params(cls):
yield dict(n_estimators=5)


class RandomForestRegressor(ForestRegressor):
"""A random forest regressor.
Expand Down Expand Up @@ -1252,6 +1256,10 @@ def __init__(self,
self.min_impurity_decrease = min_impurity_decrease
self.min_impurity_split = min_impurity_split

@classmethod
def _generate_test_params(cls):
yield dict(n_estimators=5)


class ExtraTreesClassifier(ForestClassifier):
"""An extra-trees classifier.
Expand Down Expand Up @@ -1497,6 +1505,10 @@ def __init__(self,
self.min_impurity_decrease = min_impurity_decrease
self.min_impurity_split = min_impurity_split

@classmethod
def _generate_test_params(cls):
yield dict(n_estimators=5)


class ExtraTreesRegressor(ForestRegressor):
"""An extra-trees regressor.
Expand Down Expand Up @@ -1707,6 +1719,10 @@ def __init__(self,
self.min_impurity_decrease = min_impurity_decrease
self.min_impurity_split = min_impurity_split

@classmethod
def _generate_test_params(cls):
yield dict(n_estimators=5)


class RandomTreesEmbedding(BaseForest):
"""An ensemble of totally random trees.
Expand Down Expand Up @@ -1872,6 +1888,10 @@ def __init__(self,
self.min_impurity_split = min_impurity_split
self.sparse_output = sparse_output

@classmethod
def _generate_test_params(cls):
yield dict(n_estimators=5)

def _set_oob_score(self, X, y):
raise NotImplementedError("OOB score not supported by tree embedding")

Expand Down
8 changes: 8 additions & 0 deletions sklearn/ensemble/gradient_boosting.py
Original file line number Diff line number Diff line change
Expand Up @@ -1552,6 +1552,10 @@ def __init__(self, loss='deviance', learning_rate=0.1, n_estimators=100,
validation_fraction=validation_fraction,
n_iter_no_change=n_iter_no_change, tol=tol)

@classmethod
def _generate_test_params(cls):
yield dict(n_estimators=5)

def _validate_y(self, y, sample_weight):
check_classification_targets(y)
self.classes_, y = np.unique(y, return_inverse=True)
Expand Down Expand Up @@ -2000,6 +2004,10 @@ def __init__(self, loss='ls', learning_rate=0.1, n_estimators=100,
presort=presort, validation_fraction=validation_fraction,
n_iter_no_change=n_iter_no_change, tol=tol)

@classmethod
def _generate_test_params(cls):
yield dict(n_estimators=5)

def predict(self, X):
"""Predict regression target for X.

Expand Down
4 changes: 4 additions & 0 deletions sklearn/ensemble/iforest.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ def __init__(self,
DeprecationWarning)
self.contamination = contamination

@classmethod
def _generate_test_params(cls):
yield dict(n_estimators=5)

def _set_oob_score(self, X, y):
raise NotImplementedError("OOB score not supported by iforest")

Expand Down
8 changes: 8 additions & 0 deletions sklearn/ensemble/weight_boosting.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,10 @@ def __init__(self,

self.algorithm = algorithm

@classmethod
def _generate_test_params(cls):
yield dict(n_estimators=5)

def fit(self, X, y, sample_weight=None):
"""Build a boosted classifier from the training set (X, y).

Expand Down Expand Up @@ -931,6 +935,10 @@ def __init__(self,
self.loss = loss
self.random_state = random_state

@classmethod
def _generate_test_params(cls):
yield dict(n_estimators=5)

def fit(self, X, y, sample_weight=None):
"""Build a boosted regressor from the training set (X, y).

Expand Down
Loading