PageRenderTime 399ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/HousePrices/PythonSolution/venv/Lib/site-packages/sklearn/model_selection/tests/test_validation.py

https://bitbucket.org/danmohr/machine-learning
Python | 1563 lines | 1136 code | 288 blank | 139 comment | 68 complexity | 06dd6279220eac171f1bd33514ad4a1f MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, 0BSD, BSD-2-Clause, MPL-2.0-no-copyleft-exception, LGPL-3.0
  1. """Test the validation module"""
  2. from __future__ import division
  3. import sys
  4. import warnings
  5. import tempfile
  6. import os
  7. from time import sleep
  8. import pytest
  9. import numpy as np
  10. from scipy.sparse import coo_matrix, csr_matrix
  11. from sklearn.exceptions import FitFailedWarning
  12. from sklearn.model_selection.tests.test_search import FailingClassifier
  13. from sklearn.utils.testing import assert_true
  14. from sklearn.utils.testing import assert_false
  15. from sklearn.utils.testing import assert_equal
  16. from sklearn.utils.testing import assert_almost_equal
  17. from sklearn.utils.testing import assert_raises
  18. from sklearn.utils.testing import assert_raise_message
  19. from sklearn.utils.testing import assert_warns
  20. from sklearn.utils.testing import assert_warns_message
  21. from sklearn.utils.testing import assert_no_warnings
  22. from sklearn.utils.testing import assert_raises_regex
  23. from sklearn.utils.testing import assert_greater
  24. from sklearn.utils.testing import assert_less
  25. from sklearn.utils.testing import assert_array_almost_equal
  26. from sklearn.utils.testing import assert_array_equal
  27. from sklearn.utils.mocking import CheckingClassifier, MockDataFrame
  28. from sklearn.model_selection import cross_val_score
  29. from sklearn.model_selection import cross_val_predict
  30. from sklearn.model_selection import cross_validate
  31. from sklearn.model_selection import permutation_test_score
  32. from sklearn.model_selection import KFold
  33. from sklearn.model_selection import StratifiedKFold
  34. from sklearn.model_selection import LeaveOneOut
  35. from sklearn.model_selection import LeaveOneGroupOut
  36. from sklearn.model_selection import LeavePGroupsOut
  37. from sklearn.model_selection import GroupKFold
  38. from sklearn.model_selection import GroupShuffleSplit
  39. from sklearn.model_selection import learning_curve
  40. from sklearn.model_selection import validation_curve
  41. from sklearn.model_selection._validation import _check_is_permutation
  42. from sklearn.model_selection._validation import _fit_and_score
  43. from sklearn.datasets import make_regression
  44. from sklearn.datasets import load_boston
  45. from sklearn.datasets import load_iris
  46. from sklearn.datasets import load_digits
  47. from sklearn.metrics import explained_variance_score
  48. from sklearn.metrics import make_scorer
  49. from sklearn.metrics import accuracy_score
  50. from sklearn.metrics import confusion_matrix
  51. from sklearn.metrics import precision_recall_fscore_support
  52. from sklearn.metrics import precision_score
  53. from sklearn.metrics import r2_score
  54. from sklearn.metrics.scorer import check_scoring
  55. from sklearn.linear_model import Ridge, LogisticRegression, SGDClassifier
  56. from sklearn.linear_model import PassiveAggressiveClassifier, RidgeClassifier
  57. from sklearn.neighbors import KNeighborsClassifier
  58. from sklearn.svm import SVC
  59. from sklearn.cluster import KMeans
  60. from sklearn.impute import SimpleImputer
  61. from sklearn.preprocessing import LabelEncoder
  62. from sklearn.pipeline import Pipeline
  63. from sklearn.externals.six.moves import cStringIO as StringIO
  64. from sklearn.base import BaseEstimator
  65. from sklearn.base import clone
  66. from sklearn.multiclass import OneVsRestClassifier
  67. from sklearn.utils import shuffle
  68. from sklearn.datasets import make_classification
  69. from sklearn.datasets import make_multilabel_classification
  70. from sklearn.model_selection.tests.common import OneTimeSplitter
  71. from sklearn.model_selection import GridSearchCV
  72. try:
  73. WindowsError
  74. except NameError:
  75. WindowsError = None
  76. class MockImprovingEstimator(BaseEstimator):
  77. """Dummy classifier to test the learning curve"""
  78. def __init__(self, n_max_train_sizes):
  79. self.n_max_train_sizes = n_max_train_sizes
  80. self.train_sizes = 0
  81. self.X_subset = None
  82. def fit(self, X_subset, y_subset=None):
  83. self.X_subset = X_subset
  84. self.train_sizes = X_subset.shape[0]
  85. return self
  86. def predict(self, X):
  87. raise NotImplementedError
  88. def score(self, X=None, Y=None):
  89. # training score becomes worse (2 -> 1), test error better (0 -> 1)
  90. if self._is_training_data(X):
  91. return 2. - float(self.train_sizes) / self.n_max_train_sizes
  92. else:
  93. return float(self.train_sizes) / self.n_max_train_sizes
  94. def _is_training_data(self, X):
  95. return X is self.X_subset
  96. class MockIncrementalImprovingEstimator(MockImprovingEstimator):
  97. """Dummy classifier that provides partial_fit"""
  98. def __init__(self, n_max_train_sizes):
  99. super(MockIncrementalImprovingEstimator,
  100. self).__init__(n_max_train_sizes)
  101. self.x = None
  102. def _is_training_data(self, X):
  103. return self.x in X
  104. def partial_fit(self, X, y=None, **params):
  105. self.train_sizes += X.shape[0]
  106. self.x = X[0]
  107. class MockEstimatorWithParameter(BaseEstimator):
  108. """Dummy classifier to test the validation curve"""
  109. def __init__(self, param=0.5):
  110. self.X_subset = None
  111. self.param = param
  112. def fit(self, X_subset, y_subset):
  113. self.X_subset = X_subset
  114. self.train_sizes = X_subset.shape[0]
  115. return self
  116. def predict(self, X):
  117. raise NotImplementedError
  118. def score(self, X=None, y=None):
  119. return self.param if self._is_training_data(X) else 1 - self.param
  120. def _is_training_data(self, X):
  121. return X is self.X_subset
  122. class MockEstimatorWithSingleFitCallAllowed(MockEstimatorWithParameter):
  123. """Dummy classifier that disallows repeated calls of fit method"""
  124. def fit(self, X_subset, y_subset):
  125. assert_false(
  126. hasattr(self, 'fit_called_'),
  127. 'fit is called the second time'
  128. )
  129. self.fit_called_ = True
  130. return super(type(self), self).fit(X_subset, y_subset)
  131. def predict(self, X):
  132. raise NotImplementedError
  133. class MockClassifier(object):
  134. """Dummy classifier to test the cross-validation"""
  135. def __init__(self, a=0, allow_nd=False):
  136. self.a = a
  137. self.allow_nd = allow_nd
  138. def fit(self, X, Y=None, sample_weight=None, class_prior=None,
  139. sparse_sample_weight=None, sparse_param=None, dummy_int=None,
  140. dummy_str=None, dummy_obj=None, callback=None):
  141. """The dummy arguments are to test that this fit function can
  142. accept non-array arguments through cross-validation, such as:
  143. - int
  144. - str (this is actually array-like)
  145. - object
  146. - function
  147. """
  148. self.dummy_int = dummy_int
  149. self.dummy_str = dummy_str
  150. self.dummy_obj = dummy_obj
  151. if callback is not None:
  152. callback(self)
  153. if self.allow_nd:
  154. X = X.reshape(len(X), -1)
  155. if X.ndim >= 3 and not self.allow_nd:
  156. raise ValueError('X cannot be d')
  157. if sample_weight is not None:
  158. assert_true(sample_weight.shape[0] == X.shape[0],
  159. 'MockClassifier extra fit_param sample_weight.shape[0]'
  160. ' is {0}, should be {1}'.format(sample_weight.shape[0],
  161. X.shape[0]))
  162. if class_prior is not None:
  163. assert_true(class_prior.shape[0] == len(np.unique(y)),
  164. 'MockClassifier extra fit_param class_prior.shape[0]'
  165. ' is {0}, should be {1}'.format(class_prior.shape[0],
  166. len(np.unique(y))))
  167. if sparse_sample_weight is not None:
  168. fmt = ('MockClassifier extra fit_param sparse_sample_weight'
  169. '.shape[0] is {0}, should be {1}')
  170. assert_true(sparse_sample_weight.shape[0] == X.shape[0],
  171. fmt.format(sparse_sample_weight.shape[0], X.shape[0]))
  172. if sparse_param is not None:
  173. fmt = ('MockClassifier extra fit_param sparse_param.shape '
  174. 'is ({0}, {1}), should be ({2}, {3})')
  175. assert_true(sparse_param.shape == P_sparse.shape,
  176. fmt.format(sparse_param.shape[0],
  177. sparse_param.shape[1],
  178. P_sparse.shape[0], P_sparse.shape[1]))
  179. return self
  180. def predict(self, T):
  181. if self.allow_nd:
  182. T = T.reshape(len(T), -1)
  183. return T[:, 0]
  184. def score(self, X=None, Y=None):
  185. return 1. / (1 + np.abs(self.a))
  186. def get_params(self, deep=False):
  187. return {'a': self.a, 'allow_nd': self.allow_nd}
  188. # XXX: use 2D array, since 1D X is being detected as a single sample in
  189. # check_consistent_length
  190. X = np.ones((10, 2))
  191. X_sparse = coo_matrix(X)
  192. y = np.array([0, 0, 1, 1, 2, 2, 3, 3, 4, 4])
  193. # The number of samples per class needs to be > n_splits,
  194. # for StratifiedKFold(n_splits=3)
  195. y2 = np.array([1, 1, 1, 2, 2, 2, 3, 3, 3, 3])
  196. P_sparse = coo_matrix(np.eye(5))
  197. @pytest.mark.filterwarnings('ignore: You should specify a value') # 0.22
  198. def test_cross_val_score():
  199. clf = MockClassifier()
  200. for a in range(-10, 10):
  201. clf.a = a
  202. # Smoke test
  203. scores = cross_val_score(clf, X, y2)
  204. assert_array_equal(scores, clf.score(X, y2))
  205. # test with multioutput y
  206. multioutput_y = np.column_stack([y2, y2[::-1]])
  207. scores = cross_val_score(clf, X_sparse, multioutput_y)
  208. assert_array_equal(scores, clf.score(X_sparse, multioutput_y))
  209. scores = cross_val_score(clf, X_sparse, y2)
  210. assert_array_equal(scores, clf.score(X_sparse, y2))
  211. # test with multioutput y
  212. scores = cross_val_score(clf, X_sparse, multioutput_y)
  213. assert_array_equal(scores, clf.score(X_sparse, multioutput_y))
  214. # test with X and y as list
  215. list_check = lambda x: isinstance(x, list)
  216. clf = CheckingClassifier(check_X=list_check)
  217. scores = cross_val_score(clf, X.tolist(), y2.tolist())
  218. clf = CheckingClassifier(check_y=list_check)
  219. scores = cross_val_score(clf, X, y2.tolist())
  220. assert_raises(ValueError, cross_val_score, clf, X, y2, scoring="sklearn")
  221. # test with 3d X and
  222. X_3d = X[:, :, np.newaxis]
  223. clf = MockClassifier(allow_nd=True)
  224. scores = cross_val_score(clf, X_3d, y2)
  225. clf = MockClassifier(allow_nd=False)
  226. assert_raises(ValueError, cross_val_score, clf, X_3d, y2,
  227. error_score='raise')
  228. @pytest.mark.filterwarnings('ignore:You should specify a value for') # 0.22
  229. def test_cross_validate_many_jobs():
  230. # regression test for #12154: cv='warn' with n_jobs>1 trigger a copy of
  231. # the parameters leading to a failure in check_cv due to cv is 'warn'
  232. # instead of cv == 'warn'.
  233. X, y = load_iris(return_X_y=True)
  234. clf = SVC(gamma='auto')
  235. grid = GridSearchCV(clf, param_grid={'C': [1, 10]})
  236. cross_validate(grid, X, y, n_jobs=2)
  237. @pytest.mark.filterwarnings('ignore: You should specify a value') # 0.22
  238. def test_cross_validate_invalid_scoring_param():
  239. X, y = make_classification(random_state=0)
  240. estimator = MockClassifier()
  241. # Test the errors
  242. error_message_regexp = ".*must be unique strings.*"
  243. # List/tuple of callables should raise a message advising users to use
  244. # dict of names to callables mapping
  245. assert_raises_regex(ValueError, error_message_regexp,
  246. cross_validate, estimator, X, y,
  247. scoring=(make_scorer(precision_score),
  248. make_scorer(accuracy_score)))
  249. assert_raises_regex(ValueError, error_message_regexp,
  250. cross_validate, estimator, X, y,
  251. scoring=(make_scorer(precision_score),))
  252. # So should empty lists/tuples
  253. assert_raises_regex(ValueError, error_message_regexp + "Empty list.*",
  254. cross_validate, estimator, X, y, scoring=())
  255. # So should duplicated entries
  256. assert_raises_regex(ValueError, error_message_regexp + "Duplicate.*",
  257. cross_validate, estimator, X, y,
  258. scoring=('f1_micro', 'f1_micro'))
  259. # Nested Lists should raise a generic error message
  260. assert_raises_regex(ValueError, error_message_regexp,
  261. cross_validate, estimator, X, y,
  262. scoring=[[make_scorer(precision_score)]])
  263. error_message_regexp = (".*should either be.*string or callable.*for "
  264. "single.*.*dict.*for multi.*")
  265. # Empty dict should raise invalid scoring error
  266. assert_raises_regex(ValueError, "An empty dict",
  267. cross_validate, estimator, X, y, scoring=(dict()))
  268. # And so should any other invalid entry
  269. assert_raises_regex(ValueError, error_message_regexp,
  270. cross_validate, estimator, X, y, scoring=5)
  271. multiclass_scorer = make_scorer(precision_recall_fscore_support)
  272. # Multiclass Scorers that return multiple values are not supported yet
  273. assert_raises_regex(ValueError,
  274. "Classification metrics can't handle a mix of "
  275. "binary and continuous targets",
  276. cross_validate, estimator, X, y,
  277. scoring=multiclass_scorer)
  278. assert_raises_regex(ValueError,
  279. "Classification metrics can't handle a mix of "
  280. "binary and continuous targets",
  281. cross_validate, estimator, X, y,
  282. scoring={"foo": multiclass_scorer})
  283. multivalued_scorer = make_scorer(confusion_matrix)
  284. # Multiclass Scorers that return multiple values are not supported yet
  285. assert_raises_regex(ValueError, "scoring must return a number, got",
  286. cross_validate, SVC(gamma='scale'), X, y,
  287. scoring=multivalued_scorer)
  288. assert_raises_regex(ValueError, "scoring must return a number, got",
  289. cross_validate, SVC(gamma='scale'), X, y,
  290. scoring={"foo": multivalued_scorer})
  291. assert_raises_regex(ValueError, "'mse' is not a valid scoring value.",
  292. cross_validate, SVC(), X, y, scoring="mse")
  293. def test_cross_validate():
  294. # Compute train and test mse/r2 scores
  295. cv = KFold(n_splits=5)
  296. # Regression
  297. X_reg, y_reg = make_regression(n_samples=30, random_state=0)
  298. reg = Ridge(random_state=0)
  299. # Classification
  300. X_clf, y_clf = make_classification(n_samples=30, random_state=0)
  301. clf = SVC(kernel="linear", random_state=0)
  302. for X, y, est in ((X_reg, y_reg, reg), (X_clf, y_clf, clf)):
  303. # It's okay to evaluate regression metrics on classification too
  304. mse_scorer = check_scoring(est, 'neg_mean_squared_error')
  305. r2_scorer = check_scoring(est, 'r2')
  306. train_mse_scores = []
  307. test_mse_scores = []
  308. train_r2_scores = []
  309. test_r2_scores = []
  310. fitted_estimators = []
  311. for train, test in cv.split(X, y):
  312. est = clone(reg).fit(X[train], y[train])
  313. train_mse_scores.append(mse_scorer(est, X[train], y[train]))
  314. train_r2_scores.append(r2_scorer(est, X[train], y[train]))
  315. test_mse_scores.append(mse_scorer(est, X[test], y[test]))
  316. test_r2_scores.append(r2_scorer(est, X[test], y[test]))
  317. fitted_estimators.append(est)
  318. train_mse_scores = np.array(train_mse_scores)
  319. test_mse_scores = np.array(test_mse_scores)
  320. train_r2_scores = np.array(train_r2_scores)
  321. test_r2_scores = np.array(test_r2_scores)
  322. fitted_estimators = np.array(fitted_estimators)
  323. scores = (train_mse_scores, test_mse_scores, train_r2_scores,
  324. test_r2_scores, fitted_estimators)
  325. check_cross_validate_single_metric(est, X, y, scores)
  326. check_cross_validate_multi_metric(est, X, y, scores)
  327. def test_cross_validate_return_train_score_warn():
  328. # Test that warnings are raised. Will be removed in 0.21
  329. X, y = make_classification(random_state=0)
  330. estimator = MockClassifier()
  331. result = {}
  332. for val in [False, True, 'warn']:
  333. result[val] = assert_no_warnings(cross_validate, estimator, X, y,
  334. return_train_score=val, cv=5)
  335. msg = (
  336. 'You are accessing a training score ({!r}), '
  337. 'which will not be available by default '
  338. 'any more in 0.21. If you need training scores, '
  339. 'please set return_train_score=True').format('train_score')
  340. train_score = assert_warns_message(FutureWarning, msg,
  341. result['warn'].get, 'train_score')
  342. assert np.allclose(train_score, result[True]['train_score'])
  343. assert 'train_score' not in result[False]
  344. def check_cross_validate_single_metric(clf, X, y, scores):
  345. (train_mse_scores, test_mse_scores, train_r2_scores,
  346. test_r2_scores, fitted_estimators) = scores
  347. # Test single metric evaluation when scoring is string or singleton list
  348. for (return_train_score, dict_len) in ((True, 4), (False, 3)):
  349. # Single metric passed as a string
  350. if return_train_score:
  351. # It must be True by default - deprecated
  352. mse_scores_dict = cross_validate(clf, X, y, cv=5,
  353. scoring='neg_mean_squared_error',
  354. return_train_score=True)
  355. assert_array_almost_equal(mse_scores_dict['train_score'],
  356. train_mse_scores)
  357. else:
  358. mse_scores_dict = cross_validate(clf, X, y, cv=5,
  359. scoring='neg_mean_squared_error',
  360. return_train_score=False)
  361. assert isinstance(mse_scores_dict, dict)
  362. assert_equal(len(mse_scores_dict), dict_len)
  363. assert_array_almost_equal(mse_scores_dict['test_score'],
  364. test_mse_scores)
  365. # Single metric passed as a list
  366. if return_train_score:
  367. # It must be True by default - deprecated
  368. r2_scores_dict = cross_validate(clf, X, y, cv=5, scoring=['r2'],
  369. return_train_score=True)
  370. assert_array_almost_equal(r2_scores_dict['train_r2'],
  371. train_r2_scores, True)
  372. else:
  373. r2_scores_dict = cross_validate(clf, X, y, cv=5, scoring=['r2'],
  374. return_train_score=False)
  375. assert isinstance(r2_scores_dict, dict)
  376. assert_equal(len(r2_scores_dict), dict_len)
  377. assert_array_almost_equal(r2_scores_dict['test_r2'], test_r2_scores)
  378. # Test return_estimator option
  379. mse_scores_dict = cross_validate(clf, X, y, cv=5,
  380. scoring='neg_mean_squared_error',
  381. return_estimator=True)
  382. for k, est in enumerate(mse_scores_dict['estimator']):
  383. assert_almost_equal(est.coef_, fitted_estimators[k].coef_)
  384. assert_almost_equal(est.intercept_, fitted_estimators[k].intercept_)
  385. def check_cross_validate_multi_metric(clf, X, y, scores):
  386. # Test multimetric evaluation when scoring is a list / dict
  387. (train_mse_scores, test_mse_scores, train_r2_scores,
  388. test_r2_scores, fitted_estimators) = scores
  389. all_scoring = (('r2', 'neg_mean_squared_error'),
  390. {'r2': make_scorer(r2_score),
  391. 'neg_mean_squared_error': 'neg_mean_squared_error'})
  392. keys_sans_train = set(('test_r2', 'test_neg_mean_squared_error',
  393. 'fit_time', 'score_time'))
  394. keys_with_train = keys_sans_train.union(
  395. set(('train_r2', 'train_neg_mean_squared_error')))
  396. for return_train_score in (True, False):
  397. for scoring in all_scoring:
  398. if return_train_score:
  399. # return_train_score must be True by default - deprecated
  400. cv_results = cross_validate(clf, X, y, cv=5, scoring=scoring,
  401. return_train_score=True)
  402. assert_array_almost_equal(cv_results['train_r2'],
  403. train_r2_scores)
  404. assert_array_almost_equal(
  405. cv_results['train_neg_mean_squared_error'],
  406. train_mse_scores)
  407. else:
  408. cv_results = cross_validate(clf, X, y, cv=5, scoring=scoring,
  409. return_train_score=False)
  410. assert isinstance(cv_results, dict)
  411. assert_equal(set(cv_results.keys()),
  412. keys_with_train if return_train_score
  413. else keys_sans_train)
  414. assert_array_almost_equal(cv_results['test_r2'], test_r2_scores)
  415. assert_array_almost_equal(
  416. cv_results['test_neg_mean_squared_error'], test_mse_scores)
  417. # Make sure all the arrays are of np.ndarray type
  418. assert type(cv_results['test_r2']) == np.ndarray
  419. assert (type(cv_results['test_neg_mean_squared_error']) ==
  420. np.ndarray)
  421. assert type(cv_results['fit_time']) == np.ndarray
  422. assert type(cv_results['score_time']) == np.ndarray
  423. # Ensure all the times are within sane limits
  424. assert np.all(cv_results['fit_time'] >= 0)
  425. assert np.all(cv_results['fit_time'] < 10)
  426. assert np.all(cv_results['score_time'] >= 0)
  427. assert np.all(cv_results['score_time'] < 10)
  428. @pytest.mark.filterwarnings('ignore: You should specify a value') # 0.22
  429. def test_cross_val_score_predict_groups():
  430. # Check if ValueError (when groups is None) propagates to cross_val_score
  431. # and cross_val_predict
  432. # And also check if groups is correctly passed to the cv object
  433. X, y = make_classification(n_samples=20, n_classes=2, random_state=0)
  434. clf = SVC(kernel="linear")
  435. group_cvs = [LeaveOneGroupOut(), LeavePGroupsOut(2), GroupKFold(),
  436. GroupShuffleSplit()]
  437. for cv in group_cvs:
  438. assert_raise_message(ValueError,
  439. "The 'groups' parameter should not be None.",
  440. cross_val_score, estimator=clf, X=X, y=y, cv=cv)
  441. assert_raise_message(ValueError,
  442. "The 'groups' parameter should not be None.",
  443. cross_val_predict, estimator=clf, X=X, y=y, cv=cv)
  444. @pytest.mark.filterwarnings('ignore: Using or importing the ABCs from')
  445. @pytest.mark.filterwarnings('ignore: You should specify a value') # 0.22
  446. def test_cross_val_score_pandas():
  447. # check cross_val_score doesn't destroy pandas dataframe
  448. types = [(MockDataFrame, MockDataFrame)]
  449. try:
  450. from pandas import Series, DataFrame
  451. types.append((Series, DataFrame))
  452. except ImportError:
  453. pass
  454. for TargetType, InputFeatureType in types:
  455. # X dataframe, y series
  456. # 3 fold cross val is used so we need atleast 3 samples per class
  457. X_df, y_ser = InputFeatureType(X), TargetType(y2)
  458. check_df = lambda x: isinstance(x, InputFeatureType)
  459. check_series = lambda x: isinstance(x, TargetType)
  460. clf = CheckingClassifier(check_X=check_df, check_y=check_series)
  461. cross_val_score(clf, X_df, y_ser)
  462. def test_cross_val_score_mask():
  463. # test that cross_val_score works with boolean masks
  464. svm = SVC(kernel="linear")
  465. iris = load_iris()
  466. X, y = iris.data, iris.target
  467. kfold = KFold(5)
  468. scores_indices = cross_val_score(svm, X, y, cv=kfold)
  469. kfold = KFold(5)
  470. cv_masks = []
  471. for train, test in kfold.split(X, y):
  472. mask_train = np.zeros(len(y), dtype=np.bool)
  473. mask_test = np.zeros(len(y), dtype=np.bool)
  474. mask_train[train] = 1
  475. mask_test[test] = 1
  476. cv_masks.append((train, test))
  477. scores_masks = cross_val_score(svm, X, y, cv=cv_masks)
  478. assert_array_equal(scores_indices, scores_masks)
  479. @pytest.mark.filterwarnings('ignore: You should specify a value') # 0.22
  480. def test_cross_val_score_precomputed():
  481. # test for svm with precomputed kernel
  482. svm = SVC(kernel="precomputed")
  483. iris = load_iris()
  484. X, y = iris.data, iris.target
  485. linear_kernel = np.dot(X, X.T)
  486. score_precomputed = cross_val_score(svm, linear_kernel, y)
  487. svm = SVC(kernel="linear")
  488. score_linear = cross_val_score(svm, X, y)
  489. assert_array_almost_equal(score_precomputed, score_linear)
  490. # test with callable
  491. svm = SVC(gamma='scale', kernel=lambda x, y: np.dot(x, y.T))
  492. score_callable = cross_val_score(svm, X, y)
  493. assert_array_almost_equal(score_precomputed, score_callable)
  494. # Error raised for non-square X
  495. svm = SVC(kernel="precomputed")
  496. assert_raises(ValueError, cross_val_score, svm, X, y)
  497. # test error is raised when the precomputed kernel is not array-like
  498. # or sparse
  499. assert_raises(ValueError, cross_val_score, svm,
  500. linear_kernel.tolist(), y)
  501. @pytest.mark.filterwarnings('ignore: You should specify a value') # 0.22
  502. def test_cross_val_score_fit_params():
  503. clf = MockClassifier()
  504. n_samples = X.shape[0]
  505. n_classes = len(np.unique(y))
  506. W_sparse = coo_matrix((np.array([1]), (np.array([1]), np.array([0]))),
  507. shape=(10, 1))
  508. P_sparse = coo_matrix(np.eye(5))
  509. DUMMY_INT = 42
  510. DUMMY_STR = '42'
  511. DUMMY_OBJ = object()
  512. def assert_fit_params(clf):
  513. # Function to test that the values are passed correctly to the
  514. # classifier arguments for non-array type
  515. assert_equal(clf.dummy_int, DUMMY_INT)
  516. assert_equal(clf.dummy_str, DUMMY_STR)
  517. assert_equal(clf.dummy_obj, DUMMY_OBJ)
  518. fit_params = {'sample_weight': np.ones(n_samples),
  519. 'class_prior': np.full(n_classes, 1. / n_classes),
  520. 'sparse_sample_weight': W_sparse,
  521. 'sparse_param': P_sparse,
  522. 'dummy_int': DUMMY_INT,
  523. 'dummy_str': DUMMY_STR,
  524. 'dummy_obj': DUMMY_OBJ,
  525. 'callback': assert_fit_params}
  526. cross_val_score(clf, X, y, fit_params=fit_params)
  527. def test_cross_val_score_score_func():
  528. clf = MockClassifier()
  529. _score_func_args = []
  530. def score_func(y_test, y_predict):
  531. _score_func_args.append((y_test, y_predict))
  532. return 1.0
  533. with warnings.catch_warnings(record=True):
  534. scoring = make_scorer(score_func)
  535. score = cross_val_score(clf, X, y, scoring=scoring, cv=3)
  536. assert_array_equal(score, [1.0, 1.0, 1.0])
  537. # Test that score function is called only 3 times (for cv=3)
  538. assert len(_score_func_args) == 3
  539. def test_cross_val_score_errors():
  540. class BrokenEstimator:
  541. pass
  542. assert_raises(TypeError, cross_val_score, BrokenEstimator(), X)
  543. def test_cross_val_score_with_score_func_classification():
  544. iris = load_iris()
  545. clf = SVC(kernel='linear')
  546. # Default score (should be the accuracy score)
  547. scores = cross_val_score(clf, iris.data, iris.target, cv=5)
  548. assert_array_almost_equal(scores, [0.97, 1., 0.97, 0.97, 1.], 2)
  549. # Correct classification score (aka. zero / one score) - should be the
  550. # same as the default estimator score
  551. zo_scores = cross_val_score(clf, iris.data, iris.target,
  552. scoring="accuracy", cv=5)
  553. assert_array_almost_equal(zo_scores, [0.97, 1., 0.97, 0.97, 1.], 2)
  554. # F1 score (class are balanced so f1_score should be equal to zero/one
  555. # score
  556. f1_scores = cross_val_score(clf, iris.data, iris.target,
  557. scoring="f1_weighted", cv=5)
  558. assert_array_almost_equal(f1_scores, [0.97, 1., 0.97, 0.97, 1.], 2)
  559. def test_cross_val_score_with_score_func_regression():
  560. X, y = make_regression(n_samples=30, n_features=20, n_informative=5,
  561. random_state=0)
  562. reg = Ridge()
  563. # Default score of the Ridge regression estimator
  564. scores = cross_val_score(reg, X, y, cv=5)
  565. assert_array_almost_equal(scores, [0.94, 0.97, 0.97, 0.99, 0.92], 2)
  566. # R2 score (aka. determination coefficient) - should be the
  567. # same as the default estimator score
  568. r2_scores = cross_val_score(reg, X, y, scoring="r2", cv=5)
  569. assert_array_almost_equal(r2_scores, [0.94, 0.97, 0.97, 0.99, 0.92], 2)
  570. # Mean squared error; this is a loss function, so "scores" are negative
  571. neg_mse_scores = cross_val_score(reg, X, y, cv=5,
  572. scoring="neg_mean_squared_error")
  573. expected_neg_mse = np.array([-763.07, -553.16, -274.38, -273.26, -1681.99])
  574. assert_array_almost_equal(neg_mse_scores, expected_neg_mse, 2)
  575. # Explained variance
  576. scoring = make_scorer(explained_variance_score)
  577. ev_scores = cross_val_score(reg, X, y, cv=5, scoring=scoring)
  578. assert_array_almost_equal(ev_scores, [0.94, 0.97, 0.97, 0.99, 0.92], 2)
  579. def test_permutation_score():
  580. iris = load_iris()
  581. X = iris.data
  582. X_sparse = coo_matrix(X)
  583. y = iris.target
  584. svm = SVC(kernel='linear')
  585. cv = StratifiedKFold(2)
  586. score, scores, pvalue = permutation_test_score(
  587. svm, X, y, n_permutations=30, cv=cv, scoring="accuracy")
  588. assert_greater(score, 0.9)
  589. assert_almost_equal(pvalue, 0.0, 1)
  590. score_group, _, pvalue_group = permutation_test_score(
  591. svm, X, y, n_permutations=30, cv=cv, scoring="accuracy",
  592. groups=np.ones(y.size), random_state=0)
  593. assert score_group == score
  594. assert pvalue_group == pvalue
  595. # check that we obtain the same results with a sparse representation
  596. svm_sparse = SVC(kernel='linear')
  597. cv_sparse = StratifiedKFold(2)
  598. score_group, _, pvalue_group = permutation_test_score(
  599. svm_sparse, X_sparse, y, n_permutations=30, cv=cv_sparse,
  600. scoring="accuracy", groups=np.ones(y.size), random_state=0)
  601. assert score_group == score
  602. assert pvalue_group == pvalue
  603. # test with custom scoring object
  604. def custom_score(y_true, y_pred):
  605. return (((y_true == y_pred).sum() - (y_true != y_pred).sum()) /
  606. y_true.shape[0])
  607. scorer = make_scorer(custom_score)
  608. score, _, pvalue = permutation_test_score(
  609. svm, X, y, n_permutations=100, scoring=scorer, cv=cv, random_state=0)
  610. assert_almost_equal(score, .93, 2)
  611. assert_almost_equal(pvalue, 0.01, 3)
  612. # set random y
  613. y = np.mod(np.arange(len(y)), 3)
  614. score, scores, pvalue = permutation_test_score(
  615. svm, X, y, n_permutations=30, cv=cv, scoring="accuracy")
  616. assert_less(score, 0.5)
  617. assert_greater(pvalue, 0.2)
  618. def test_permutation_test_score_allow_nans():
  619. # Check that permutation_test_score allows input data with NaNs
  620. X = np.arange(200, dtype=np.float64).reshape(10, -1)
  621. X[2, :] = np.nan
  622. y = np.repeat([0, 1], X.shape[0] / 2)
  623. p = Pipeline([
  624. ('imputer', SimpleImputer(strategy='mean', missing_values=np.nan)),
  625. ('classifier', MockClassifier()),
  626. ])
  627. permutation_test_score(p, X, y, cv=5)
  628. def test_cross_val_score_allow_nans():
  629. # Check that cross_val_score allows input data with NaNs
  630. X = np.arange(200, dtype=np.float64).reshape(10, -1)
  631. X[2, :] = np.nan
  632. y = np.repeat([0, 1], X.shape[0] / 2)
  633. p = Pipeline([
  634. ('imputer', SimpleImputer(strategy='mean', missing_values=np.nan)),
  635. ('classifier', MockClassifier()),
  636. ])
  637. cross_val_score(p, X, y, cv=5)
  638. def test_cross_val_score_multilabel():
  639. X = np.array([[-3, 4], [2, 4], [3, 3], [0, 2], [-3, 1],
  640. [-2, 1], [0, 0], [-2, -1], [-1, -2], [1, -2]])
  641. y = np.array([[1, 1], [0, 1], [0, 1], [0, 1], [1, 1],
  642. [0, 1], [1, 0], [1, 1], [1, 0], [0, 0]])
  643. clf = KNeighborsClassifier(n_neighbors=1)
  644. scoring_micro = make_scorer(precision_score, average='micro')
  645. scoring_macro = make_scorer(precision_score, average='macro')
  646. scoring_samples = make_scorer(precision_score, average='samples')
  647. score_micro = cross_val_score(clf, X, y, scoring=scoring_micro, cv=5)
  648. score_macro = cross_val_score(clf, X, y, scoring=scoring_macro, cv=5)
  649. score_samples = cross_val_score(clf, X, y, scoring=scoring_samples, cv=5)
  650. assert_almost_equal(score_micro, [1, 1 / 2, 3 / 4, 1 / 2, 1 / 3])
  651. assert_almost_equal(score_macro, [1, 1 / 2, 3 / 4, 1 / 2, 1 / 4])
  652. assert_almost_equal(score_samples, [1, 1 / 2, 3 / 4, 1 / 2, 1 / 4])
  653. @pytest.mark.filterwarnings('ignore: Default solver will be changed') # 0.22
  654. @pytest.mark.filterwarnings('ignore: Default multi_class will') # 0.22
  655. @pytest.mark.filterwarnings('ignore: You should specify a value') # 0.22
  656. def test_cross_val_predict():
  657. boston = load_boston()
  658. X, y = boston.data, boston.target
  659. cv = KFold()
  660. est = Ridge()
  661. # Naive loop (should be same as cross_val_predict):
  662. preds2 = np.zeros_like(y)
  663. for train, test in cv.split(X, y):
  664. est.fit(X[train], y[train])
  665. preds2[test] = est.predict(X[test])
  666. preds = cross_val_predict(est, X, y, cv=cv)
  667. assert_array_almost_equal(preds, preds2)
  668. preds = cross_val_predict(est, X, y)
  669. assert_equal(len(preds), len(y))
  670. cv = LeaveOneOut()
  671. preds = cross_val_predict(est, X, y, cv=cv)
  672. assert_equal(len(preds), len(y))
  673. Xsp = X.copy()
  674. Xsp *= (Xsp > np.median(Xsp))
  675. Xsp = coo_matrix(Xsp)
  676. preds = cross_val_predict(est, Xsp, y)
  677. assert_array_almost_equal(len(preds), len(y))
  678. preds = cross_val_predict(KMeans(), X)
  679. assert_equal(len(preds), len(y))
  680. class BadCV():
  681. def split(self, X, y=None, groups=None):
  682. for i in range(4):
  683. yield np.array([0, 1, 2, 3]), np.array([4, 5, 6, 7, 8])
  684. assert_raises(ValueError, cross_val_predict, est, X, y, cv=BadCV())
  685. X, y = load_iris(return_X_y=True)
  686. warning_message = ('Number of classes in training fold (2) does '
  687. 'not match total number of classes (3). '
  688. 'Results may not be appropriate for your use case.')
  689. assert_warns_message(RuntimeWarning, warning_message,
  690. cross_val_predict, LogisticRegression(),
  691. X, y, method='predict_proba', cv=KFold(2))
  692. @pytest.mark.filterwarnings('ignore: Default solver will be changed') # 0.22
  693. @pytest.mark.filterwarnings('ignore: Default multi_class will') # 0.22
  694. @pytest.mark.filterwarnings('ignore: You should specify a value') # 0.22
  695. def test_cross_val_predict_decision_function_shape():
  696. X, y = make_classification(n_classes=2, n_samples=50, random_state=0)
  697. preds = cross_val_predict(LogisticRegression(), X, y,
  698. method='decision_function')
  699. assert_equal(preds.shape, (50,))
  700. X, y = load_iris(return_X_y=True)
  701. preds = cross_val_predict(LogisticRegression(), X, y,
  702. method='decision_function')
  703. assert_equal(preds.shape, (150, 3))
  704. # This specifically tests imbalanced splits for binary
  705. # classification with decision_function. This is only
  706. # applicable to classifiers that can be fit on a single
  707. # class.
  708. X = X[:100]
  709. y = y[:100]
  710. assert_raise_message(ValueError,
  711. 'Only 1 class/es in training fold, this'
  712. ' is not supported for decision_function'
  713. ' with imbalanced folds. To fix '
  714. 'this, use a cross-validation technique '
  715. 'resulting in properly stratified folds',
  716. cross_val_predict, RidgeClassifier(), X, y,
  717. method='decision_function', cv=KFold(2))
  718. X, y = load_digits(return_X_y=True)
  719. est = SVC(kernel='linear', decision_function_shape='ovo')
  720. preds = cross_val_predict(est,
  721. X, y,
  722. method='decision_function')
  723. assert_equal(preds.shape, (1797, 45))
  724. ind = np.argsort(y)
  725. X, y = X[ind], y[ind]
  726. assert_raises_regex(ValueError,
  727. r'Output shape \(599L?, 21L?\) of decision_function '
  728. r'does not match number of classes \(7\) in fold. '
  729. 'Irregular decision_function .*',
  730. cross_val_predict, est, X, y,
  731. cv=KFold(n_splits=3), method='decision_function')
  732. @pytest.mark.filterwarnings('ignore: Default solver will be changed') # 0.22
  733. @pytest.mark.filterwarnings('ignore: Default multi_class will') # 0.22
  734. @pytest.mark.filterwarnings('ignore: You should specify a value') # 0.22
  735. def test_cross_val_predict_predict_proba_shape():
  736. X, y = make_classification(n_classes=2, n_samples=50, random_state=0)
  737. preds = cross_val_predict(LogisticRegression(), X, y,
  738. method='predict_proba')
  739. assert_equal(preds.shape, (50, 2))
  740. X, y = load_iris(return_X_y=True)
  741. preds = cross_val_predict(LogisticRegression(), X, y,
  742. method='predict_proba')
  743. assert_equal(preds.shape, (150, 3))
  744. @pytest.mark.filterwarnings('ignore: Default solver will be changed') # 0.22
  745. @pytest.mark.filterwarnings('ignore: Default multi_class will') # 0.22
  746. @pytest.mark.filterwarnings('ignore: You should specify a value') # 0.22
  747. def test_cross_val_predict_predict_log_proba_shape():
  748. X, y = make_classification(n_classes=2, n_samples=50, random_state=0)
  749. preds = cross_val_predict(LogisticRegression(), X, y,
  750. method='predict_log_proba')
  751. assert_equal(preds.shape, (50, 2))
  752. X, y = load_iris(return_X_y=True)
  753. preds = cross_val_predict(LogisticRegression(), X, y,
  754. method='predict_log_proba')
  755. assert_equal(preds.shape, (150, 3))
  756. @pytest.mark.filterwarnings('ignore: Default solver will be changed') # 0.22
  757. @pytest.mark.filterwarnings('ignore: Default multi_class will') # 0.22
  758. @pytest.mark.filterwarnings('ignore: You should specify a value') # 0.22
  759. def test_cross_val_predict_input_types():
  760. iris = load_iris()
  761. X, y = iris.data, iris.target
  762. X_sparse = coo_matrix(X)
  763. multioutput_y = np.column_stack([y, y[::-1]])
  764. clf = Ridge(fit_intercept=False, random_state=0)
  765. # 3 fold cv is used --> atleast 3 samples per class
  766. # Smoke test
  767. predictions = cross_val_predict(clf, X, y)
  768. assert_equal(predictions.shape, (150,))
  769. # test with multioutput y
  770. predictions = cross_val_predict(clf, X_sparse, multioutput_y)
  771. assert_equal(predictions.shape, (150, 2))
  772. predictions = cross_val_predict(clf, X_sparse, y)
  773. assert_array_equal(predictions.shape, (150,))
  774. # test with multioutput y
  775. predictions = cross_val_predict(clf, X_sparse, multioutput_y)
  776. assert_array_equal(predictions.shape, (150, 2))
  777. # test with X and y as list
  778. list_check = lambda x: isinstance(x, list)
  779. clf = CheckingClassifier(check_X=list_check)
  780. predictions = cross_val_predict(clf, X.tolist(), y.tolist())
  781. clf = CheckingClassifier(check_y=list_check)
  782. predictions = cross_val_predict(clf, X, y.tolist())
  783. # test with X and y as list and non empty method
  784. predictions = cross_val_predict(LogisticRegression(), X.tolist(),
  785. y.tolist(), method='decision_function')
  786. predictions = cross_val_predict(LogisticRegression(), X,
  787. y.tolist(), method='decision_function')
  788. # test with 3d X and
  789. X_3d = X[:, :, np.newaxis]
  790. check_3d = lambda x: x.ndim == 3
  791. clf = CheckingClassifier(check_X=check_3d)
  792. predictions = cross_val_predict(clf, X_3d, y)
  793. assert_array_equal(predictions.shape, (150,))
  794. @pytest.mark.filterwarnings('ignore: Using or importing the ABCs from')
  795. @pytest.mark.filterwarnings('ignore: You should specify a value') # 0.22
  796. # python3.7 deprecation warnings in pandas via matplotlib :-/
  797. def test_cross_val_predict_pandas():
  798. # check cross_val_score doesn't destroy pandas dataframe
  799. types = [(MockDataFrame, MockDataFrame)]
  800. try:
  801. from pandas import Series, DataFrame
  802. types.append((Series, DataFrame))
  803. except ImportError:
  804. pass
  805. for TargetType, InputFeatureType in types:
  806. # X dataframe, y series
  807. X_df, y_ser = InputFeatureType(X), TargetType(y2)
  808. check_df = lambda x: isinstance(x, InputFeatureType)
  809. check_series = lambda x: isinstance(x, TargetType)
  810. clf = CheckingClassifier(check_X=check_df, check_y=check_series)
  811. cross_val_predict(clf, X_df, y_ser)
  812. @pytest.mark.filterwarnings('ignore: You should specify a value') # 0.22
  813. def test_cross_val_score_sparse_fit_params():
  814. iris = load_iris()
  815. X, y = iris.data, iris.target
  816. clf = MockClassifier()
  817. fit_params = {'sparse_sample_weight': coo_matrix(np.eye(X.shape[0]))}
  818. a = cross_val_score(clf, X, y, fit_params=fit_params)
  819. assert_array_equal(a, np.ones(3))
  820. def test_learning_curve():
  821. n_samples = 30
  822. n_splits = 3
  823. X, y = make_classification(n_samples=n_samples, n_features=1,
  824. n_informative=1, n_redundant=0, n_classes=2,
  825. n_clusters_per_class=1, random_state=0)
  826. estimator = MockImprovingEstimator(n_samples * ((n_splits - 1) / n_splits))
  827. for shuffle_train in [False, True]:
  828. with warnings.catch_warnings(record=True) as w:
  829. train_sizes, train_scores, test_scores = learning_curve(
  830. estimator, X, y, cv=KFold(n_splits=n_splits),
  831. train_sizes=np.linspace(0.1, 1.0, 10),
  832. shuffle=shuffle_train)
  833. if len(w) > 0:
  834. raise RuntimeError("Unexpected warning: %r" % w[0].message)
  835. assert_equal(train_scores.shape, (10, 3))
  836. assert_equal(test_scores.shape, (10, 3))
  837. assert_array_equal(train_sizes, np.linspace(2, 20, 10))
  838. assert_array_almost_equal(train_scores.mean(axis=1),
  839. np.linspace(1.9, 1.0, 10))
  840. assert_array_almost_equal(test_scores.mean(axis=1),
  841. np.linspace(0.1, 1.0, 10))
  842. # Test a custom cv splitter that can iterate only once
  843. with warnings.catch_warnings(record=True) as w:
  844. train_sizes2, train_scores2, test_scores2 = learning_curve(
  845. estimator, X, y,
  846. cv=OneTimeSplitter(n_splits=n_splits, n_samples=n_samples),
  847. train_sizes=np.linspace(0.1, 1.0, 10),
  848. shuffle=shuffle_train)
  849. if len(w) > 0:
  850. raise RuntimeError("Unexpected warning: %r" % w[0].message)
  851. assert_array_almost_equal(train_scores2, train_scores)
  852. assert_array_almost_equal(test_scores2, test_scores)
  853. def test_learning_curve_unsupervised():
  854. X, _ = make_classification(n_samples=30, n_features=1, n_informative=1,
  855. n_redundant=0, n_classes=2,
  856. n_clusters_per_class=1, random_state=0)
  857. estimator = MockImprovingEstimator(20)
  858. train_sizes, train_scores, test_scores = learning_curve(
  859. estimator, X, y=None, cv=3, train_sizes=np.linspace(0.1, 1.0, 10))
  860. assert_array_equal(train_sizes, np.linspace(2, 20, 10))
  861. assert_array_almost_equal(train_scores.mean(axis=1),
  862. np.linspace(1.9, 1.0, 10))
  863. assert_array_almost_equal(test_scores.mean(axis=1),
  864. np.linspace(0.1, 1.0, 10))
  865. def test_learning_curve_verbose():
  866. X, y = make_classification(n_samples=30, n_features=1, n_informative=1,
  867. n_redundant=0, n_classes=2,
  868. n_clusters_per_class=1, random_state=0)
  869. estimator = MockImprovingEstimator(20)
  870. old_stdout = sys.stdout
  871. sys.stdout = StringIO()
  872. try:
  873. train_sizes, train_scores, test_scores = \
  874. learning_curve(estimator, X, y, cv=3, verbose=1)
  875. finally:
  876. out = sys.stdout.getvalue()
  877. sys.stdout.close()
  878. sys.stdout = old_stdout
  879. assert("[learning_curve]" in out)
  880. def test_learning_curve_incremental_learning_not_possible():
  881. X, y = make_classification(n_samples=2, n_features=1, n_informative=1,
  882. n_redundant=0, n_classes=2,
  883. n_clusters_per_class=1, random_state=0)
  884. # The mockup does not have partial_fit()
  885. estimator = MockImprovingEstimator(1)
  886. assert_raises(ValueError, learning_curve, estimator, X, y,
  887. exploit_incremental_learning=True)
  888. def test_learning_curve_incremental_learning():
  889. X, y = make_classification(n_samples=30, n_features=1, n_informative=1,
  890. n_redundant=0, n_classes=2,
  891. n_clusters_per_class=1, random_state=0)
  892. estimator = MockIncrementalImprovingEstimator(20)
  893. for shuffle_train in [False, True]:
  894. train_sizes, train_scores, test_scores = learning_curve(
  895. estimator, X, y, cv=3, exploit_incremental_learning=True,
  896. train_sizes=np.linspace(0.1, 1.0, 10), shuffle=shuffle_train)
  897. assert_array_equal(train_sizes, np.linspace(2, 20, 10))
  898. assert_array_almost_equal(train_scores.mean(axis=1),
  899. np.linspace(1.9, 1.0, 10))
  900. assert_array_almost_equal(test_scores.mean(axis=1),
  901. np.linspace(0.1, 1.0, 10))
  902. def test_learning_curve_incremental_learning_unsupervised():
  903. X, _ = make_classification(n_samples=30, n_features=1, n_informative=1,
  904. n_redundant=0, n_classes=2,
  905. n_clusters_per_class=1, random_state=0)
  906. estimator = MockIncrementalImprovingEstimator(20)
  907. train_sizes, train_scores, test_scores = learning_curve(
  908. estimator, X, y=None, cv=3, exploit_incremental_learning=True,
  909. train_sizes=np.linspace(0.1, 1.0, 10))
  910. assert_array_equal(train_sizes, np.linspace(2, 20, 10))
  911. assert_array_almost_equal(train_scores.mean(axis=1),
  912. np.linspace(1.9, 1.0, 10))
  913. assert_array_almost_equal(test_scores.mean(axis=1),
  914. np.linspace(0.1, 1.0, 10))
  915. # 0.23. warning about tol not having its correct default value.
  916. @pytest.mark.filterwarnings('ignore:max_iter and tol parameters have been')
  917. def test_learning_curve_batch_and_incremental_learning_are_equal():
  918. X, y = make_classification(n_samples=30, n_features=1, n_informative=1,
  919. n_redundant=0, n_classes=2,
  920. n_clusters_per_class=1, random_state=0)
  921. train_sizes = np.linspace(0.2, 1.0, 5)
  922. estimator = PassiveAggressiveClassifier(max_iter=1, tol=None,
  923. shuffle=False)
  924. train_sizes_inc, train_scores_inc, test_scores_inc = \
  925. learning_curve(
  926. estimator, X, y, train_sizes=train_sizes,
  927. cv=3, exploit_incremental_learning=True)
  928. train_sizes_batch, train_scores_batch, test_scores_batch = \
  929. learning_curve(
  930. estimator, X, y, cv=3, train_sizes=train_sizes,
  931. exploit_incremental_learning=False)
  932. assert_array_equal(train_sizes_inc, train_sizes_batch)
  933. assert_array_almost_equal(train_scores_inc.mean(axis=1),
  934. train_scores_batch.mean(axis=1))
  935. assert_array_almost_equal(test_scores_inc.mean(axis=1),
  936. test_scores_batch.mean(axis=1))
  937. def test_learning_curve_n_sample_range_out_of_bounds():
  938. X, y = make_classification(n_samples=30, n_features=1, n_informative=1,
  939. n_redundant=0, n_classes=2,
  940. n_clusters_per_class=1, random_state=0)
  941. estimator = MockImprovingEstimator(20)
  942. assert_raises(ValueError, learning_curve, estimator, X, y, cv=3,
  943. train_sizes=[0, 1])
  944. assert_raises(ValueError, learning_curve, estimator, X, y, cv=3,
  945. train_sizes=[0.0, 1.0])
  946. assert_raises(ValueError, learning_curve, estimator, X, y, cv=3,
  947. train_sizes=[0.1, 1.1])
  948. assert_raises(ValueError, learning_curve, estimator, X, y, cv=3,
  949. train_sizes=[0, 20])
  950. assert_raises(ValueError, learning_curve, estimator, X, y, cv=3,
  951. train_sizes=[1, 21])
  952. def test_learning_curve_remove_duplicate_sample_sizes():
  953. X, y = make_classification(n_samples=3, n_features=1, n_informative=1,
  954. n_redundant=0, n_classes=2,
  955. n_clusters_per_class=1, random_state=0)
  956. estimator = MockImprovingEstimator(2)
  957. train_sizes, _, _ = assert_warns(
  958. RuntimeWarning, learning_curve, estimator, X, y, cv=3,
  959. train_sizes=np.linspace(0.33, 1.0, 3))
  960. assert_array_equal(train_sizes, [1, 2])
  961. def test_learning_curve_with_boolean_indices():
  962. X, y = make_classification(n_samples=30, n_features=1, n_informative=1,
  963. n_redundant=0, n_classes=2,
  964. n_clusters_per_class=1, random_state=0)
  965. estimator = MockImprovingEstimator(20)
  966. cv = KFold(n_splits=3)
  967. train_sizes, train_scores, test_scores = learning_curve(
  968. estimator, X, y, cv=cv, train_sizes=np.linspace(0.1, 1.0, 10))
  969. assert_array_equal(train_sizes, np.linspace(2, 20, 10))
  970. assert_array_almost_equal(train_scores.mean(axis=1),
  971. np.linspace(1.9, 1.0, 10))
  972. assert_array_almost_equal(test_scores.mean(axis=1),
  973. np.linspace(0.1, 1.0, 10))
  974. # 0.23. warning about tol not having its correct default value.
  975. @pytest.mark.filterwarnings('ignore:max_iter and tol parameters have been')
  976. def test_learning_curve_with_shuffle():
  977. # Following test case was designed this way to verify the code
  978. # changes made in pull request: #7506.
  979. X = np.array([[1, 2], [3, 4], [5, 6], [7, 8], [11, 12], [13, 14], [15, 16],
  980. [17, 18], [19, 20], [7, 8], [9, 10], [11, 12], [13, 14],
  981. [15, 16], [17, 18]])
  982. y = np.array([1, 1, 1, 2, 3, 4, 1, 1, 2, 3, 4, 1, 2, 3, 4])
  983. groups = np.array([1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 4, 4, 4, 4])
  984. # Splits on these groups fail without shuffle as the first iteration
  985. # of the learning curve doesn't contain label 4 in the training set.
  986. estimator = PassiveAggressiveClassifier(max_iter=5, tol=None,
  987. shuffle=False)
  988. cv = GroupKFold(n_splits=2)
  989. train_sizes_batch, train_scores_batch, test_scores_batch = learning_curve(
  990. estimator, X, y, cv=cv, n_jobs=1, train_sizes=np.linspace(0.3, 1.0, 3),
  991. groups=groups, shuffle=True, random_state=2)
  992. assert_array_almost_equal(train_scores_batch.mean(axis=1),
  993. np.array([0.75, 0.3, 0.36111111]))
  994. assert_array_almost_equal(test_scores_batch.mean(axis=1),
  995. np.array([0.36111111, 0.25, 0.25]))
  996. assert_raises(ValueError, learning_curve, estimator, X, y, cv=cv, n_jobs=1,
  997. train_sizes=np.linspace(0.3, 1.0, 3), groups=groups,
  998. error_score='raise')
  999. train_sizes_inc, train_scores_inc, test_scores_inc = learning_curve(
  1000. estimator, X, y, cv=cv, n_jobs=1, train_sizes=np.linspace(0.3, 1.0, 3),
  1001. groups=groups, shuffle=True, random_state=2,
  1002. exploit_incremental_learning=True)
  1003. assert_array_almost_equal(train_scores_inc.mean(axis=1),
  1004. train_scores_batch.mean(axis=1))
  1005. assert_array_almost_equal(test_scores_inc.mean(axis=1),
  1006. test_scores_batch.mean(axis=1))
  1007. def test_validation_curve():
  1008. X, y = make_classification(n_samples=2, n_features=1, n_informative=1,
  1009. n_redundant=0, n_classes=2,
  1010. n_clusters_per_class=1, random_state=0)
  1011. param_range = np.linspace(0, 1, 10)
  1012. with warnings.catch_warnings(record=True) as w:
  1013. train_scores, test_scores = validation_curve(
  1014. MockEstimatorWithParameter(), X, y, param_name="param",
  1015. param_range=param_range, cv=2
  1016. )
  1017. if len(w) > 0:
  1018. raise RuntimeError("Unexpected warning: %r" % w[0].message)
  1019. assert_array_almost_equal(train_scores.mean(axis=1), param_range)
  1020. assert_array_almost_equal(test_scores.mean(axis=1), 1 - param_range)
  1021. def test_validation_curve_clone_estimator():
  1022. X, y = make_classification(n_samples=2, n_features=1, n_informative=1,
  1023. n_redundant=0, n_classes=2,
  1024. n_clusters_per_class=1, random_state=0)
  1025. param_range = np.linspace(1, 0, 10)
  1026. _, _ = validation_curve(
  1027. MockEstimatorWithSingleFitCallAllowed(), X, y,
  1028. param_name="param", param_range=param_range, cv=2
  1029. )
  1030. def test_validation_curve_cv_splits_consistency():
  1031. n_samples = 100
  1032. n_splits = 5
  1033. X, y = make_classification(n_samples=100, random_state=0)
  1034. scores1 = validation_curve(SVC(kernel='linear', random_state=0), X, y,
  1035. 'C', [0.1, 0.1, 0.2, 0.2],
  1036. cv=OneTimeSplitter(n_splits=n_splits,
  1037. n_samples=n_samples))
  1038. # The OneTimeSplitter is a non-re-entrant cv splitter. Unless, the
  1039. # `split` is called for each parameter, the following should produce
  1040. # identical results for param setting 1 and param setting 2 as both have
  1041. # the same C value.
  1042. assert_array_almost_equal(*np.vsplit(np.hstack(scores1)[(0, 2, 1, 3), :],
  1043. 2))
  1044. scores2 = validation_curve(SVC(kernel='linear', random_state=0), X, y,
  1045. 'C', [0.1, 0.1, 0.2, 0.2],
  1046. cv=KFold(n_splits=n_splits, shuffle=True))
  1047. # For scores2, compare the 1st and 2nd parameter's scores
  1048. # (Since the C value for 1st two param setting is 0.1, they must be
  1049. # consistent unless the train test folds differ between the param settings)
  1050. assert_array_almost_equal(*np.vsplit(np.hstack(scores2)[(0, 2, 1, 3), :],
  1051. 2))
  1052. scores3 = validation_curve(SVC(kernel='linear', random_state=0), X, y,
  1053. 'C', [0.1, 0.1, 0.2, 0.2],
  1054. cv=KFold(n_splits=n_splits))
  1055. # OneTimeSplitter is basically unshuffled KFold(n_splits=5). Sanity check.
  1056. assert_array_almost_equal(np.array(scores3), np.array(scores1))
  1057. def test_check_is_permutation():
  1058. rng = np.random.RandomState(0)
  1059. p = np.arange(100)
  1060. rng.shuffle(p)
  1061. assert _check_is_permutation(p, 100)
  1062. assert_false(_check_is_permutation(np.delete(p, 23), 100))
  1063. p[0] = 23
  1064. assert_false(_check_is_permutation(p, 100))
  1065. # Check if the additional duplicate indices are caught
  1066. assert_false(_check_is_permutation(np.hstack((p, 0)), 100))
  1067. def test_cross_val_predict_sparse_prediction():
  1068. # check that cross_val_predict gives same result for sparse and dense input
  1069. X, y = make_multilabel_classification(n_classes=2, n_labels=1,
  1070. allow_unlabeled=False,
  1071. return_indicator=True,
  1072. random_state=1)
  1073. X_sparse = csr_matrix(X)
  1074. y_sparse = csr_matrix(y)
  1075. classif = OneVsRestClassifier(SVC(kernel='linear'))
  1076. preds = cross_val_predict(classif, X, y, cv=10)
  1077. preds_sparse = cross_val_predict(classif, X_sparse, y_sparse, cv=10)
  1078. preds_sparse = preds_sparse.toarray()
  1079. assert_array_almost_equal(preds_sparse, preds)
  1080. def check_cross_val_predict_with_method(est):
  1081. iris = load_iris()
  1082. X, y = iris.data, iris.target
  1083. X, y = shuffle(X, y, random_state=0)
  1084. classes = len(set(y))
  1085. kfold = KFold()
  1086. methods = ['decision_function', 'predict_proba', 'predict_log_proba']
  1087. for method in methods:
  1088. predictions = cross_val_predict(est, X, y, method=method)
  1089. assert_equal(len(predictions), len(y))
  1090. expected_predictions = np.zeros([len(y), classes])
  1091. func = getattr(est, method)
  1092. # Naive loop (should be same as cross_val_predict):
  1093. for train, test in kfold.split(X, y):
  1094. est.fit(X[train], y[train])
  1095. expected_predictions[test] = func(X[test])
  1096. predictions = cross_val_predict(est, X, y, method=method,
  1097. cv=kfold)
  1098. assert_array_almost_equal(expected_predictions, predictions)
  1099. # Test alternative representations of y
  1100. predictions_y1 = cross_val_predict(est, X, y + 1, method=method,
  1101. cv=kfold)
  1102. assert_array_equal(predictions, predictions_y1)
  1103. predictions_y2 = cross_val_predict(est, X, y - 2, method=method,
  1104. cv=kfold)
  1105. assert_array_equal(predictions, predictions_y2)
  1106. predictions_ystr = cross_val_predict(est, X, y.astype('str'),
  1107. method=method, cv=kfold)
  1108. assert_array_equal(predictions, predictions_ystr)
  1109. @pytest.mark.filterwarnings('ignore: Default solver will be changed') # 0.22
  1110. @pytest.mark.filterwarnings('ignore: Default multi_class will') # 0.22
  1111. @pytest.mark.filterwarnings('ignore: You should specify a value') # 0.22
  1112. def test_cross_val_predict_with_method():
  1113. check_cross_val_predict_with_method(LogisticRegression())
  1114. @pytest.mark.filterwarnings('ignore: max_iter and tol parameters')
  1115. @pytest.mark.filterwarnings('ignore: You should specify a value') # 0.22
  1116. def test_cross_val_predict_method_checking():
  1117. # Regression test for issue #9639. Tests that cross_val_predict does not
  1118. # check estimator methods (e.g. predict_proba) before fitting
  1119. est = SGDClassifier(loss='log', random_state=2)
  1120. check_cross_val_predict_with_method(est)
  1121. @pytest.mark.filterwarnings('ignore: Default solver will be changed') # 0.22
  1122. @pytest.mark.filterwarnings('ignore: Default multi_class will') # 0.22
  1123. @pytest.mark.filterwarnings('ignore: The default of the `iid`')
  1124. @pytest.mark.filterwarnings('ignore: You should specify a value') # 0.22
  1125. def test_gridsearchcv_cross_val_predict_with_method():
  1126. est = GridSearchCV(LogisticRegression(random_state=42),
  1127. {'C': [0.1, 1]},
  1128. cv=2)
  1129. check_cross_val_predict_with_method(est)
  1130. def get_expected_predictions(X, y, cv, classes, est, method):
  1131. expected_predictions = np.zeros([len(y), classes])
  1132. func = getattr(est, method)
  1133. for train, test in cv.split(X, y):
  1134. est.fit(X[train], y[train])
  1135. expected_predictions_ = func(X[test])
  1136. # To avoid 2 dimensional indexing
  1137. if method == 'predict_proba':
  1138. exp_pred_test = np.zeros((len(test), classes))
  1139. else:
  1140. exp_pred_test = np.full((len(test), classes),
  1141. np.finfo(expected_predictions.dtype).min)
  1142. exp_pred_test[:, est.classes_] = expected_predictions_
  1143. expected_predictions[test] = exp_pred_test
  1144. return expected_predictions
  1145. @pytest.mark.filterwarnings('ignore: Default solver will be changed') # 0.22
  1146. @pytest.mark.filterwarnings('ignore: Default multi_class will') # 0.22
  1147. @pytest.mark.filterwarnings('ignore: You should specify a value') # 0.22
  1148. def test_cross_val_predict_class_subset():
  1149. X = np.arange(200).reshape(100, 2)
  1150. y = np.array([x // 10 for x in range(100)])
  1151. classes = 10
  1152. kfold3 = KFold(n_splits=3)
  1153. kfold4 = KFold(n_splits=4)
  1154. le = LabelEncoder()
  1155. methods = ['decision_function', 'predict_proba', 'predict_log_proba']
  1156. for method in methods:
  1157. est = LogisticRegression()
  1158. # Test with n_splits=3
  1159. predictions = cross_val_predict(est, X, y, method=method,
  1160. cv=kfold3)
  1161. # Runs a naive loop (should be same as cross_val_predict):
  1162. expected_predictions = get_expected_predictions(X, y, kfold3, classes,
  1163. est, method)
  1164. assert_array_almost_equal(expected_predictions, predictions)
  1165. # Test with n_splits=4
  1166. predictions = cross_val_predict(est, X, y, method=method,
  1167. cv=kfold4)
  1168. expected_predictions = get_expected_predictions(X, y, kfold4, classes,
  1169. est, method)
  1170. assert_array_almost_equal(expected_predictions, predictions)
  1171. # Testing unordered labels
  1172. y = shuffle(np.repeat(range(10), 10), random_state=0)
  1173. predictions = cross_val_predict(est, X, y, method=method,
  1174. cv=kfold3)
  1175. y = le.fit_transform(y)
  1176. expected_predictions = get_expected_predictions(X, y, kfold3, classes,
  1177. est, method)
  1178. assert_array_almost_equal(expected_predictions, predictions)
  1179. @pytest.mark.filterwarnings('ignore: You should specify a value') # 0.22
  1180. def test_score_memmap():
  1181. # Ensure a scalar score of memmap type is accepted
  1182. iris = load_iris()
  1183. X, y = iris.data, iris.target
  1184. clf = MockClassifier()
  1185. tf = tempfile.NamedTemporaryFile(mode='wb', delete=False)
  1186. tf.write(b'Hello world!!!!!')
  1187. tf.close()
  1188. scores = np.memmap(tf.name, dtype=np.float64)
  1189. score = np.memmap(tf.name, shape=(), mode='r', dtype=np.float64)
  1190. try:
  1191. cross_val_score(clf, X, y, scoring=lambda est, X, y: score)
  1192. # non-scalar should still fail
  1193. assert_raises(ValueError, cross_val_score, clf, X, y,
  1194. scoring=lambda est, X, y: scores)
  1195. finally:
  1196. # Best effort to release the mmap file handles before deleting the
  1197. # backing file under Windows
  1198. scores, score = None, None
  1199. for _ in range(3):
  1200. try:
  1201. os.unlink(tf.name)
  1202. break
  1203. except WindowsError:
  1204. sleep(1.)
  1205. @pytest.mark.filterwarnings('ignore: Using or importing the ABCs from')
  1206. @pytest.mark.filterwarnings('ignore: You should specify a value') # 0.22
  1207. def test_permutation_test_score_pandas():
  1208. # check permutation_test_score doesn't destroy pandas dataframe
  1209. types = [(MockDataFrame, MockDataFrame)]
  1210. try:
  1211. from pandas import Series, DataFrame
  1212. types.append((Series, DataFrame))
  1213. except ImportError:
  1214. pass
  1215. for TargetType, InputFeatureType in types:
  1216. # X dataframe, y series
  1217. iris = load_iris()
  1218. X, y = iris.data, iris.target
  1219. X_df, y_ser = InputFeatureType(X), TargetType(y)
  1220. check_df = lambda x: isinstance(x, InputFeatureType)
  1221. check_series = lambda x: isinstance(x, TargetType)
  1222. clf = CheckingClassifier(check_X=check_df, check_y=check_series)
  1223. permutation_test_score(clf, X_df, y_ser)
  1224. def test_fit_and_score():
  1225. # Create a failing classifier to deliberately fail
  1226. failing_clf = FailingClassifier(FailingClassifier.FAILING_PARAMETER)
  1227. # dummy X data
  1228. X = np.arange(1, 10)
  1229. y = np.ones(9)
  1230. fit_and_score_args = [failing_clf, X, None, dict(), None, None, 0,
  1231. None, None]
  1232. # passing error score to trigger the warning message
  1233. fit_and_score_kwargs = {'error_score': 0}
  1234. # check if the warning message type is as expected
  1235. assert_warns(FitFailedWarning, _fit_and_score, *fit_and_score_args,
  1236. **fit_and_score_kwargs)
  1237. # since we're using FailingClassfier, our error will be the following
  1238. error_message = "ValueError: Failing classifier failed as required"
  1239. # the warning message we're expecting to see
  1240. warning_message = ("Estimator fit failed. The score on this train-test "
  1241. "partition for these parameters will be set to %f. "
  1242. "Details: \n%s" % (fit_and_score_kwargs['error_score'],
  1243. error_message))
  1244. # check if the same warning is triggered
  1245. assert_warns_message(FitFailedWarning, warning_message, _fit_and_score,
  1246. *fit_and_score_args, **fit_and_score_kwargs)
  1247. # check if warning was raised, with default error_score argument
  1248. warning_message = ("From version 0.22, errors during fit will result "
  1249. "in a cross validation score of NaN by default. Use "
  1250. "error_score='raise' if you want an exception "
  1251. "raised or error_score=np.nan to adopt the "
  1252. "behavior from version 0.22.")
  1253. with pytest.raises(ValueError):
  1254. assert_warns_message(FutureWarning, warning_message, _fit_and_score,
  1255. *fit_and_score_args)
  1256. fit_and_score_kwargs = {'error_score': 'raise'}
  1257. # check if exception was raised, with default error_score='raise'
  1258. assert_raise_message(ValueError, "Failing classifier failed as required",
  1259. _fit_and_score, *fit_and_score_args,
  1260. **fit_and_score_kwargs)
  1261. # check that functions upstream pass error_score param to _fit_and_score
  1262. error_message = ("error_score must be the string 'raise' or a"
  1263. " numeric value. (Hint: if using 'raise', please"
  1264. " make sure that it has been spelled correctly.)")
  1265. assert_raise_message(ValueError, error_message, cross_validate,
  1266. failing_clf, X, cv=3, error_score='unvalid-string')
  1267. assert_raise_message(ValueError, error_message, cross_val_score,
  1268. failing_clf, X, cv=3, error_score='unvalid-string')
  1269. assert_raise_message(ValueError, error_message, learning_curve,
  1270. failing_clf, X, y, cv=3, error_score='unvalid-string')
  1271. assert_raise_message(ValueError, error_message, validation_curve,
  1272. failing_clf, X, y, 'parameter',
  1273. [FailingClassifier.FAILING_PARAMETER], cv=3,
  1274. error_score='unvalid-string')
  1275. assert_equal(failing_clf.score(), 0.) # FailingClassifier coverage