scikit-learn/sklearn/linear_model/_omp.py

915 lines
32 KiB
Python
Raw Normal View History

2011-08-03 22:59:30 +08:00
"""Orthogonal matching pursuit algorithms
2011-07-25 18:57:42 +08:00
"""
# Author: Vlad Niculae
#
# License: BSD 3 clause
2011-07-25 18:57:42 +08:00
import warnings
from math import sqrt
2011-08-02 05:40:05 +08:00
2011-07-25 18:57:42 +08:00
import numpy as np
from scipy import linalg
from scipy.linalg.lapack import get_lapack_funcs
from joblib import Parallel
2011-07-25 18:57:42 +08:00
from ._base import LinearModel, _pre_fit
2019-02-24 05:54:41 +08:00
from ..base import RegressorMixin, MultiOutputMixin
2020-03-11 07:01:51 +08:00
from ..utils import as_float_array, check_array
from ..utils.validation import _deprecate_positional_args
from ..utils.fixes import delayed
Main Commits - Major -------------------- * ENH Reogranize classes/fn from grid_search into search.py * ENH Reogranize classes/fn from cross_validation into split.py * ENH Reogranize cls/fn from cross_validation/learning_curve into validate.py * MAINT Merge _check_cv into check_cv inside the model_selection module * MAINT Update all the imports to point to the model_selection module * FIX use iter_cv to iterate throught the new style/old style cv objs * TST Add tests for the new model_selection members * ENH Wrap the old-style cv obj/iterables instead of using iter_cv * ENH Use scipy's binomial coefficient function comb for calucation of nCk * ENH Few enhancements to the split module * ENH Improve check_cv input validation and docstring * MAINT _get_test_folds(X, y, labels) --> _get_test_folds(labels) * TST if 1d arrays for X introduce any errors * ENH use 1d X arrays for all tests; * ENH X_10 --> X (global var) Minor ----- * ENH _PartitionIterator --> _BaseCrossValidator; * ENH CVIterator --> CVIterableWrapper * TST Import the old SKF locally * FIX/TST Clean up the split module's tests. * DOC Improve documentation of the cv parameter * COSMIT consistently hyphenate cross-validation/cross-validator * TST Calculate n_samples from X * COSMIT Use separate lines for each import. * COSMIT cross_validation_generator --> cross_validator Commits merged manually ----------------------- * FIX Document the random_state attribute in RandomSearchCV * MAINT Use check_cv instead of _check_cv * ENH refactor OVO decision function, use it in SVC for sklearn-like decision_function shape * FIX avoid memory cost when sampling from large parameter grids ENH Major to Minor incremental enhancements to the model_selection Squashed commit messages - (For reference) Major ----- * ENH p --> n_labels * FIX *ShuffleSplit: all float/invalid type errors at init and int error at split * FIX make PredefinedSplit accept test_folds in constructor; Cleanup docstrings * ENH+TST KFold: make rng to be generated at every split call for reproducibility * FIX/MAINT KFold: make shuffle a public attr * FIX Make CVIterableWrapper private. * FIX reuse len_cv instead of recalculating it * FIX Prevent adding *SearchCV estimators from the old grid_search module * re-FIX In all_estimators: the sorting to use only the 1st item (name) To avoid collision between the old and the new GridSearch classes. * FIX test_validate.py: Use 2D X (1D X is being detected as a single sample) * MAINT validate.py --> validation.py * MAINT make the submodules private * MAINT Support old cv/gs/lc until 0.19 * FIX/MAINT n_splits --> get_n_splits * FIX/TST test_logistic.py/test_ovr_multinomial_iris: pass predefined folds as an iterable * MAINT expose BaseCrossValidator * Update the model_selection module with changes from master - From #5161 - - MAINT remove redundant p variable - - Add check for sparse prediction in cross_val_predict - From #5201 - DOC improve random_state param doc - From #5190 - LabelKFold and test - From #4583 - LabelShuffleSplit and tests - From #5300 - shuffle the `labels` not the `indxs` in LabelKFold + tests - From #5378 - Make the GridSearchCV docs more accurate. - From #5458 - Remove shuffle from LabelKFold - From #5466(#4270) - Gaussian Process by Jan Metzen - From #4826 - Move custom error / warnings into sklearn.exception Minor ----- * ENH Make the KFold shuffling test stronger * FIX/DOC Use the higher level model_selection module as ref * DOC in check_cv "y : array-like, optional" * DOC a supervised learning problem --> supervised learning problems * DOC cross-validators --> cross-validation strategies * DOC Correct Olivier Grisel's name ;) * MINOR/FIX cv_indices --> kfold * FIX/DOC Align the 'See also' section of the new KFold, LeaveOneOut * TST/FIX imports on separate lines * FIX use __class__ instead of classmethod * TST/FIX import directly from model_selection * COSMIT Relocate the random_state documentation * COSMIT remove pass * MAINT Remove deprecation warnings from old tests * FIX correct import at test_split * FIX/MAINT Move P_sparse, X, y defns to top; rm unused W_sparse, X_sparse * FIX random state to avoid doctest failure * TST n_splits and split wrapping of _CVIterableWrapper * FIX/MAINT Use multilabel indicator matrix directly * TST/DOC clarify why we conflate classes 0 and 1 * DOC add comment that this was taken from BaseEstimator * FIX use of labels is not needed in stratified k fold * Fix cross_validation reference * Fix the labels param doc FIX/DOC/MAINT Addressing the review comments by Arnaud and Andy COSMIT Sort the members alphabetically COSMIT len_cv --> n_splits COSMIT Merge 2 if; FIX Use kwargs DOC Add my name to the authors :D DOC make labels parameter consistent FIX Remove hack for boolean indices; + COSMIT idx --> indices; DOC Add Returns COSMIT preds --> predictions DOC Add Returns and neatly arrange X, y, labels FIX idx(s)/ind(s)--> indice(s) COSMIT Merge if and else to elif COSMIT n --> n_samples COSMIT Use bincount only once COSMIT cls --> class_i / class_i (ith class indices) --> perm_indices_class_i FIX/ENH/TST Addressing the final reviews COSMIT c --> count FIX/TST make check_cv raise ValueError for string cv value TST nested cv (gs inside cross_val_score) works for diff cvs FIX/ENH Raise ValueError when labels is None for label based cvs; TST if labels is being passed correctly to the cv and that the ValueError is being propagated to the cross_val_score/predict and grid search FIX pass labels to cross_val_score FIX use make_classification DOC Add Returns; COSMIT Remove scaffolding TST add a test to check the _build_repr helper REVERT the old GS/RS should also be tested by the common tests. ENH Add a tuple of all/label based CVS FIX raise VE even at get_n_splits if labels is None FIX Fabian's comments PEP8
2015-06-05 03:45:10 +08:00
from ..model_selection import check_cv
2011-07-25 18:57:42 +08:00
2011-08-02 05:40:05 +08:00
premature = """ Orthogonal matching pursuit ended prematurely due to linear
dependence in the dictionary. The requested precision might not have been met.
"""
def _cholesky_omp(X, y, n_nonzero_coefs, tol=None, copy_X=True,
return_path=False):
"""Orthogonal Matching Pursuit step using the Cholesky decomposition.
2011-07-25 18:57:42 +08:00
2013-06-13 16:50:30 +08:00
Parameters
----------
X : ndarray of shape (n_samples, n_features)
2011-07-25 18:57:42 +08:00
Input dictionary. Columns are assumed to have unit norm.
y : ndarray of shape (n_samples,)
Input targets.
2011-07-25 18:57:42 +08:00
2013-07-25 21:42:19 +08:00
n_nonzero_coefs : int
Targeted number of non-zero elements.
2011-07-25 18:57:42 +08:00
tol : float, default=None
2011-07-29 05:09:22 +08:00
Targeted squared error, if not None overrides n_nonzero_coefs.
2011-07-25 18:57:42 +08:00
copy_X : bool, default=True
Whether the design matrix X must be copied by the algorithm. A false
value is only helpful if X is already Fortran-ordered, otherwise a
copy is made anyway.
2011-08-03 21:18:16 +08:00
return_path : bool, default=False
Whether to return every value of the nonzero coefficients along the
forward path. Useful for cross-validation.
2013-07-25 21:42:19 +08:00
Returns
-------
gamma : ndarray of shape (n_nonzero_coefs,)
Non-zero elements of the solution.
2011-07-25 18:57:42 +08:00
idx : ndarray of shape (n_nonzero_coefs,)
2011-07-25 18:57:42 +08:00
Indices of the positions of the elements in gamma within the solution
vector.
2011-07-25 18:57:42 +08:00
coef : ndarray of shape (n_features, n_nonzero_coefs)
The first k values of column k correspond to the coefficient value
for the active features at that step. The lower left triangle contains
garbage. Only returned if ``return_path=True``.
2014-07-21 07:03:46 +08:00
n_active : int
Number of active features at convergence.
2011-07-25 18:57:42 +08:00
"""
if copy_X:
X = X.copy('F')
else: # even if we are allowed to overwrite, still copy it if bad order
X = np.asfortranarray(X)
2011-10-20 23:36:25 +08:00
2011-07-30 05:24:34 +08:00
min_float = np.finfo(X.dtype).eps
nrm2, swap = linalg.get_blas_funcs(('nrm2', 'swap'), (X,))
2011-07-30 06:41:47 +08:00
potrs, = get_lapack_funcs(('potrs',), (X,))
2011-07-30 05:24:34 +08:00
2011-07-25 18:57:42 +08:00
alpha = np.dot(X.T, y)
residual = y
gamma = np.empty(0)
2011-07-30 05:24:34 +08:00
n_active = 0
indices = np.arange(X.shape[1]) # keeping track of swapping
2011-07-25 18:57:42 +08:00
2011-08-24 21:31:07 +08:00
max_features = X.shape[1] if tol is not None else n_nonzero_coefs
L = np.empty((max_features, max_features), dtype=X.dtype)
2015-03-18 09:54:51 +08:00
if return_path:
coefs = np.empty_like(L)
2011-07-30 05:24:34 +08:00
while True:
2011-08-02 23:00:20 +08:00
lam = np.argmax(np.abs(np.dot(X.T, residual)))
if lam < n_active or alpha[lam] ** 2 < min_float:
# atom already selected or inner product too small
warnings.warn(premature, RuntimeWarning, stacklevel=2)
break
2011-07-30 07:00:16 +08:00
if n_active > 0:
# Updates the Cholesky decomposition of X' X
L[n_active, :n_active] = np.dot(X[:, :n_active].T, X[:, lam])
linalg.solve_triangular(L[:n_active, :n_active],
L[n_active, :n_active],
trans=0, lower=1,
overwrite_b=True,
check_finite=False)
v = nrm2(L[n_active, :n_active]) ** 2
Lkk = linalg.norm(X[:, lam]) ** 2 - v
if Lkk <= min_float: # selected atoms are dependent
warnings.warn(premature, RuntimeWarning, stacklevel=2)
break
L[n_active, n_active] = sqrt(Lkk)
else:
L[0, 0] = linalg.norm(X[:, lam])
X.T[n_active], X.T[lam] = swap(X.T[n_active], X.T[lam])
alpha[n_active], alpha[lam] = alpha[lam], alpha[n_active]
indices[n_active], indices[lam] = indices[lam], indices[n_active]
2011-07-30 05:24:34 +08:00
n_active += 1
# solves LL'x = X'y as a composition of two triangular systems
gamma, _ = potrs(L[:n_active, :n_active], alpha[:n_active], lower=True,
2011-07-30 07:00:16 +08:00
overwrite_b=False)
if return_path:
coefs[:n_active, n_active - 1] = gamma
residual = y - np.dot(X[:, :n_active], gamma)
2011-08-24 21:31:07 +08:00
if tol is not None and nrm2(residual) ** 2 <= tol:
2011-07-25 18:57:42 +08:00
break
2011-07-30 05:28:02 +08:00
elif n_active == max_features:
2011-07-25 18:57:42 +08:00
break
if return_path:
2014-07-21 07:03:46 +08:00
return gamma, indices[:n_active], coefs[:, :n_active], n_active
else:
2014-07-21 07:03:46 +08:00
return gamma, indices[:n_active], n_active
2011-07-25 18:57:42 +08:00
2011-08-24 21:31:07 +08:00
def _gram_omp(Gram, Xy, n_nonzero_coefs, tol_0=None, tol=None,
copy_Gram=True, copy_Xy=True, return_path=False):
"""Orthogonal Matching Pursuit step on a precomputed Gram matrix.
2016-02-23 15:40:46 +08:00
This function uses the Cholesky decomposition method.
2011-07-25 18:57:42 +08:00
2013-06-13 16:50:30 +08:00
Parameters
----------
Gram : ndarray of shape (n_features, n_features)
Gram matrix of the input data matrix.
2011-07-25 18:57:42 +08:00
Xy : ndarray of shape (n_features,)
Input targets.
2011-07-25 18:57:42 +08:00
2013-07-25 21:42:19 +08:00
n_nonzero_coefs : int
Targeted number of non-zero elements.
2011-07-25 18:57:42 +08:00
tol_0 : float, default=None
2011-08-24 21:31:07 +08:00
Squared norm of y, required if tol is not None.
2011-07-25 18:57:42 +08:00
tol : float, default=None
2011-07-29 05:09:22 +08:00
Targeted squared error, if not None overrides n_nonzero_coefs.
2011-07-25 18:57:42 +08:00
copy_Gram : bool, default=True
Whether the gram matrix must be copied by the algorithm. A false
value is only helpful if it is already Fortran-ordered, otherwise a
copy is made anyway.
2011-08-03 21:18:16 +08:00
copy_Xy : bool, default=True
Whether the covariance vector Xy must be copied by the algorithm.
If False, it may be overwritten.
2011-08-03 21:18:16 +08:00
return_path : bool, default=False
Whether to return every value of the nonzero coefficients along the
forward path. Useful for cross-validation.
2013-07-25 21:42:19 +08:00
Returns
-------
gamma : ndarray of shape (n_nonzero_coefs,)
Non-zero elements of the solution.
2011-07-25 18:57:42 +08:00
idx : ndarray of shape (n_nonzero_coefs,)
2011-07-25 18:57:42 +08:00
Indices of the positions of the elements in gamma within the solution
vector.
2011-07-25 18:57:42 +08:00
coefs : ndarray of shape (n_features, n_nonzero_coefs)
The first k values of column k correspond to the coefficient value
for the active features at that step. The lower left triangle contains
garbage. Only returned if ``return_path=True``.
2014-07-21 07:03:46 +08:00
n_active : int
Number of active features at convergence.
2011-07-25 18:57:42 +08:00
"""
Gram = Gram.copy('F') if copy_Gram else np.asfortranarray(Gram)
2011-08-03 21:18:16 +08:00
if copy_Xy or not Xy.flags.writeable:
2011-08-03 21:18:16 +08:00
Xy = Xy.copy()
2011-07-25 18:57:42 +08:00
2011-08-03 21:18:16 +08:00
min_float = np.finfo(Gram.dtype).eps
nrm2, swap = linalg.get_blas_funcs(('nrm2', 'swap'), (Gram,))
potrs, = get_lapack_funcs(('potrs',), (Gram,))
2011-07-30 05:24:34 +08:00
indices = np.arange(len(Gram)) # keeping track of swapping
2011-07-25 18:57:42 +08:00
alpha = Xy
2011-08-24 21:31:07 +08:00
tol_curr = tol_0
2011-07-25 18:57:42 +08:00
delta = 0
gamma = np.empty(0)
2011-07-30 05:24:34 +08:00
n_active = 0
2011-07-25 18:57:42 +08:00
2011-08-24 21:31:07 +08:00
max_features = len(Gram) if tol is not None else n_nonzero_coefs
L = np.empty((max_features, max_features), dtype=Gram.dtype)
2011-07-30 05:24:34 +08:00
L[0, 0] = 1.
if return_path:
coefs = np.empty_like(L)
2011-07-30 05:24:34 +08:00
while True:
2011-08-02 23:00:20 +08:00
lam = np.argmax(np.abs(alpha))
2011-08-03 21:18:16 +08:00
if lam < n_active or alpha[lam] ** 2 < min_float:
# selected same atom twice, or inner product too small
2013-11-29 23:40:23 +08:00
warnings.warn(premature, RuntimeWarning, stacklevel=3)
break
2011-07-30 07:00:16 +08:00
if n_active > 0:
2011-08-03 21:18:16 +08:00
L[n_active, :n_active] = Gram[lam, :n_active]
linalg.solve_triangular(L[:n_active, :n_active],
L[n_active, :n_active],
trans=0, lower=1,
overwrite_b=True,
check_finite=False)
v = nrm2(L[n_active, :n_active]) ** 2
Lkk = Gram[lam, lam] - v
if Lkk <= min_float: # selected atoms are dependent
2013-11-29 23:40:23 +08:00
warnings.warn(premature, RuntimeWarning, stacklevel=3)
break
L[n_active, n_active] = sqrt(Lkk)
else:
L[0, 0] = sqrt(Gram[lam, lam])
2011-08-03 21:18:16 +08:00
Gram[n_active], Gram[lam] = swap(Gram[n_active], Gram[lam])
Gram.T[n_active], Gram.T[lam] = swap(Gram.T[n_active], Gram.T[lam])
indices[n_active], indices[lam] = indices[lam], indices[n_active]
2011-08-03 21:18:16 +08:00
Xy[n_active], Xy[lam] = Xy[lam], Xy[n_active]
2011-07-30 05:24:34 +08:00
n_active += 1
# solves LL'x = X'y as a composition of two triangular systems
2011-08-03 21:18:16 +08:00
gamma, _ = potrs(L[:n_active, :n_active], Xy[:n_active], lower=True,
2011-07-30 07:00:16 +08:00
overwrite_b=False)
if return_path:
coefs[:n_active, n_active - 1] = gamma
2011-08-03 21:18:16 +08:00
beta = np.dot(Gram[:, :n_active], gamma)
2011-07-25 18:57:42 +08:00
alpha = Xy - beta
2011-08-24 21:31:07 +08:00
if tol is not None:
tol_curr += delta
2011-08-03 21:18:16 +08:00
delta = np.inner(gamma, beta[:n_active])
2011-08-24 21:31:07 +08:00
tol_curr -= delta
2013-11-29 23:40:23 +08:00
if abs(tol_curr) <= tol:
2011-07-25 18:57:42 +08:00
break
2011-07-30 05:24:34 +08:00
elif n_active == max_features:
2011-07-25 18:57:42 +08:00
break
2011-07-30 05:24:34 +08:00
if return_path:
2014-07-21 07:03:46 +08:00
return gamma, indices[:n_active], coefs[:, :n_active], n_active
else:
2014-07-21 07:03:46 +08:00
return gamma, indices[:n_active], n_active
2011-07-25 18:57:42 +08:00
2013-07-25 23:59:36 +08:00
@_deprecate_positional_args
def orthogonal_mp(X, y, *, n_nonzero_coefs=None, tol=None, precompute=False,
2014-07-21 07:03:46 +08:00
copy_X=True, return_path=False,
return_n_iter=False):
r"""Orthogonal Matching Pursuit (OMP).
2011-07-25 18:57:42 +08:00
Solves n_targets Orthogonal Matching Pursuit problems.
An instance of the problem has the form:
2011-07-29 05:09:22 +08:00
When parametrized by the number of non-zero coefficients using
`n_nonzero_coefs`:
argmin ||y - X\gamma||^2 subject to ||\gamma||_0 <= n_{nonzero coefs}
2011-07-25 18:57:42 +08:00
2011-08-24 21:31:07 +08:00
When parametrized by error using the parameter `tol`:
argmin ||\gamma||_0 subject to ||y - X\gamma||^2 <= tol
2011-07-25 18:57:42 +08:00
2015-06-03 12:24:04 +08:00
Read more in the :ref:`User Guide <omp>`.
2011-07-25 18:57:42 +08:00
Parameters
----------
X : ndarray of shape (n_samples, n_features)
2011-08-03 22:59:30 +08:00
Input data. Columns are assumed to have unit norm.
2011-07-25 18:57:42 +08:00
y : ndarray of shape (n_samples,) or (n_samples, n_targets)
Input targets.
2011-07-25 18:57:42 +08:00
n_nonzero_coefs : int, default=None
Desired number of non-zero entries in the solution. If None (by
default) this value is set to 10% of n_features.
2011-07-25 18:57:42 +08:00
tol : float, default=None
2011-07-29 05:09:22 +08:00
Maximum norm of the residual. If not None, overrides n_nonzero_coefs.
2011-07-25 18:57:42 +08:00
precompute : 'auto' or bool, default=False
2011-07-25 18:57:42 +08:00
Whether to perform precomputations. Improves performance when n_targets
or n_samples is very large.
copy_X : bool, default=True
Whether the design matrix X must be copied by the algorithm. A false
value is only helpful if X is already Fortran-ordered, otherwise a
copy is made anyway.
2011-08-03 21:18:16 +08:00
return_path : bool, default=False
Whether to return every value of the nonzero coefficients along the
forward path. Useful for cross-validation.
return_n_iter : bool, default=False
2014-07-21 07:03:46 +08:00
Whether or not to return the number of iterations.
2011-07-25 18:57:42 +08:00
Returns
-------
coef : ndarray of shape (n_features,) or (n_features, n_targets)
Coefficients of the OMP solution. If `return_path=True`, this contains
the whole coefficient path. In this case its shape is
(n_features, n_features) or (n_features, n_targets, n_features) and
iterating over the last axis yields coefficients in increasing order
of active features.
2011-07-25 18:57:42 +08:00
2014-07-21 07:03:46 +08:00
n_iters : array-like or int
Number of active features across every target. Returned only if
`return_n_iter` is set to True.
See Also
2011-07-25 18:57:42 +08:00
--------
2011-08-03 22:59:30 +08:00
OrthogonalMatchingPursuit
2011-07-25 18:57:42 +08:00
orthogonal_mp_gram
lars_path
sklearn.decomposition.sparse_encode
2011-07-25 18:57:42 +08:00
2011-08-03 22:59:30 +08:00
Notes
-----
Orthogonal matching pursuit was introduced in S. Mallat, Z. Zhang,
2011-08-03 22:59:30 +08:00
Matching pursuits with time-frequency dictionaries, IEEE Transactions on
Signal Processing, Vol. 41, No. 12. (December 1993), pp. 3397-3415.
(http://blanche.polytechnique.fr/~mallat/papiers/MallatPursuit93.pdf)
This implementation is based on Rubinstein, R., Zibulevsky, M. and Elad,
M., Efficient Implementation of the K-SVD Algorithm using Batch Orthogonal
Matching Pursuit Technical Report - CS Technion, April 2008.
https://www.cs.technion.ac.il/~ronrubin/Publications/KSVD-OMP-v2.pdf
2011-08-03 22:59:30 +08:00
2011-07-25 18:57:42 +08:00
"""
X = check_array(X, order='F', copy=copy_X)
copy_X = False
2011-07-25 18:57:42 +08:00
if y.ndim == 1:
y = y.reshape(-1, 1)
y = check_array(y)
2011-08-04 00:27:34 +08:00
if y.shape[1] > 1: # subsequent targets will be affected
copy_X = True
2012-12-22 20:02:50 +08:00
if n_nonzero_coefs is None and tol is None:
# default for n_nonzero_coefs is 0.1 * n_features
# but at least one.
n_nonzero_coefs = max(int(0.1 * X.shape[1]), 1)
2011-08-24 21:31:07 +08:00
if tol is not None and tol < 0:
2011-07-25 18:57:42 +08:00
raise ValueError("Epsilon cannot be negative")
2011-08-24 21:31:07 +08:00
if tol is None and n_nonzero_coefs <= 0:
2011-07-25 18:57:42 +08:00
raise ValueError("The number of atoms must be positive")
2011-08-24 21:31:07 +08:00
if tol is None and n_nonzero_coefs > X.shape[1]:
2012-08-26 03:54:30 +08:00
raise ValueError("The number of atoms cannot be more than the number "
"of features")
2013-07-26 00:49:02 +08:00
if precompute == 'auto':
precompute = X.shape[0] > X.shape[1]
if precompute:
2011-07-25 18:57:42 +08:00
G = np.dot(X.T, X)
G = np.asfortranarray(G)
2011-07-25 18:57:42 +08:00
Xy = np.dot(X.T, y)
2011-08-24 21:31:07 +08:00
if tol is not None:
2011-07-25 18:57:42 +08:00
norms_squared = np.sum((y ** 2), axis=0)
else:
norms_squared = None
return orthogonal_mp_gram(G, Xy, n_nonzero_coefs=n_nonzero_coefs,
tol=tol, norms_squared=norms_squared,
2015-05-20 17:38:38 +08:00
copy_Gram=copy_X, copy_Xy=False,
return_path=return_path)
2011-07-25 18:57:42 +08:00
if return_path:
coef = np.zeros((X.shape[1], y.shape[1], X.shape[1]))
else:
coef = np.zeros((X.shape[1], y.shape[1]))
2014-07-21 07:03:46 +08:00
n_iters = []
2013-07-26 20:11:39 +08:00
for k in range(y.shape[1]):
2014-07-21 07:03:46 +08:00
out = _cholesky_omp(
X, y[:, k], n_nonzero_coefs, tol,
2015-03-18 09:54:51 +08:00
copy_X=copy_X, return_path=return_path)
if return_path:
2014-07-21 07:03:46 +08:00
_, idx, coefs, n_iter = out
coef = coef[:, :, :len(idx)]
for n_active, x in enumerate(coefs.T):
coef[idx[:n_active + 1], k, n_active] = x[:n_active + 1]
else:
2014-07-21 07:03:46 +08:00
x, idx, n_iter = out
coef[idx, k] = x
2014-07-21 07:03:46 +08:00
n_iters.append(n_iter)
if y.shape[1] == 1:
n_iters = n_iters[0]
if return_n_iter:
return np.squeeze(coef), n_iters
else:
return np.squeeze(coef)
2011-07-25 18:57:42 +08:00
@_deprecate_positional_args
def orthogonal_mp_gram(Gram, Xy, *, n_nonzero_coefs=None, tol=None,
norms_squared=None, copy_Gram=True,
2014-07-21 07:03:46 +08:00
copy_Xy=True, return_path=False,
return_n_iter=False):
"""Gram Orthogonal Matching Pursuit (OMP).
2011-07-25 18:57:42 +08:00
Solves n_targets Orthogonal Matching Pursuit problems using only
2011-08-03 22:01:53 +08:00
the Gram matrix X.T * X and the product X.T * y.
2011-07-25 18:57:42 +08:00
2015-06-03 12:24:04 +08:00
Read more in the :ref:`User Guide <omp>`.
2011-07-25 18:57:42 +08:00
Parameters
----------
Gram : ndarray of shape (n_features, n_features)
Gram matrix of the input data: X.T * X.
2011-07-25 18:57:42 +08:00
Xy : ndarray of shape (n_features,) or (n_features, n_targets)
Input targets multiplied by X: X.T * y.
2011-07-25 18:57:42 +08:00
n_nonzero_coefs : int, default=None
Desired number of non-zero entries in the solution. If None (by
default) this value is set to 10% of n_features.
2011-07-25 18:57:42 +08:00
tol : float, default=None
2011-07-29 05:09:22 +08:00
Maximum norm of the residual. If not None, overrides n_nonzero_coefs.
2011-07-25 18:57:42 +08:00
norms_squared : array-like of shape (n_targets,), default=None
2011-08-24 21:31:07 +08:00
Squared L2 norms of the lines of y. Required if tol is not None.
2011-07-25 18:57:42 +08:00
copy_Gram : bool, default=True
Whether the gram matrix must be copied by the algorithm. A false
value is only helpful if it is already Fortran-ordered, otherwise a
copy is made anyway.
2011-08-03 21:18:16 +08:00
copy_Xy : bool, default=True
Whether the covariance vector Xy must be copied by the algorithm.
If False, it may be overwritten.
2011-08-03 21:18:16 +08:00
return_path : bool, default=False
Whether to return every value of the nonzero coefficients along the
forward path. Useful for cross-validation.
return_n_iter : bool, default=False
2014-07-21 07:03:46 +08:00
Whether or not to return the number of iterations.
2011-07-25 18:57:42 +08:00
Returns
-------
coef : ndarray of shape (n_features,) or (n_features, n_targets)
Coefficients of the OMP solution. If `return_path=True`, this contains
the whole coefficient path. In this case its shape is
(n_features, n_features) or (n_features, n_targets, n_features) and
iterating over the last axis yields coefficients in increasing order
of active features.
2011-07-25 18:57:42 +08:00
2014-07-21 07:03:46 +08:00
n_iters : array-like or int
Number of active features across every target. Returned only if
`return_n_iter` is set to True.
See Also
2011-07-25 18:57:42 +08:00
--------
2011-08-03 22:59:30 +08:00
OrthogonalMatchingPursuit
2011-07-25 18:57:42 +08:00
orthogonal_mp
lars_path
sklearn.decomposition.sparse_encode
2011-07-25 18:57:42 +08:00
2011-08-03 22:59:30 +08:00
Notes
-----
Orthogonal matching pursuit was introduced in G. Mallat, Z. Zhang,
Matching pursuits with time-frequency dictionaries, IEEE Transactions on
Signal Processing, Vol. 41, No. 12. (December 1993), pp. 3397-3415.
(http://blanche.polytechnique.fr/~mallat/papiers/MallatPursuit93.pdf)
This implementation is based on Rubinstein, R., Zibulevsky, M. and Elad,
M., Efficient Implementation of the K-SVD Algorithm using Batch Orthogonal
Matching Pursuit Technical Report - CS Technion, April 2008.
https://www.cs.technion.ac.il/~ronrubin/Publications/KSVD-OMP-v2.pdf
2011-08-03 22:59:30 +08:00
2011-07-25 18:57:42 +08:00
"""
Gram = check_array(Gram, order='F', copy=copy_Gram)
Xy = np.asarray(Xy)
2012-10-10 15:38:10 +08:00
if Xy.ndim > 1 and Xy.shape[1] > 1:
# or subsequent target will be affected
copy_Gram = True
2011-07-25 18:57:42 +08:00
if Xy.ndim == 1:
Xy = Xy[:, np.newaxis]
2011-08-24 21:31:07 +08:00
if tol is not None:
norms_squared = [norms_squared]
if copy_Xy or not Xy.flags.writeable:
# Make the copy once instead of many times in _gram_omp itself.
Xy = Xy.copy()
2011-07-25 18:57:42 +08:00
2012-12-22 20:02:50 +08:00
if n_nonzero_coefs is None and tol is None:
2011-08-03 21:18:16 +08:00
n_nonzero_coefs = int(0.1 * len(Gram))
2012-12-22 20:02:50 +08:00
if tol is not None and norms_squared is None:
2012-08-26 03:54:30 +08:00
raise ValueError('Gram OMP needs the precomputed norms in order '
'to evaluate the error sum of squares.')
2011-08-24 21:31:07 +08:00
if tol is not None and tol < 0:
2012-08-26 03:54:30 +08:00
raise ValueError("Epsilon cannot be negative")
2011-08-24 21:31:07 +08:00
if tol is None and n_nonzero_coefs <= 0:
2011-07-25 18:57:42 +08:00
raise ValueError("The number of atoms must be positive")
2011-08-24 21:31:07 +08:00
if tol is None and n_nonzero_coefs > len(Gram):
2012-08-26 03:54:30 +08:00
raise ValueError("The number of atoms cannot be more than the number "
2012-12-22 20:02:50 +08:00
"of features")
if return_path:
coef = np.zeros((len(Gram), Xy.shape[1], len(Gram)))
else:
coef = np.zeros((len(Gram), Xy.shape[1]))
2014-07-21 07:03:46 +08:00
n_iters = []
2011-07-25 18:57:42 +08:00
for k in range(Xy.shape[1]):
2014-07-21 07:03:46 +08:00
out = _gram_omp(
Gram, Xy[:, k], n_nonzero_coefs,
norms_squared[k] if tol is not None else None, tol,
copy_Gram=copy_Gram, copy_Xy=False,
2015-03-18 09:54:51 +08:00
return_path=return_path)
if return_path:
2014-07-21 07:03:46 +08:00
_, idx, coefs, n_iter = out
coef = coef[:, :, :len(idx)]
for n_active, x in enumerate(coefs.T):
coef[idx[:n_active + 1], k, n_active] = x[:n_active + 1]
else:
2014-07-21 07:03:46 +08:00
x, idx, n_iter = out
coef[idx, k] = x
2014-07-21 07:03:46 +08:00
n_iters.append(n_iter)
if Xy.shape[1] == 1:
n_iters = n_iters[0]
2014-07-21 07:03:46 +08:00
if return_n_iter:
return np.squeeze(coef), n_iters
else:
return np.squeeze(coef)
2011-07-29 07:54:23 +08:00
class OrthogonalMatchingPursuit(MultiOutputMixin, RegressorMixin, LinearModel):
"""Orthogonal Matching Pursuit model (OMP).
2011-07-29 07:54:23 +08:00
Read more in the :ref:`User Guide <omp>`.
2011-07-29 07:54:23 +08:00
Parameters
----------
n_nonzero_coefs : int, default=None
Desired number of non-zero entries in the solution. If None (by
default) this value is set to 10% of n_features.
2011-07-29 07:54:23 +08:00
tol : float, default=None
2011-07-29 07:54:23 +08:00
Maximum norm of the residual. If not None, overrides n_nonzero_coefs.
fit_intercept : bool, default=True
2011-07-29 07:54:23 +08:00
whether to calculate the intercept for this model. If set
to false, no intercept will be used in calculations
(i.e. data is expected to be centered).
2011-07-29 07:55:48 +08:00
normalize : bool, default=True
This parameter is ignored when ``fit_intercept`` is set to False.
If True, the regressors X will be normalized before regression by
subtracting the mean and dividing by the l2-norm.
If you wish to standardize, please use
:class:`~sklearn.preprocessing.StandardScaler` before calling ``fit``
on an estimator with ``normalize=False``.
2011-07-29 07:54:23 +08:00
precompute : 'auto' or bool, default='auto'
2011-08-03 21:18:16 +08:00
Whether to use a precomputed Gram and Xy matrix to speed up
calculations. Improves performance when :term:`n_targets` or
:term:`n_samples` is very large. Note that if you already have such
matrices, you can pass them directly to the fit method.
2011-07-29 07:54:23 +08:00
Attributes
----------
coef_ : ndarray of shape (n_features,) or (n_targets, n_features)
Parameter vector (w in the formula).
2011-07-29 07:54:23 +08:00
intercept_ : float or ndarray of shape (n_targets,)
Independent term in decision function.
2011-07-29 07:54:23 +08:00
n_iter_ : int or array-like
2014-07-21 07:03:46 +08:00
Number of active features across every target.
Examples
--------
>>> from sklearn.linear_model import OrthogonalMatchingPursuit
>>> from sklearn.datasets import make_regression
>>> X, y = make_regression(noise=4, random_state=0)
>>> reg = OrthogonalMatchingPursuit().fit(X, y)
>>> reg.score(X, y)
0.9991...
>>> reg.predict(X[:1,])
array([-78.3854...])
2011-08-03 22:59:30 +08:00
Notes
-----
Orthogonal matching pursuit was introduced in G. Mallat, Z. Zhang,
Matching pursuits with time-frequency dictionaries, IEEE Transactions on
Signal Processing, Vol. 41, No. 12. (December 1993), pp. 3397-3415.
(http://blanche.polytechnique.fr/~mallat/papiers/MallatPursuit93.pdf)
This implementation is based on Rubinstein, R., Zibulevsky, M. and Elad,
M., Efficient Implementation of the K-SVD Algorithm using Batch Orthogonal
Matching Pursuit Technical Report - CS Technion, April 2008.
https://www.cs.technion.ac.il/~ronrubin/Publications/KSVD-OMP-v2.pdf
2011-08-03 22:59:30 +08:00
See Also
2011-08-03 22:59:30 +08:00
--------
orthogonal_mp
orthogonal_mp_gram
lars_path
Lars
LassoLars
sklearn.decomposition.sparse_encode
OrthogonalMatchingPursuitCV
2011-07-29 07:54:23 +08:00
"""
@_deprecate_positional_args
def __init__(self, *, n_nonzero_coefs=None, tol=None, fit_intercept=True,
normalize=True, precompute='auto'):
2011-07-29 07:54:23 +08:00
self.n_nonzero_coefs = n_nonzero_coefs
2011-08-24 21:31:07 +08:00
self.tol = tol
2011-07-29 07:54:23 +08:00
self.fit_intercept = fit_intercept
self.normalize = normalize
self.precompute = precompute
2011-07-29 07:54:23 +08:00
def fit(self, X, y):
2011-07-29 07:54:23 +08:00
"""Fit the model using X, y as training data.
Parameters
----------
X : array-like of shape (n_samples, n_features)
2011-07-29 07:54:23 +08:00
Training data.
y : array-like of shape (n_samples,) or (n_samples, n_targets)
Target values. Will be cast to X's dtype if necessary
2011-08-03 22:04:26 +08:00
2011-07-29 07:54:23 +08:00
Returns
-------
2014-12-01 09:59:42 +08:00
self : object
2011-07-29 07:54:23 +08:00
returns an instance of self.
"""
X, y = self._validate_data(X, y, multi_output=True, y_numeric=True)
n_features = X.shape[1]
2011-07-29 07:54:23 +08:00
X, y, X_offset, y_offset, X_scale, Gram, Xy = \
_pre_fit(X, y, None, self.precompute, self.normalize,
self.fit_intercept, copy=True)
2012-03-19 18:35:58 +08:00
if y.ndim == 1:
y = y[:, np.newaxis]
2012-12-22 20:02:50 +08:00
if self.n_nonzero_coefs is None and self.tol is None:
# default for n_nonzero_coefs is 0.1 * n_features
# but at least one.
self.n_nonzero_coefs_ = max(int(0.1 * n_features), 1)
else:
self.n_nonzero_coefs_ = self.n_nonzero_coefs
2013-07-26 00:49:02 +08:00
if Gram is False:
2014-07-21 07:03:46 +08:00
coef_, self.n_iter_ = orthogonal_mp(
X, y, n_nonzero_coefs=self.n_nonzero_coefs_, tol=self.tol,
2014-07-21 07:03:46 +08:00
precompute=False, copy_X=True,
return_n_iter=True)
2013-07-26 00:49:02 +08:00
else:
2011-08-24 21:31:07 +08:00
norms_sq = np.sum(y ** 2, axis=0) if self.tol is not None else None
2014-07-21 07:03:46 +08:00
coef_, self.n_iter_ = orthogonal_mp_gram(
Gram, Xy=Xy, n_nonzero_coefs=self.n_nonzero_coefs_,
tol=self.tol, norms_squared=norms_sq,
2014-07-21 07:03:46 +08:00
copy_Gram=True, copy_Xy=True,
return_n_iter=True)
self.coef_ = coef_.T
self._set_intercept(X_offset, y_offset, X_scale)
2011-07-29 07:54:23 +08:00
return self
def _omp_path_residues(X_train, y_train, X_test, y_test, copy=True,
fit_intercept=True, normalize=True, max_iter=100):
"""Compute the residues on left-out data for a full LARS path.
Parameters
----------
X_train : ndarray of shape (n_samples, n_features)
The data to fit the LARS on.
y_train : ndarray of shape (n_samples)
The target variable to fit LARS on.
X_test : ndarray of shape (n_samples, n_features)
The data to compute the residues on.
y_test : ndarray of shape (n_samples)
The target variable to compute the residues on.
copy : bool, default=True
Whether X_train, X_test, y_train and y_test should be copied. If
False, they may be overwritten.
fit_intercept : bool, default=True
Whether to calculate the intercept for this model. If set
to false, no intercept will be used in calculations
(i.e. data is expected to be centered).
normalize : bool, default=True
This parameter is ignored when ``fit_intercept`` is set to False.
If True, the regressors X will be normalized before regression by
subtracting the mean and dividing by the l2-norm.
If you wish to standardize, please use
:class:`~sklearn.preprocessing.StandardScaler` before calling ``fit``
on an estimator with ``normalize=False``.
max_iter : int, default=100
Maximum numbers of iterations to perform, therefore maximum features
to include. 100 by default.
Returns
-------
residues : ndarray of shape (n_samples, max_features)
Residues of the prediction on the test data.
"""
if copy:
X_train = X_train.copy()
y_train = y_train.copy()
X_test = X_test.copy()
y_test = y_test.copy()
if fit_intercept:
X_mean = X_train.mean(axis=0)
X_train -= X_mean
X_test -= X_mean
y_mean = y_train.mean(axis=0)
y_train = as_float_array(y_train, copy=False)
y_train -= y_mean
y_test = as_float_array(y_test, copy=False)
y_test -= y_mean
if normalize:
norms = np.sqrt(np.sum(X_train ** 2, axis=0))
nonzeros = np.flatnonzero(norms)
X_train[:, nonzeros] /= norms[nonzeros]
coefs = orthogonal_mp(X_train, y_train, n_nonzero_coefs=max_iter, tol=None,
2013-07-26 00:49:02 +08:00
precompute=False, copy_X=False,
return_path=True)
if coefs.ndim == 1:
coefs = coefs[:, np.newaxis]
if normalize:
coefs[nonzeros] /= norms[nonzeros][:, np.newaxis]
return np.dot(coefs.T, X_test.T) - y_test
class OrthogonalMatchingPursuitCV(RegressorMixin, LinearModel):
"""Cross-validated Orthogonal Matching Pursuit model (OMP).
See glossary entry for :term:`cross-validation estimator`.
Read more in the :ref:`User Guide <omp>`.
Parameters
----------
copy : bool, default=True
Whether the design matrix X must be copied by the algorithm. A false
value is only helpful if X is already Fortran-ordered, otherwise a
copy is made anyway.
fit_intercept : bool, default=True
whether to calculate the intercept for this model. If set
to false, no intercept will be used in calculations
(i.e. data is expected to be centered).
normalize : bool, default=True
This parameter is ignored when ``fit_intercept`` is set to False.
If True, the regressors X will be normalized before regression by
subtracting the mean and dividing by the l2-norm.
If you wish to standardize, please use
:class:`~sklearn.preprocessing.StandardScaler` before calling ``fit``
on an estimator with ``normalize=False``.
max_iter : int, default=None
Maximum numbers of iterations to perform, therefore maximum features
2013-07-26 15:36:49 +08:00
to include. 10% of ``n_features`` but at least 5 if available.
cv : int, cross-validation generator or iterable, default=None
Determines the cross-validation splitting strategy.
Possible inputs for cv are:
2015-11-05 08:21:50 +08:00
- None, to use the default 5-fold cross-validation,
2015-11-05 08:21:50 +08:00
- integer, to specify the number of folds.
- :term:`CV splitter`,
- An iterable yielding (train, test) splits as arrays of indices.
For integer/None inputs, :class:`KFold` is used.
Refer :ref:`User Guide <cross_validation>` for the various
cross-validation strategies that can be used here.
.. versionchanged:: 0.22
``cv`` default value if None changed from 3-fold to 5-fold.
n_jobs : int, default=None
Number of CPUs to use during the cross validation.
``None`` means 1 unless in a :obj:`joblib.parallel_backend` context.
``-1`` means using all processors. See :term:`Glossary <n_jobs>`
for more details.
verbose : bool or int, default=False
Sets the verbosity amount.
Attributes
----------
intercept_ : float or ndarray of shape (n_targets,)
Independent term in decision function.
coef_ : ndarray of shape (n_features,) or (n_targets, n_features)
Parameter vector (w in the problem formulation).
n_nonzero_coefs_ : int
Estimated number of non-zero coefficients giving the best mean squared
error over the cross-validation folds.
n_iter_ : int or array-like
2014-07-21 07:03:46 +08:00
Number of active features across every target for the model refit with
the best hyperparameters got by cross-validating across all folds.
Examples
--------
>>> from sklearn.linear_model import OrthogonalMatchingPursuitCV
>>> from sklearn.datasets import make_regression
>>> X, y = make_regression(n_features=100, n_informative=10,
... noise=4, random_state=0)
>>> reg = OrthogonalMatchingPursuitCV(cv=5).fit(X, y)
>>> reg.score(X, y)
0.9991...
>>> reg.n_nonzero_coefs_
10
>>> reg.predict(X[:1,])
array([-78.3854...])
See Also
--------
orthogonal_mp
orthogonal_mp_gram
lars_path
Lars
LassoLars
OrthogonalMatchingPursuit
LarsCV
LassoLarsCV
sklearn.decomposition.sparse_encode
"""
@_deprecate_positional_args
def __init__(self, *, copy=True, fit_intercept=True, normalize=True,
max_iter=None, cv=None, n_jobs=None, verbose=False):
self.copy = copy
self.fit_intercept = fit_intercept
self.normalize = normalize
self.max_iter = max_iter
self.cv = cv
self.n_jobs = n_jobs
self.verbose = verbose
def fit(self, X, y):
"""Fit the model using X, y as training data.
Parameters
----------
X : array-like of shape (n_samples, n_features)
Training data.
y : array-like of shape (n_samples,)
Target values. Will be cast to X's dtype if necessary.
Returns
-------
self : object
returns an instance of self.
"""
X, y = self._validate_data(X, y, y_numeric=True, ensure_min_features=2,
estimator=self)
X = as_float_array(X, copy=False, force_all_finite=False)
Main Commits - Major -------------------- * ENH Reogranize classes/fn from grid_search into search.py * ENH Reogranize classes/fn from cross_validation into split.py * ENH Reogranize cls/fn from cross_validation/learning_curve into validate.py * MAINT Merge _check_cv into check_cv inside the model_selection module * MAINT Update all the imports to point to the model_selection module * FIX use iter_cv to iterate throught the new style/old style cv objs * TST Add tests for the new model_selection members * ENH Wrap the old-style cv obj/iterables instead of using iter_cv * ENH Use scipy's binomial coefficient function comb for calucation of nCk * ENH Few enhancements to the split module * ENH Improve check_cv input validation and docstring * MAINT _get_test_folds(X, y, labels) --> _get_test_folds(labels) * TST if 1d arrays for X introduce any errors * ENH use 1d X arrays for all tests; * ENH X_10 --> X (global var) Minor ----- * ENH _PartitionIterator --> _BaseCrossValidator; * ENH CVIterator --> CVIterableWrapper * TST Import the old SKF locally * FIX/TST Clean up the split module's tests. * DOC Improve documentation of the cv parameter * COSMIT consistently hyphenate cross-validation/cross-validator * TST Calculate n_samples from X * COSMIT Use separate lines for each import. * COSMIT cross_validation_generator --> cross_validator Commits merged manually ----------------------- * FIX Document the random_state attribute in RandomSearchCV * MAINT Use check_cv instead of _check_cv * ENH refactor OVO decision function, use it in SVC for sklearn-like decision_function shape * FIX avoid memory cost when sampling from large parameter grids ENH Major to Minor incremental enhancements to the model_selection Squashed commit messages - (For reference) Major ----- * ENH p --> n_labels * FIX *ShuffleSplit: all float/invalid type errors at init and int error at split * FIX make PredefinedSplit accept test_folds in constructor; Cleanup docstrings * ENH+TST KFold: make rng to be generated at every split call for reproducibility * FIX/MAINT KFold: make shuffle a public attr * FIX Make CVIterableWrapper private. * FIX reuse len_cv instead of recalculating it * FIX Prevent adding *SearchCV estimators from the old grid_search module * re-FIX In all_estimators: the sorting to use only the 1st item (name) To avoid collision between the old and the new GridSearch classes. * FIX test_validate.py: Use 2D X (1D X is being detected as a single sample) * MAINT validate.py --> validation.py * MAINT make the submodules private * MAINT Support old cv/gs/lc until 0.19 * FIX/MAINT n_splits --> get_n_splits * FIX/TST test_logistic.py/test_ovr_multinomial_iris: pass predefined folds as an iterable * MAINT expose BaseCrossValidator * Update the model_selection module with changes from master - From #5161 - - MAINT remove redundant p variable - - Add check for sparse prediction in cross_val_predict - From #5201 - DOC improve random_state param doc - From #5190 - LabelKFold and test - From #4583 - LabelShuffleSplit and tests - From #5300 - shuffle the `labels` not the `indxs` in LabelKFold + tests - From #5378 - Make the GridSearchCV docs more accurate. - From #5458 - Remove shuffle from LabelKFold - From #5466(#4270) - Gaussian Process by Jan Metzen - From #4826 - Move custom error / warnings into sklearn.exception Minor ----- * ENH Make the KFold shuffling test stronger * FIX/DOC Use the higher level model_selection module as ref * DOC in check_cv "y : array-like, optional" * DOC a supervised learning problem --> supervised learning problems * DOC cross-validators --> cross-validation strategies * DOC Correct Olivier Grisel's name ;) * MINOR/FIX cv_indices --> kfold * FIX/DOC Align the 'See also' section of the new KFold, LeaveOneOut * TST/FIX imports on separate lines * FIX use __class__ instead of classmethod * TST/FIX import directly from model_selection * COSMIT Relocate the random_state documentation * COSMIT remove pass * MAINT Remove deprecation warnings from old tests * FIX correct import at test_split * FIX/MAINT Move P_sparse, X, y defns to top; rm unused W_sparse, X_sparse * FIX random state to avoid doctest failure * TST n_splits and split wrapping of _CVIterableWrapper * FIX/MAINT Use multilabel indicator matrix directly * TST/DOC clarify why we conflate classes 0 and 1 * DOC add comment that this was taken from BaseEstimator * FIX use of labels is not needed in stratified k fold * Fix cross_validation reference * Fix the labels param doc FIX/DOC/MAINT Addressing the review comments by Arnaud and Andy COSMIT Sort the members alphabetically COSMIT len_cv --> n_splits COSMIT Merge 2 if; FIX Use kwargs DOC Add my name to the authors :D DOC make labels parameter consistent FIX Remove hack for boolean indices; + COSMIT idx --> indices; DOC Add Returns COSMIT preds --> predictions DOC Add Returns and neatly arrange X, y, labels FIX idx(s)/ind(s)--> indice(s) COSMIT Merge if and else to elif COSMIT n --> n_samples COSMIT Use bincount only once COSMIT cls --> class_i / class_i (ith class indices) --> perm_indices_class_i FIX/ENH/TST Addressing the final reviews COSMIT c --> count FIX/TST make check_cv raise ValueError for string cv value TST nested cv (gs inside cross_val_score) works for diff cvs FIX/ENH Raise ValueError when labels is None for label based cvs; TST if labels is being passed correctly to the cv and that the ValueError is being propagated to the cross_val_score/predict and grid search FIX pass labels to cross_val_score FIX use make_classification DOC Add Returns; COSMIT Remove scaffolding TST add a test to check the _build_repr helper REVERT the old GS/RS should also be tested by the common tests. ENH Add a tuple of all/label based CVS FIX raise VE even at get_n_splits if labels is None FIX Fabian's comments PEP8
2015-06-05 03:45:10 +08:00
cv = check_cv(self.cv, classifier=False)
2013-07-26 15:36:49 +08:00
max_iter = (min(max(int(0.1 * X.shape[1]), 5), X.shape[1])
if not self.max_iter
else self.max_iter)
cv_paths = Parallel(n_jobs=self.n_jobs, verbose=self.verbose)(
delayed(_omp_path_residues)(
X[train], y[train], X[test], y[test], self.copy,
self.fit_intercept, self.normalize, max_iter)
Main Commits - Major -------------------- * ENH Reogranize classes/fn from grid_search into search.py * ENH Reogranize classes/fn from cross_validation into split.py * ENH Reogranize cls/fn from cross_validation/learning_curve into validate.py * MAINT Merge _check_cv into check_cv inside the model_selection module * MAINT Update all the imports to point to the model_selection module * FIX use iter_cv to iterate throught the new style/old style cv objs * TST Add tests for the new model_selection members * ENH Wrap the old-style cv obj/iterables instead of using iter_cv * ENH Use scipy's binomial coefficient function comb for calucation of nCk * ENH Few enhancements to the split module * ENH Improve check_cv input validation and docstring * MAINT _get_test_folds(X, y, labels) --> _get_test_folds(labels) * TST if 1d arrays for X introduce any errors * ENH use 1d X arrays for all tests; * ENH X_10 --> X (global var) Minor ----- * ENH _PartitionIterator --> _BaseCrossValidator; * ENH CVIterator --> CVIterableWrapper * TST Import the old SKF locally * FIX/TST Clean up the split module's tests. * DOC Improve documentation of the cv parameter * COSMIT consistently hyphenate cross-validation/cross-validator * TST Calculate n_samples from X * COSMIT Use separate lines for each import. * COSMIT cross_validation_generator --> cross_validator Commits merged manually ----------------------- * FIX Document the random_state attribute in RandomSearchCV * MAINT Use check_cv instead of _check_cv * ENH refactor OVO decision function, use it in SVC for sklearn-like decision_function shape * FIX avoid memory cost when sampling from large parameter grids ENH Major to Minor incremental enhancements to the model_selection Squashed commit messages - (For reference) Major ----- * ENH p --> n_labels * FIX *ShuffleSplit: all float/invalid type errors at init and int error at split * FIX make PredefinedSplit accept test_folds in constructor; Cleanup docstrings * ENH+TST KFold: make rng to be generated at every split call for reproducibility * FIX/MAINT KFold: make shuffle a public attr * FIX Make CVIterableWrapper private. * FIX reuse len_cv instead of recalculating it * FIX Prevent adding *SearchCV estimators from the old grid_search module * re-FIX In all_estimators: the sorting to use only the 1st item (name) To avoid collision between the old and the new GridSearch classes. * FIX test_validate.py: Use 2D X (1D X is being detected as a single sample) * MAINT validate.py --> validation.py * MAINT make the submodules private * MAINT Support old cv/gs/lc until 0.19 * FIX/MAINT n_splits --> get_n_splits * FIX/TST test_logistic.py/test_ovr_multinomial_iris: pass predefined folds as an iterable * MAINT expose BaseCrossValidator * Update the model_selection module with changes from master - From #5161 - - MAINT remove redundant p variable - - Add check for sparse prediction in cross_val_predict - From #5201 - DOC improve random_state param doc - From #5190 - LabelKFold and test - From #4583 - LabelShuffleSplit and tests - From #5300 - shuffle the `labels` not the `indxs` in LabelKFold + tests - From #5378 - Make the GridSearchCV docs more accurate. - From #5458 - Remove shuffle from LabelKFold - From #5466(#4270) - Gaussian Process by Jan Metzen - From #4826 - Move custom error / warnings into sklearn.exception Minor ----- * ENH Make the KFold shuffling test stronger * FIX/DOC Use the higher level model_selection module as ref * DOC in check_cv "y : array-like, optional" * DOC a supervised learning problem --> supervised learning problems * DOC cross-validators --> cross-validation strategies * DOC Correct Olivier Grisel's name ;) * MINOR/FIX cv_indices --> kfold * FIX/DOC Align the 'See also' section of the new KFold, LeaveOneOut * TST/FIX imports on separate lines * FIX use __class__ instead of classmethod * TST/FIX import directly from model_selection * COSMIT Relocate the random_state documentation * COSMIT remove pass * MAINT Remove deprecation warnings from old tests * FIX correct import at test_split * FIX/MAINT Move P_sparse, X, y defns to top; rm unused W_sparse, X_sparse * FIX random state to avoid doctest failure * TST n_splits and split wrapping of _CVIterableWrapper * FIX/MAINT Use multilabel indicator matrix directly * TST/DOC clarify why we conflate classes 0 and 1 * DOC add comment that this was taken from BaseEstimator * FIX use of labels is not needed in stratified k fold * Fix cross_validation reference * Fix the labels param doc FIX/DOC/MAINT Addressing the review comments by Arnaud and Andy COSMIT Sort the members alphabetically COSMIT len_cv --> n_splits COSMIT Merge 2 if; FIX Use kwargs DOC Add my name to the authors :D DOC make labels parameter consistent FIX Remove hack for boolean indices; + COSMIT idx --> indices; DOC Add Returns COSMIT preds --> predictions DOC Add Returns and neatly arrange X, y, labels FIX idx(s)/ind(s)--> indice(s) COSMIT Merge if and else to elif COSMIT n --> n_samples COSMIT Use bincount only once COSMIT cls --> class_i / class_i (ith class indices) --> perm_indices_class_i FIX/ENH/TST Addressing the final reviews COSMIT c --> count FIX/TST make check_cv raise ValueError for string cv value TST nested cv (gs inside cross_val_score) works for diff cvs FIX/ENH Raise ValueError when labels is None for label based cvs; TST if labels is being passed correctly to the cv and that the ValueError is being propagated to the cross_val_score/predict and grid search FIX pass labels to cross_val_score FIX use make_classification DOC Add Returns; COSMIT Remove scaffolding TST add a test to check the _build_repr helper REVERT the old GS/RS should also be tested by the common tests. ENH Add a tuple of all/label based CVS FIX raise VE even at get_n_splits if labels is None FIX Fabian's comments PEP8
2015-06-05 03:45:10 +08:00
for train, test in cv.split(X))
min_early_stop = min(fold.shape[0] for fold in cv_paths)
mse_folds = np.array([(fold[:min_early_stop] ** 2).mean(axis=1)
for fold in cv_paths])
best_n_nonzero_coefs = np.argmin(mse_folds.mean(axis=0)) + 1
self.n_nonzero_coefs_ = best_n_nonzero_coefs
omp = OrthogonalMatchingPursuit(n_nonzero_coefs=best_n_nonzero_coefs,
fit_intercept=self.fit_intercept,
normalize=self.normalize)
omp.fit(X, y)
self.coef_ = omp.coef_
self.intercept_ = omp.intercept_
2014-07-21 07:03:46 +08:00
self.n_iter_ = omp.n_iter_
return self