diff --git a/doc/modules/linear_model.rst b/doc/modules/linear_model.rst index f54860c7d03fc..1ba890f52bcf3 100644 --- a/doc/modules/linear_model.rst +++ b/doc/modules/linear_model.rst @@ -184,7 +184,7 @@ for another implementation:: >>> clf = linear_model.Lasso(alpha = 0.1) >>> clf.fit([[0, 0], [1, 1]], [0, 1]) Lasso(alpha=0.1, copy_X=True, fit_intercept=True, max_iter=1000, - normalize=False, positive=False, precompute='auto', tol=0.0001, + normalize=False, positive=False, precompute=False, tol=0.0001, warm_start=False) >>> clf.predict([[1, 1]]) array([ 0.8]) diff --git a/doc/tutorial/statistical_inference/model_selection.rst b/doc/tutorial/statistical_inference/model_selection.rst index 18293d707f505..f877c5919139e 100644 --- a/doc/tutorial/statistical_inference/model_selection.rst +++ b/doc/tutorial/statistical_inference/model_selection.rst @@ -196,7 +196,7 @@ automatically by cross-validation:: >>> lasso.fit(X_diabetes, y_diabetes) LassoCV(alphas=None, copy_X=True, cv=None, eps=0.001, fit_intercept=True, max_iter=1000, n_alphas=100, n_jobs=1, normalize=False, positive=False, - precompute='auto', tol=0.0001, verbose=False) + precompute=False, tol=0.0001, verbose=False) >>> # The estimator chose automatically its lambda: >>> lasso.alpha_ # doctest: +ELLIPSIS 0.01229... diff --git a/doc/tutorial/statistical_inference/supervised_learning.rst b/doc/tutorial/statistical_inference/supervised_learning.rst index 66fddfee35edd..5612ace25f397 100644 --- a/doc/tutorial/statistical_inference/supervised_learning.rst +++ b/doc/tutorial/statistical_inference/supervised_learning.rst @@ -327,7 +327,7 @@ application of Occam's razor: `prefer simpler models`. >>> regr.alpha = best_alpha >>> regr.fit(diabetes_X_train, diabetes_y_train) Lasso(alpha=0.025118864315095794, copy_X=True, fit_intercept=True, - max_iter=1000, normalize=False, positive=False, precompute='auto', + max_iter=1000, normalize=False, positive=False, precompute=False, tol=0.0001, warm_start=False) >>> print(regr.coef_) [ 0. -212.43764548 517.19478111 313.77959962 -160.8303982 -0. diff --git a/doc/whats_new.rst b/doc/whats_new.rst index a0a49713488c3..b82465cbea51e 100644 --- a/doc/whats_new.rst +++ b/doc/whats_new.rst @@ -291,6 +291,13 @@ API changes summary Previously it was broken for input of non-int dtype and the weighted array that was returned was wrong. By `Manoj Kumar`_. + - Change default value of precompute in :class:`ElasticNet` + :class:`ElasticNetCV`, :class:`Lasso` and :class:`LassoCV` from "auto" + to False. Setting precompute to "auto" was found to be slower since + the computation of the Gram matrix is computationally expensive and + outweighs the benefit of fitting the Gram. + By `Manoj Kumar`_. + .. _changes_0_14: 0.14 diff --git a/sklearn/linear_model/coordinate_descent.py b/sklearn/linear_model/coordinate_descent.py index 89fbc093e4edb..f551c8b0168ea 100644 --- a/sklearn/linear_model/coordinate_descent.py +++ b/sklearn/linear_model/coordinate_descent.py @@ -467,12 +467,19 @@ def enet_path(X, y, l1_ratio=0.5, eps=1e-3, n_alphas=100, alphas=None, coef_, l1_reg, l2_reg, X.data, X.indices, X.indptr, y, X_sparse_scaling, max_iter, tol, positive) - elif not multi_output: + elif multi_output: + model = cd_fast.enet_coordinate_descent_multi_task( + coef_, l1_reg, l2_reg, X, y, max_iter, tol) + elif isinstance(precompute, np.ndarray): + model = cd_fast.enet_coordinate_descent_gram( + coef_, l1_reg, l2_reg, precompute, Xy, y, max_iter, + tol, positive) + elif precompute is False: model = cd_fast.enet_coordinate_descent( coef_, l1_reg, l2_reg, X, y, max_iter, tol, positive) else: - model = cd_fast.enet_coordinate_descent_multi_task( - coef_, l1_reg, l2_reg, X, y, max_iter, tol) + raise ValueError("Precompute should be one of True, False, " + "'auto' or array-like") coef_, dual_gap_, eps_ = model coefs[..., i] = coef_ dual_gaps[i] = dual_gap_ @@ -615,7 +622,7 @@ class ElasticNet(LinearModel, RegressorMixin): path = staticmethod(enet_path) def __init__(self, alpha=1.0, l1_ratio=0.5, fit_intercept=True, - normalize=False, precompute='auto', max_iter=1000, + normalize=False, precompute=False, max_iter=1000, copy_X=True, tol=1e-4, warm_start=False, positive=False): self.alpha = alpha self.l1_ratio = l1_ratio @@ -802,7 +809,7 @@ class Lasso(ElasticNet): >>> clf = linear_model.Lasso(alpha=0.1) >>> clf.fit([[0,0], [1, 1], [2, 2]], [0, 1, 2]) Lasso(alpha=0.1, copy_X=True, fit_intercept=True, max_iter=1000, - normalize=False, positive=False, precompute='auto', tol=0.0001, + normalize=False, positive=False, precompute=False, tol=0.0001, warm_start=False) >>> print(clf.coef_) [ 0.85 0. ] @@ -828,7 +835,7 @@ class Lasso(ElasticNet): path = staticmethod(enet_path) def __init__(self, alpha=1.0, fit_intercept=True, normalize=False, - precompute='auto', copy_X=True, max_iter=1000, + precompute=False, copy_X=True, max_iter=1000, tol=1e-4, warm_start=False, positive=False): super(Lasso, self).__init__( alpha=alpha, l1_ratio=1.0, fit_intercept=fit_intercept, @@ -889,7 +896,13 @@ def _path_residuals(X, y, train, test, path, path_params, alphas=None, y_test = y[test] fit_intercept = path_params['fit_intercept'] normalize = path_params['normalize'] - precompute = path_params['precompute'] + + if y.ndim == 1: + precompute = path_params['precompute'] + else: + # No Gram variant of multi-task exists right now. + # Fall back to default enet_multitask + precompute = False X_train, y_train, X_mean, y_mean, X_std, precompute, Xy = \ _pre_fit(X_train, y_train, None, precompute, normalize, fit_intercept, @@ -1218,7 +1231,7 @@ class LassoCV(LinearModelCV, RegressorMixin): path = staticmethod(lasso_path) def __init__(self, eps=1e-3, n_alphas=100, alphas=None, fit_intercept=True, - normalize=False, precompute='auto', max_iter=1000, tol=1e-4, + normalize=False, precompute=False, max_iter=1000, tol=1e-4, copy_X=True, cv=None, verbose=False, n_jobs=1, positive=False): super(LassoCV, self).__init__( @@ -1345,7 +1358,7 @@ class ElasticNetCV(LinearModelCV, RegressorMixin): path = staticmethod(enet_path) def __init__(self, l1_ratio=0.5, eps=1e-3, n_alphas=100, alphas=None, - fit_intercept=True, normalize=False, precompute='auto', + fit_intercept=True, normalize=False, precompute=False, max_iter=1000, tol=1e-4, cv=None, copy_X=True, verbose=0, n_jobs=1, positive=False): self.l1_ratio = l1_ratio @@ -1638,11 +1651,6 @@ class MultiTaskElasticNetCV(LinearModelCV, RegressorMixin): List of alphas where to compute the models. If not provided, set automatically. - precompute : True | False | 'auto' | array-like - Whether to use a precomputed Gram matrix to speed up - calculations. If set to ``'auto'`` let us decide. The Gram - matrix can also be passed as argument. - n_alphas : int, optional Number of alphas along the regularization path @@ -1716,8 +1724,7 @@ class MultiTaskElasticNetCV(LinearModelCV, RegressorMixin): ... #doctest: +NORMALIZE_WHITESPACE MultiTaskElasticNetCV(alphas=None, copy_X=True, cv=None, eps=0.001, fit_intercept=True, l1_ratio=0.5, max_iter=1000, n_alphas=100, - n_jobs=1, normalize=False, precompute='auto', tol=0.0001, - verbose=0) + n_jobs=1, normalize=False, tol=0.0001, verbose=0) >>> print(clf.coef_) [[ 0.52875032 0.46958558] [ 0.52875032 0.46958558]] @@ -1740,7 +1747,7 @@ class MultiTaskElasticNetCV(LinearModelCV, RegressorMixin): path = staticmethod(enet_path) def __init__(self, l1_ratio=0.5, eps=1e-3, n_alphas=100, alphas=None, - fit_intercept=True, normalize=False, precompute='auto', + fit_intercept=True, normalize=False, max_iter=1000, tol=1e-4, cv=None, copy_X=True, verbose=0, n_jobs=1): self.l1_ratio = l1_ratio @@ -1749,7 +1756,6 @@ def __init__(self, l1_ratio=0.5, eps=1e-3, n_alphas=100, alphas=None, self.alphas = alphas self.fit_intercept = fit_intercept self.normalize = normalize - self.precompute = precompute self.max_iter = max_iter self.tol = tol self.cv = cv @@ -1781,11 +1787,6 @@ class MultiTaskLassoCV(LinearModelCV, RegressorMixin): List of alphas where to compute the models. If not provided, set automaticlly. - precompute : True | False | 'auto' | array-like - Whether to use a precomputed Gram matrix to speed up - calculations. If set to ``'auto'`` let us decide. The Gram - matrix can also be passed as argument. - n_alphas : int, optional Number of alphas along the regularization path @@ -1856,10 +1857,10 @@ class MultiTaskLassoCV(LinearModelCV, RegressorMixin): path = staticmethod(lasso_path) def __init__(self, eps=1e-3, n_alphas=100, alphas=None, fit_intercept=True, - normalize=False, precompute='auto', max_iter=1000, tol=1e-4, - copy_X=True, cv=None, verbose=False, n_jobs=1): + normalize=False, max_iter=1000, tol=1e-4, copy_X=True, + cv=None, verbose=False, n_jobs=1): super(MultiTaskLassoCV, self).__init__( eps=eps, n_alphas=n_alphas, alphas=alphas, fit_intercept=fit_intercept, normalize=normalize, - precompute=precompute, max_iter=max_iter, tol=tol, copy_X=copy_X, + max_iter=max_iter, tol=tol, copy_X=copy_X, cv=cv, verbose=verbose, n_jobs=n_jobs) diff --git a/sklearn/linear_model/tests/test_coordinate_descent.py b/sklearn/linear_model/tests/test_coordinate_descent.py index 08f1faa60ec6e..67e5cba8eec9b 100644 --- a/sklearn/linear_model/tests/test_coordinate_descent.py +++ b/sklearn/linear_model/tests/test_coordinate_descent.py @@ -460,6 +460,13 @@ def test_sparse_input_dtype_enet_and_lassocv(): assert_almost_equal(clf.coef_, clf1.coef_, decimal=6) +def test_precompute_invalid_argument(): + X, y, _, _ = build_dataset() + for clf in [ElasticNetCV(precompute="invalid"), + LassoCV(precompute="invalid")]: + assert_raises(ValueError, clf.fit, X, y) + + if __name__ == '__main__': import nose nose.runmodule()