scikit-learn/sklearn/tests/test_common.py

1057 lines
41 KiB
Python

"""
General tests for all estimators in sklearn.
"""
# Authors: Andreas Mueller <amueller@ais.uni-bonn.de>
# Gael Varoquaux gael.varoquaux@normalesup.org
# License: BSD 3 clause
from __future__ import print_function
import os
import warnings
import sys
import traceback
import inspect
import pickle
import pkgutil
import numpy as np
from scipy import sparse
from sklearn.externals.six import PY3
from sklearn.utils.testing import assert_raises
from sklearn.utils.testing import assert_equal
from sklearn.utils.testing import assert_true
from sklearn.utils.testing import assert_false
from sklearn.utils.testing import assert_array_equal
from sklearn.utils.testing import assert_array_almost_equal
from sklearn.utils.testing import all_estimators
from sklearn.utils.testing import meta_estimators
from sklearn.utils.testing import set_random_state
from sklearn.utils.testing import assert_greater
import sklearn
from sklearn.base import (clone, ClassifierMixin, RegressorMixin,
TransformerMixin, ClusterMixin)
from sklearn.utils import shuffle
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import (load_iris, load_boston, make_blobs,
make_classification)
from sklearn.metrics import accuracy_score, adjusted_rand_score, f1_score
from sklearn.lda import LDA
from sklearn.svm.base import BaseLibSVM
from sklearn.cross_validation import train_test_split
from sklearn.utils.validation import DataConversionWarning
dont_test = ['SparseCoder', 'EllipticEnvelope', 'EllipticEnvelop',
'DictVectorizer', 'LabelBinarizer', 'LabelEncoder',
'TfidfTransformer', 'IsotonicRegression', 'OneHotEncoder',
'RandomTreesEmbedding', 'FeatureHasher', 'DummyClassifier',
'DummyRegressor', 'TruncatedSVD']
def test_all_estimators():
# Test that estimators are default-constructible, clonable
# and have working repr.
estimators = all_estimators(include_meta_estimators=True)
classifier = LDA()
# Meta sanity-check to make sure that the estimator introspection runs
# properly
assert_greater(len(estimators), 0)
for name, Estimator in estimators:
# some can just not be sensibly default constructed
if name in dont_test:
continue
# test default-constructibility
# get rid of deprecation warnings
with warnings.catch_warnings(record=True):
if name in meta_estimators:
estimator = Estimator(classifier)
else:
estimator = Estimator()
# test cloning
clone(estimator)
# test __repr__
repr(estimator)
# test that set_params returns self
assert_true(isinstance(estimator.set_params(), Estimator))
# test if init does nothing but set parameters
# this is important for grid_search etc.
# We get the default parameters from init and then
# compare these against the actual values of the attributes.
# this comes from getattr. Gets rid of deprecation decorator.
init = getattr(estimator.__init__, 'deprecated_original',
estimator.__init__)
try:
args, varargs, kws, defaults = inspect.getargspec(init)
except TypeError:
# init is not a python function.
# true for mixins
continue
params = estimator.get_params()
if name in meta_estimators:
# they need a non-default argument
args = args[2:]
else:
args = args[1:]
if args:
# non-empty list
assert_equal(len(args), len(defaults))
else:
continue
for arg, default in zip(args, defaults):
if arg not in params.keys():
# deprecated parameter, not in get_params
assert_true(default is None)
continue
if isinstance(params[arg], np.ndarray):
assert_array_equal(params[arg], default)
else:
assert_equal(params[arg], default)
def test_all_estimator_no_base_class():
for name, Estimator in all_estimators():
msg = ("Base estimators such as {0} should not be included"
" in all_estimators").format(name)
assert_false(name.lower().startswith('base'), msg=msg)
def test_estimators_sparse_data():
# All estimators should either deal with sparse data, or raise an
# intelligible error message
rng = np.random.RandomState(0)
X = rng.rand(40, 10)
X[X < .8] = 0
X = sparse.csr_matrix(X)
y = (4 * rng.rand(40)).astype(np.int)
estimators = all_estimators()
estimators = [(name, Estimator) for name, Estimator in estimators
if issubclass(Estimator, (ClassifierMixin, RegressorMixin))]
for name, Classifier in estimators:
if name in dont_test:
continue
# catch deprecation warnings
with warnings.catch_warnings(record=True):
classifier = Classifier()
# fit
try:
classifier.fit(X, y)
except TypeError as e:
if not 'sparse' in repr(e):
print("Estimator %s doesn't seem to fail gracefully on "
"sparse data" % name)
traceback.print_exc(file=sys.stdout)
raise e
except Exception as exc:
print("Estimator %s doesn't seem to fail gracefully on "
"sparse data" % name)
traceback.print_exc(file=sys.stdout)
raise exc
def test_transformers():
# test if transformers do something sensible on training set
# also test all shapes / shape errors
transformers = all_estimators(type_filter='transformer')
X, y = make_blobs(n_samples=30, centers=[[0, 0, 0], [1, 1, 1]],
random_state=0, n_features=2, cluster_std=0.1)
n_samples, n_features = X.shape
X = StandardScaler().fit_transform(X)
X -= X.min()
succeeded = True
for name, Transformer in transformers:
if name in dont_test:
continue
# these don't actually fit the data:
if name in ['AdditiveChi2Sampler', 'Binarizer', 'Normalizer']:
continue
# catch deprecation warnings
with warnings.catch_warnings(record=True):
transformer = Transformer()
set_random_state(transformer)
if hasattr(transformer, 'compute_importances'):
transformer.compute_importances = True
if name == 'SelectKBest':
# SelectKBest has a default of k=10
# which is more feature than we have.
transformer.k = 1
elif name in ['GaussianRandomProjection',
'SparseRandomProjection']:
# Due to the jl lemma and very few samples, the number
# of components of the random matrix projection will be greater
# than the number of features.
# So we impose a smaller number (avoid "auto" mode)
transformer.n_components = 1
elif name == "MiniBatchDictionaryLearning":
transformer.set_params(n_iter=5) # default = 1000
elif name == "KernelPCA":
transformer.remove_zero_eig = False
# fit
if name in ('PLSCanonical', 'PLSRegression', 'CCA', 'PLSSVD'):
y_ = np.c_[y, y]
y_[::2, 1] *= 2
else:
y_ = y
try:
transformer.fit(X, y_)
X_pred = transformer.fit_transform(X, y=y_)
if isinstance(X_pred, tuple):
for x_pred in X_pred:
assert_equal(x_pred.shape[0], n_samples)
else:
assert_equal(X_pred.shape[0], n_samples)
except Exception as e:
print(transformer)
print(e)
print()
succeeded = False
continue
if hasattr(transformer, 'transform'):
if name in ('PLSCanonical', 'PLSRegression', 'CCA',
'PLSSVD'):
X_pred2 = transformer.transform(X, y_)
X_pred3 = transformer.fit_transform(X, y=y_)
else:
X_pred2 = transformer.transform(X)
X_pred3 = transformer.fit_transform(X, y=y_)
if isinstance(X_pred, tuple) and isinstance(X_pred2, tuple):
for x_pred, x_pred2, x_pred3 in zip(X_pred, X_pred2, X_pred3):
assert_array_almost_equal(
x_pred, x_pred2, 2,
"fit_transform not correct in %s" % Transformer)
assert_array_almost_equal(
x_pred3, x_pred2, 2,
"fit_transform not correct in %s" % Transformer)
else:
assert_array_almost_equal(
X_pred, X_pred2, 2,
"fit_transform not correct in %s" % Transformer)
assert_array_almost_equal(
X_pred3, X_pred2, 2,
"fit_transform not correct in %s" % Transformer)
# raises error on malformed input for transform
assert_raises(ValueError, transformer.transform, X.T)
assert_true(succeeded)
def test_transformers_sparse_data():
# All estimators should either deal with sparse data, or raise an
# intelligible error message
rng = np.random.RandomState(0)
X = rng.rand(40, 10)
X[X < .8] = 0
X = sparse.csr_matrix(X)
y = (4 * rng.rand(40)).astype(np.int)
estimators = all_estimators(type_filter='transformer')
for name, Transformer in estimators:
if name in dont_test:
continue
# catch deprecation warnings
with warnings.catch_warnings(record=True):
if name in ['Scaler', 'StandardScaler']:
transformer = Transformer(with_mean=False)
elif name in ['GaussianRandomProjection',
'SparseRandomProjection']:
# Due to the jl lemma and very few samples, the number
# of components of the random matrix projection will be greater
# than the number of features.
# So we impose a smaller number (avoid "auto" mode)
transformer = Transformer(n_components=np.int(X.shape[1] / 4))
else:
transformer = Transformer()
# fit
try:
transformer.fit(X, y)
except TypeError as e:
if not 'sparse' in repr(e):
print("Estimator %s doesn't seem to fail gracefully on "
"sparse data" % name)
traceback.print_exc(file=sys.stdout)
raise e
except Exception as exc:
print("Estimator %s doesn't seem to fail gracefully on "
"sparse data" % name)
traceback.print_exc(file=sys.stdout)
raise exc
def test_estimators_nan_inf():
# Test that all estimators check their input for NaN's and infs
rnd = np.random.RandomState(0)
X_train_finite = rnd.uniform(size=(10, 3))
X_train_nan = rnd.uniform(size=(10, 3))
X_train_nan[0, 0] = np.nan
X_train_inf = rnd.uniform(size=(10, 3))
X_train_inf[0, 0] = np.inf
y = np.ones(10)
y[:5] = 0
estimators = all_estimators()
estimators = [(name, E) for name, E in estimators
if (issubclass(E, ClassifierMixin) or
issubclass(E, RegressorMixin) or
issubclass(E, TransformerMixin) or
issubclass(E, ClusterMixin))]
error_string_fit = "Estimator doesn't check for NaN and inf in fit."
error_string_predict = ("Estimator doesn't check for NaN and inf in"
" predict.")
error_string_transform = ("Estimator doesn't check for NaN and inf in"
" transform.")
for X_train in [X_train_nan, X_train_inf]:
for name, Estimator in estimators:
if name in dont_test:
continue
if name in ('PLSCanonical', 'PLSRegression', 'CCA',
'PLSSVD', 'Imputer'): # Imputer accepts nan
continue
# catch deprecation warnings
with warnings.catch_warnings(record=True):
estimator = Estimator()
if name in ['GaussianRandomProjection',
'SparseRandomProjection']:
# Due to the jl lemma and very few samples, the number
# of components of the random matrix projection will be
# greater
# than the number of features.
# So we impose a smaller number (avoid "auto" mode)
estimator = Estimator(n_components=1)
set_random_state(estimator, 1)
# try to fit
try:
if issubclass(Estimator, ClusterMixin):
estimator.fit(X_train)
else:
estimator.fit(X_train, y)
except ValueError as e:
if not 'inf' in repr(e) and not 'NaN' in repr(e):
print(error_string_fit, Estimator, e)
traceback.print_exc(file=sys.stdout)
raise e
except Exception as exc:
print(error_string_fit, Estimator, exc)
traceback.print_exc(file=sys.stdout)
raise exc
else:
raise AssertionError(error_string_fit, Estimator)
# actually fit
if issubclass(Estimator, ClusterMixin):
# All estimators except clustering algorithm
# support fitting with (optional) y
estimator.fit(X_train_finite)
else:
estimator.fit(X_train_finite, y)
# predict
if hasattr(estimator, "predict"):
try:
estimator.predict(X_train)
except ValueError as e:
if not 'inf' in repr(e) and not 'NaN' in repr(e):
print(error_string_predict, Estimator, e)
traceback.print_exc(file=sys.stdout)
raise e
except Exception as exc:
print(error_string_predict, Estimator, exc)
traceback.print_exc(file=sys.stdout)
else:
raise AssertionError(error_string_predict, Estimator)
# transform
if hasattr(estimator, "transform"):
try:
estimator.transform(X_train)
except ValueError as e:
if not 'inf' in repr(e) and not 'NaN' in repr(e):
print(error_string_transform, Estimator, e)
traceback.print_exc(file=sys.stdout)
raise e
except Exception as exc:
print(error_string_transform, Estimator, exc)
traceback.print_exc(file=sys.stdout)
else:
raise AssertionError(error_string_transform, Estimator)
def test_transformers_pickle():
# test if transformers do something sensible on training set
# also test all shapes / shape errors
transformers = all_estimators(type_filter='transformer')
X, y = make_blobs(n_samples=30, centers=[[0, 0, 0], [1, 1, 1]],
random_state=0, n_features=2, cluster_std=0.1)
n_samples, n_features = X.shape
X = StandardScaler().fit_transform(X)
X -= X.min()
succeeded = True
for name, Transformer in transformers:
if name in dont_test:
continue
# catch deprecation warnings
with warnings.catch_warnings(record=True):
transformer = Transformer()
if not hasattr(transformer, 'transform'):
continue
set_random_state(transformer)
if hasattr(transformer, 'compute_importances'):
transformer.compute_importances = True
if name == "SelectKBest":
# SelectKBest has a default of k=10
# which is more feature than we have.
transformer.k = 1
elif name in ['GaussianRandomProjection', 'SparseRandomProjection']:
# Due to the jl lemma and very few samples, the number
# of components of the random matrix projection will be greater
# than the number of features.
# So we impose a smaller number (avoid "auto" mode)
transformer.n_components = 1
# fit
if name in ('PLSCanonical', 'PLSRegression', 'CCA',
'PLSSVD'):
random_state = np.random.RandomState(seed=12345)
y_ = np.vstack([y, 2 * y + random_state.randint(2, size=len(y))])
y_ = y_.T
else:
y_ = y
transformer.fit(X, y_)
X_pred = transformer.fit(X, y_).transform(X)
pickled_transformer = pickle.dumps(transformer)
unpickled_transformer = pickle.loads(pickled_transformer)
pickled_X_pred = unpickled_transformer.transform(X)
try:
assert_array_almost_equal(pickled_X_pred, X_pred)
except Exception as exc:
succeeded = False
print ("Transformer %s doesn't predict the same value "
"after pickling" % name)
raise exc
assert_true(succeeded)
def test_classifiers_one_label():
# test classifiers trained on a single label always return this label
# or raise an sensible error message
rnd = np.random.RandomState(0)
X_train = rnd.uniform(size=(10, 3))
X_test = rnd.uniform(size=(10, 3))
y = np.ones(10)
classifiers = all_estimators(type_filter='classifier')
error_string_fit = "Classifier can't train when only one class is present."
error_string_predict = ("Classifier can't predict when only one class is "
"present.")
for name, Classifier in classifiers:
if name in dont_test:
continue
# catch deprecation warnings
with warnings.catch_warnings(record=True):
classifier = Classifier()
# try to fit
try:
classifier.fit(X_train, y)
except ValueError as e:
if not 'class' in repr(e):
print(error_string_fit, Classifier, e)
traceback.print_exc(file=sys.stdout)
raise e
else:
continue
except Exception as exc:
print(error_string_fit, Classifier, exc)
traceback.print_exc(file=sys.stdout)
raise exc
# predict
try:
assert_array_equal(classifier.predict(X_test), y)
except Exception as exc:
print(error_string_predict, Classifier, exc)
traceback.print_exc(file=sys.stdout)
def test_clustering():
# test if clustering algorithms do something sensible
# also test all shapes / shape errors
clustering = all_estimators(type_filter='cluster')
iris = load_iris()
X, y = iris.data, iris.target
X, y = shuffle(X, y, random_state=7)
n_samples, n_features = X.shape
X = StandardScaler().fit_transform(X)
for name, Alg in clustering:
if name == 'WardAgglomeration':
# this is clustering on the features
# let's not test that here.
continue
# catch deprecation and neighbors warnings
with warnings.catch_warnings(record=True):
alg = Alg()
if hasattr(alg, "n_clusters"):
alg.set_params(n_clusters=3)
set_random_state(alg)
if name == 'AffinityPropagation':
alg.set_params(preference=-100)
# fit
alg.fit(X)
assert_equal(alg.labels_.shape, (n_samples,))
pred = alg.labels_
assert_greater(adjusted_rand_score(pred, y), 0.4)
# fit another time with ``fit_predict`` and compare results
if name is 'SpectralClustering':
# there is no way to make Spectral clustering deterministic :(
continue
set_random_state(alg)
with warnings.catch_warnings(record=True):
pred2 = alg.fit_predict(X)
assert_array_equal(pred, pred2)
def test_classifiers_train():
# test if classifiers do something sensible on training set
# also test all shapes / shape errors
classifiers = all_estimators(type_filter='classifier')
X_m, y_m = make_blobs(random_state=0)
X_m, y_m = shuffle(X_m, y_m, random_state=7)
X_m = StandardScaler().fit_transform(X_m)
# generate binary problem from multi-class one
y_b = y_m[y_m != 2]
X_b = X_m[y_m != 2]
for (X, y) in [(X_m, y_m), (X_b, y_b)]:
# do it once with binary, once with multiclass
classes = np.unique(y)
n_classes = len(classes)
n_samples, n_features = X.shape
for name, Classifier in classifiers:
if name in dont_test:
continue
if name in ['MultinomialNB', 'BernoulliNB']:
# TODO also test these!
continue
# catch deprecation warnings
with warnings.catch_warnings(record=True):
classifier = Classifier()
# raises error on malformed input for fit
assert_raises(ValueError, classifier.fit, X, y[:-1])
# fit
classifier.fit(X, y)
assert_true(hasattr(classifier, "classes_"))
y_pred = classifier.predict(X)
assert_equal(y_pred.shape, (n_samples,))
# training set performance
assert_greater(accuracy_score(y, y_pred), 0.85)
# raises error on malformed input for predict
assert_raises(ValueError, classifier.predict, X.T)
if hasattr(classifier, "decision_function"):
try:
# decision_function agrees with predict:
decision = classifier.decision_function(X)
if n_classes is 2:
assert_equal(decision.ravel().shape, (n_samples,))
dec_pred = (decision.ravel() > 0).astype(np.int)
assert_array_equal(dec_pred, y_pred)
if (n_classes is 3
and not isinstance(classifier, BaseLibSVM)):
# 1on1 of LibSVM works differently
assert_equal(decision.shape, (n_samples, n_classes))
assert_array_equal(np.argmax(decision, axis=1), y_pred)
# raises error on malformed input
assert_raises(ValueError,
classifier.decision_function, X.T)
# raises error on malformed input for decision_function
assert_raises(ValueError,
classifier.decision_function, X.T)
except NotImplementedError:
pass
if hasattr(classifier, "predict_proba"):
try:
# predict_proba agrees with predict:
y_prob = classifier.predict_proba(X)
assert_equal(y_prob.shape, (n_samples, n_classes))
assert_array_equal(np.argmax(y_prob, axis=1), y_pred)
# check that probas for all classes sum to one
assert_array_almost_equal(
np.sum(y_prob, axis=1), np.ones(n_samples))
# raises error on malformed input
assert_raises(ValueError, classifier.predict_proba, X.T)
# raises error on malformed input for predict_proba
assert_raises(ValueError, classifier.predict_proba, X.T)
except NotImplementedError:
pass
def test_classifiers_classes():
# test if classifiers can cope with non-consecutive classes
classifiers = all_estimators(type_filter='classifier')
iris = load_iris()
X, y = iris.data, iris.target
X, y = shuffle(X, y, random_state=1)
X = StandardScaler().fit_transform(X)
y_names = iris.target_names[y]
for name, Classifier in classifiers:
if name in dont_test:
continue
if name in ['MultinomialNB', 'BernoulliNB']:
# TODO also test these!
continue
if name in ["LabelPropagation", "LabelSpreading"]:
# TODO some complication with -1 label
y_ = y
else:
y_ = y_names
classes = np.unique(y_)
# catch deprecation warnings
with warnings.catch_warnings(record=True):
classifier = Classifier()
# fit
try:
classifier.fit(X, y_)
except Exception as e:
print(e)
y_pred = classifier.predict(X)
# training set performance
assert_array_equal(np.unique(y_), np.unique(y_pred))
accuracy = accuracy_score(y_, y_pred)
assert_greater(accuracy, 0.78,
"accuracy %f of %s not greater than 0.78"
% (accuracy, name))
#assert_array_equal(
#clf.classes_, classes,
#"Unexpected classes_ attribute for %r" % clf)
if np.any(classifier.classes_ != classes):
print("Unexpected classes_ attribute for %r: expected %s, got %s" %
(classifier, classes, classifier.classes_))
def test_classifiers_input_shapes():
# test if classifiers can cope with y.shape = (n_samples, 1)
classifiers = all_estimators(type_filter='classifier')
iris = load_iris()
X, y = iris.data, iris.target
X, y = shuffle(X, y, random_state=1)
X = StandardScaler().fit_transform(X)
for name, Classifier in classifiers:
if name in dont_test:
continue
if name in ["MultinomialNB", "LabelPropagation", "LabelSpreading"]:
# TODO some complication with -1 label
continue
if name in ["DecisionTreeClassifier", "ExtraTreeClassifier"]:
# We don't raise a warning in these classifiers, as
# the column y interface is used by the forests.
continue
# catch deprecation warnings
with warnings.catch_warnings(record=True):
classifier = Classifier()
set_random_state(classifier)
# fit
classifier.fit(X, y)
y_pred = classifier.predict(X)
set_random_state(classifier)
# Check that when a 2D y is given, a DataConversionWarning is
# raised
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always", DataConversionWarning)
classifier.fit(X, y[:, np.newaxis])
try:
assert_equal(len(w), 1)
assert_array_equal(y_pred, classifier.predict(X))
except Exception:
print(classifier)
raise
def test_classifiers_pickle():
# test if classifiers do something sensible on training set
# also test all shapes / shape errors
classifiers = all_estimators(type_filter='classifier')
X_m, y_m = make_blobs(random_state=0)
X_m, y_m = shuffle(X_m, y_m, random_state=7)
X_m = StandardScaler().fit_transform(X_m)
# generate binary problem from multi-class one
y_b = y_m[y_m != 2]
X_b = X_m[y_m != 2]
succeeded = True
for (X, y) in [(X_m, y_m), (X_b, y_b)]:
# do it once with binary, once with multiclass
n_samples, n_features = X.shape
for name, Classifier in classifiers:
if name in dont_test:
continue
if name in ['MultinomialNB', 'BernoulliNB']:
# TODO also test these!
continue
# catch deprecation warnings
with warnings.catch_warnings(record=True):
classifier = Classifier()
# raises error on malformed input for fit
assert_raises(ValueError, classifier.fit, X, y[:-1])
# fit
classifier.fit(X, y)
y_pred = classifier.predict(X)
pickled_classifier = pickle.dumps(classifier)
unpickled_classifier = pickle.loads(pickled_classifier)
pickled_y_pred = unpickled_classifier.predict(X)
try:
assert_array_almost_equal(pickled_y_pred, y_pred)
except Exception as exc:
succeeded = False
print ("Estimator %s doesn't predict the same value "
"after pickling" % name)
raise exc
assert_true(succeeded)
BOSTON = None
def _boston_subset():
global BOSTON
if BOSTON is None:
boston = load_boston()
X, y = boston.data, boston.target
X, y = shuffle(X, y, random_state=0)
X, y = X[:200], y[:200]
X = StandardScaler().fit_transform(X)
BOSTON = X, y
return BOSTON
def test_regressors_int():
# test if regressors can cope with integer labels (by converting them to
# float)
regressors = all_estimators(type_filter='regressor')
X, _ = _boston_subset()
X = X[:50]
rnd = np.random.RandomState(0)
y = rnd.randint(3, size=X.shape[0])
for name, Regressor in regressors:
if name in dont_test or name in ('CCA'):
continue
# catch deprecation warnings
with warnings.catch_warnings(record=True):
# separate estimators to control random seeds
regressor_1 = Regressor()
regressor_2 = Regressor()
set_random_state(regressor_1)
set_random_state(regressor_2)
if name in ('_PLS', 'PLSCanonical', 'PLSRegression'):
y_ = np.vstack([y, 2 * y + rnd.randint(2, size=len(y))])
y_ = y_.T
else:
y_ = y
# fit
regressor_1.fit(X, y_)
pred1 = regressor_1.predict(X)
regressor_2.fit(X, y_.astype(np.float))
pred2 = regressor_2.predict(X)
assert_array_almost_equal(pred1, pred2, 2, name)
def test_regressors_train():
regressors = all_estimators(type_filter='regressor')
# TODO: test with intercept
# TODO: test with multiple responses
X, y = _boston_subset()
y = StandardScaler().fit_transform(y) # X is already scaled
rnd = np.random.RandomState(0)
succeeded = True
for name, Regressor in regressors:
if name in dont_test:
continue
# catch deprecation warnings
with warnings.catch_warnings(record=True):
regressor = Regressor()
if not hasattr(regressor, 'alphas') and hasattr(regressor, 'alpha'):
# linear regressors need to set alpha, but not generalized CV ones
regressor.alpha = 0.01
# raises error on malformed input for fit
assert_raises(ValueError, regressor.fit, X, y[:-1])
# fit
try:
if name in ('PLSCanonical', 'PLSRegression', 'CCA'):
y_ = np.vstack([y, 2 * y + rnd.randint(2, size=len(y))])
y_ = y_.T
else:
y_ = y
regressor.fit(X, y_)
regressor.predict(X)
# TODO: find out why PLS and CCA fail. RANSAC is random
# and furthermore assumes the presence of outliers, hence
# skipped
if name not in ('PLSCanonical', 'CCA', 'RANSACRegressor'):
assert_greater(regressor.score(X, y_), 0.5)
except Exception as e:
print(regressor)
print(e)
print()
succeeded = False
assert_true(succeeded)
def test_regressor_pickle():
# Test that estimators can be pickled, and once pickled
# give the same answer as before.
regressors = all_estimators(type_filter='regressor')
X, y = _boston_subset()
# TODO: test with intercept
# TODO: test with multiple responses
y = StandardScaler().fit_transform(y) # X is already scaled
rnd = np.random.RandomState(0)
succeeded = True
for name, Regressor in regressors:
if name in dont_test:
continue
# catch deprecation warnings
with warnings.catch_warnings(record=True):
regressor = Regressor()
if not hasattr(regressor, 'alphas') and hasattr(regressor, 'alpha'):
# linear regressors need to set alpha, but not generalized CV ones
regressor.alpha = 0.01
if name in ('PLSCanonical', 'PLSRegression', 'CCA'):
y_ = np.vstack([y, 2 * y + rnd.randint(2, size=len(y))])
y_ = y_.T
else:
y_ = y
regressor.fit(X, y_)
y_pred = regressor.predict(X)
# store old predictions
pickled_regressor = pickle.dumps(regressor)
unpickled_regressor = pickle.loads(pickled_regressor)
pickled_y_pred = unpickled_regressor.predict(X)
try:
assert_array_almost_equal(pickled_y_pred, y_pred)
except Exception as exc:
succeeded = False
print ("Estimator %s doesn't predict the same value "
"after pickling" % name)
raise exc
assert_true(succeeded)
def test_configure():
# Smoke test the 'configure' step of setup, this tests all the
# 'configure' functions in the setup.pys in the scikit
cwd = os.getcwd()
setup_path = os.path.abspath(os.path.join(sklearn.__path__[0], '..'))
setup_filename = os.path.join(setup_path, 'setup.py')
if not os.path.exists(setup_filename):
return
try:
os.chdir(setup_path)
old_argv = sys.argv
sys.argv = ['setup.py', 'config']
with warnings.catch_warnings():
# The configuration spits out warnings when not finding
# Blas/Atlas development headers
warnings.simplefilter('ignore', UserWarning)
if PY3:
exec(open('setup.py').read(), dict(__name__='__main__'))
else:
execfile('setup.py', dict(__name__='__main__'))
finally:
sys.argv = old_argv
os.chdir(cwd)
def test_class_weight_classifiers():
# test that class_weight works and that the semantics are consistent
classifiers = all_estimators(type_filter='classifier')
with warnings.catch_warnings(record=True):
classifiers = [c for c in classifiers
if 'class_weight' in c[1]().get_params().keys()]
for n_centers in [2, 3]:
# create a very noisy dataset
X, y = make_blobs(centers=n_centers, random_state=0, cluster_std=20)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.5,
random_state=0)
for name, Classifier in classifiers:
if name == "NuSVC":
# the sparse version has a parameter that doesn't do anything
continue
if name.endswith("NB"):
# NaiveBayes classifiers have a somewhat different interface.
# FIXME SOON!
continue
if n_centers == 2:
class_weight = {0: 1000, 1: 0.0001}
else:
class_weight = {0: 1000, 1: 0.0001, 2: 0.0001}
with warnings.catch_warnings(record=True):
classifier = Classifier(class_weight=class_weight)
if hasattr(classifier, "n_iter"):
classifier.set_params(n_iter=100)
set_random_state(classifier)
classifier.fit(X_train, y_train)
y_pred = classifier.predict(X_test)
assert_greater(np.mean(y_pred == 0), 0.9)
def test_class_weight_auto_classifies():
# test that class_weight="auto" improves f1-score
classifiers = all_estimators(type_filter='classifier')
with warnings.catch_warnings(record=True):
classifiers = [c for c in classifiers
if 'class_weight' in c[1]().get_params().keys()]
for n_classes, weights in zip([2, 3], [[.8, .2], [.8, .1, .1]]):
# create unbalanced dataset
X, y = make_classification(n_classes=n_classes, n_samples=200,
n_features=10, weights=weights,
random_state=0, n_informative=n_classes)
X = StandardScaler().fit_transform(X)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.5,
random_state=0)
for name, Classifier in classifiers:
if name == "NuSVC":
# the sparse version has a parameter that doesn't do anything
continue
if name.startswith("RidgeClassifier"):
# RidgeClassifier behaves unexpected
# FIXME!
continue
if name.endswith("NB"):
# NaiveBayes classifiers have a somewhat different interface.
# FIXME SOON!
continue
with warnings.catch_warnings(record=True):
classifier = Classifier()
if hasattr(classifier, "n_iter"):
classifier.set_params(n_iter=100)
set_random_state(classifier)
classifier.fit(X_train, y_train)
y_pred = classifier.predict(X_test)
classifier.set_params(class_weight='auto')
classifier.fit(X_train, y_train)
y_pred_auto = classifier.predict(X_test)
assert_greater(f1_score(y_test, y_pred_auto),
f1_score(y_test, y_pred))
def test_estimators_overwrite_params():
# test whether any classifier overwrites his init parameters during fit
for est_type in ["classifier", "regressor", "transformer"]:
estimators = all_estimators(type_filter=est_type)
X, y = make_blobs(random_state=0, n_samples=9)
# some want non-negative input
X -= X.min()
for name, Estimator in estimators:
if (name in dont_test
or name in ['CCA', '_CCA', 'PLSCanonical',
'PLSRegression',
'PLSSVD', 'GaussianProcess']):
# FIXME!
# in particular GaussianProcess!
continue
with warnings.catch_warnings(record=True):
# catch deprecation warnings
estimator = Estimator()
if hasattr(estimator, 'batch_size'):
# FIXME
# for MiniBatchDictLearning
estimator.batch_size = 1
if name in ['GaussianRandomProjection',
'SparseRandomProjection']:
# Due to the jl lemma and very few samples, the number
# of components of the random matrix projection will be
# greater
# than the number of features.
# So we impose a smaller number (avoid "auto" mode)
estimator = Estimator(n_components=1)
set_random_state(estimator)
params = estimator.get_params()
estimator.fit(X, y)
new_params = estimator.get_params()
for k, v in params.items():
assert_false(np.any(new_params[k] != v),
"Estimator %s changes its parameter %s"
" from %s to %s during fit."
% (name, k, v, new_params[k]))
def test_cluster_overwrite_params():
# test whether any classifier overwrites his init parameters during fit
clusterers = all_estimators(type_filter="cluster")
X, y = make_blobs(random_state=0, n_samples=9)
# some want non-negative input
X
for name, Clustering in clusterers:
with warnings.catch_warnings(record=True):
# catch deprecation warnings
clustering = Clustering()
params = clustering.get_params()
clustering.fit(X)
new_params = clustering.get_params()
for k, v in params.items():
assert_false(np.any(new_params[k] != v),
"Estimator %s changes its parameter %s"
" from %s to %s during fit."
% (name, k, v, new_params[k]))
def test_import_all_consistency():
# Smoke test to check that any name in a __all__ list is actually defined
# in the namespace of the module or package.
pkgs = pkgutil.walk_packages(path=sklearn.__path__, prefix='sklearn.',
onerror=lambda _: None)
for importer, modname, ispkg in pkgs:
if ".tests." in modname:
continue
package = __import__(modname, fromlist="dummy")
for name in getattr(package, '__all__', ()):
if getattr(package, name, None) is None:
raise AttributeError(
"Module '{}' has no attribute '{}'".format(
modname, name))