scikit-learn/sklearn/linear_model/omp.py

883 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 distutils.version import LooseVersion
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
2011-07-25 18:57:42 +08:00
2013-07-25 23:59:36 +08:00
from .base import LinearModel, _pre_fit
2012-06-13 12:26:02 +08:00
from ..base import RegressorMixin
from ..utils import as_float_array, check_array, check_X_y
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
from ..externals.joblib import Parallel, delayed
2011-07-25 18:57:42 +08:00
import scipy
solve_triangular_args = {}
if LooseVersion(scipy.__version__) >= LooseVersion('0.12'):
2015-03-18 09:54:51 +08:00
# check_finite=False is an optimization available only in scipy >=0.12
solve_triangular_args = {'check_finite': False}
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
----------
2013-07-25 21:42:19 +08:00
X : array, shape (n_samples, n_features)
2011-07-25 18:57:42 +08:00
Input dictionary. Columns are assumed to have unit norm.
2013-07-25 21:42:19 +08:00
y : array, shape (n_samples,)
2011-07-25 18:57:42 +08:00
Input targets
2013-07-25 21:42:19 +08:00
n_nonzero_coefs : int
2011-07-25 18:57:42 +08:00
Targeted number of non-zero elements
2013-07-25 21:42:19 +08:00
tol : float
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
2013-07-25 21:42:19 +08:00
copy_X : bool, optional
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
2013-07-25 21:42:19 +08:00
return_path : bool, optional. 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 : array, shape (n_nonzero_coefs,)
2011-07-25 18:57:42 +08:00
Non-zero elements of the solution
2013-07-25 21:42:19 +08:00
idx : array, 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
2013-07-25 21:42:19 +08:00
coef : array, 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
2015-03-18 09:54:51 +08:00
if solve_triangular_args:
# new scipy, don't need to initialize because check_finite=False
L = np.empty((max_features, max_features), dtype=X.dtype)
else:
# old scipy, we need the garbage upper triangle to be non-Inf
L = np.zeros((max_features, max_features), dtype=X.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(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,
**solve_triangular_args)
v = nrm2(L[n_active, :n_active]) ** 2
if 1 - v <= min_float: # selected atoms are dependent
warnings.warn(premature, RuntimeWarning, stacklevel=2)
break
L[n_active, n_active] = np.sqrt(1 - v)
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
2011-07-25 18:57:42 +08:00
# solves LL'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
----------
2013-07-25 21:42:19 +08:00
Gram : array, shape (n_features, n_features)
2011-07-25 18:57:42 +08:00
Gram matrix of the input data matrix
2013-07-25 21:42:19 +08:00
Xy : array, shape (n_features,)
2011-07-25 18:57:42 +08:00
Input targets
2013-07-25 21:42:19 +08:00
n_nonzero_coefs : int
2011-07-25 18:57:42 +08:00
Targeted number of non-zero elements
2013-07-25 21:42:19 +08:00
tol_0 : float
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
2013-07-25 21:42:19 +08:00
tol : float
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
2013-07-25 21:42:19 +08:00
copy_Gram : bool, optional
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
2013-07-25 21:42:19 +08:00
copy_Xy : bool, optional
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
2013-07-25 21:42:19 +08:00
return_path : bool, optional. 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 : array, shape (n_nonzero_coefs,)
2011-07-25 18:57:42 +08:00
Non-zero elements of the solution
2013-07-25 21:42:19 +08:00
idx : array, 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
2013-07-25 21:42:19 +08:00
coefs : array, 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:
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
2015-05-20 17:38:38 +08:00
if solve_triangular_args:
# new scipy, don't need to initialize because check_finite=False
L = np.empty((max_features, max_features), dtype=Gram.dtype)
else:
# old scipy, we need the garbage upper triangle to be non-Inf
L = np.zeros((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,
**solve_triangular_args)
v = nrm2(L[n_active, :n_active]) ** 2
if 1 - v <= 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] = np.sqrt(1 - v)
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 = 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
2013-07-26 00:49:02 +08:00
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):
2011-07-25 18:57:42 +08:00
"""Orthogonal Matching Pursuit (OMP)
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
----------
2014-12-01 09:59:42 +08:00
X : array, 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
2014-12-01 09:59:42 +08:00
y : array, shape (n_samples,) or (n_samples, n_targets)
2011-07-25 18:57:42 +08:00
Input targets
2014-12-01 09:59:42 +08:00
n_nonzero_coefs : int
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
2014-12-01 09:59:42 +08:00
tol : float
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
2014-12-01 09:59:42 +08:00
precompute : {True, False, 'auto'},
2011-07-25 18:57:42 +08:00
Whether to perform precomputations. Improves performance when n_targets
or n_samples is very large.
2014-12-01 09:59:42 +08:00
copy_X : bool, optional
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
2014-12-01 09:59:42 +08:00
return_path : bool, optional. Default: False
Whether to return every value of the nonzero coefficients along the
forward path. Useful for cross-validation.
2014-07-21 07:03:46 +08:00
return_n_iter : bool, optional default False
Whether or not to return the number of iterations.
2011-07-25 18:57:42 +08:00
Returns
-------
2014-12-01 09:59:42 +08:00
coef : array, 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.
2011-07-25 18:57:42 +08:00
See also
--------
2011-08-03 22:59:30 +08:00
OrthogonalMatchingPursuit
2011-07-25 18:57:42 +08:00
orthogonal_mp_gram
lars_path
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.
http://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
2011-08-24 21:31:07 +08:00
return orthogonal_mp_gram(G, Xy, n_nonzero_coefs, tol, 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
2011-08-24 21:31:07 +08:00
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):
2011-07-25 18:57:42 +08:00
"""Gram Orthogonal Matching Pursuit (OMP)
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
----------
2014-12-01 09:59:42 +08:00
Gram : array, shape (n_features, n_features)
2011-07-25 18:57:42 +08:00
Gram matrix of the input data: X.T * X
2014-12-01 09:59:42 +08:00
Xy : array, shape (n_features,) or (n_features, n_targets)
2011-08-03 22:01:53 +08:00
Input targets multiplied by X: X.T * y
2011-07-25 18:57:42 +08:00
2014-12-01 09:59:42 +08:00
n_nonzero_coefs : int
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
2014-12-01 09:59:42 +08:00
tol : float
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
2014-12-01 09:59:42 +08:00
norms_squared : array-like, shape (n_targets,)
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
2014-12-01 09:59:42 +08:00
copy_Gram : bool, optional
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
2014-12-01 09:59:42 +08:00
copy_Xy : bool, optional
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
2014-12-01 09:59:42 +08:00
return_path : bool, optional. Default: False
Whether to return every value of the nonzero coefficients along the
forward path. Useful for cross-validation.
2014-07-21 07:03:46 +08:00
return_n_iter : bool, optional default False
Whether or not to return the number of iterations.
2011-07-25 18:57:42 +08:00
Returns
-------
2014-12-01 09:59:42 +08:00
coef : array, 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.
2011-07-25 18:57:42 +08:00
See also
--------
2011-08-03 22:59:30 +08:00
OrthogonalMatchingPursuit
2011-07-25 18:57:42 +08:00
orthogonal_mp
lars_path
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.
http://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]
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=copy_Xy,
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
2012-06-13 12:26:02 +08:00
class OrthogonalMatchingPursuit(LinearModel, RegressorMixin):
2015-01-16 04:09:35 +08:00
"""Orthogonal Matching Pursuit model (OMP)
2011-07-29 07:54:23 +08:00
Parameters
----------
2011-12-23 04:05:27 +08:00
n_nonzero_coefs : int, optional
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
2011-12-23 04:05:27 +08:00
tol : float, optional
2011-07-29 07:54:23 +08:00
Maximum norm of the residual. If not None, overrides n_nonzero_coefs.
2011-12-23 04:05:27 +08:00
fit_intercept : boolean, optional
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
(e.g. data is expected to be already centered).
2011-07-29 07:55:48 +08:00
normalize : boolean, optional, default False
If True, the regressors X will be normalized before regression.
This parameter is ignored when `fit_intercept` is set to `False`.
When the regressors are normalized, note that this makes the
hyperparameters learnt more robust and almost independent of the number
of samples. The same property is not valid for standardized data.
However, if you wish to standardize, please use
`preprocessing.StandardScaler` before calling `fit` on an estimator
with `normalize=False`.
2011-07-29 07:54:23 +08:00
precompute : {True, False, 'auto'}, default 'auto'
2011-08-03 21:18:16 +08:00
Whether to use a precomputed Gram and Xy matrix to speed up
2011-08-03 22:59:30 +08:00
calculations. Improves performance when `n_targets` or `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
2015-06-03 12:24:04 +08:00
Read more in the :ref:`User Guide <omp>`.
2011-07-29 07:54:23 +08:00
Attributes
----------
coef_ : array, shape (n_features,) or (n_features, n_targets)
parameter vector (w in the formula)
2011-07-29 07:54:23 +08:00
intercept_ : float or array, shape (n_targets,)
2011-07-29 07:54:23 +08:00
independent term in decision function.
n_iter_ : int or array-like
2014-07-21 07:03:46 +08:00
Number of active features across every target.
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.
http://www.cs.technion.ac.il/~ronrubin/Publications/KSVD-OMP-v2.pdf
2011-08-03 22:59:30 +08:00
See also
--------
orthogonal_mp
orthogonal_mp_gram
lars_path
Lars
LassoLars
decomposition.sparse_encode
2011-08-03 22:59:30 +08:00
2011-07-29 07:54:23 +08:00
"""
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
----------
2013-07-25 21:42:19 +08:00
X : array-like, shape (n_samples, n_features)
2011-07-29 07:54:23 +08:00
Training data.
2013-07-25 21:42:19 +08:00
y : array-like, shape (n_samples,) or (n_samples, n_targets)
2011-07-29 07:54:23 +08:00
Target values.
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 = check_X_y(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, self.n_nonzero_coefs_, self.tol,
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 : array, shape (n_samples, n_features)
The data to fit the LARS on
y_train : array, shape (n_samples)
The target variable to fit LARS on
X_test : array, shape (n_samples, n_features)
The data to compute the residues on
y_test : array, shape (n_samples)
The target variable to compute the residues on
copy : boolean, optional
Whether X_train, X_test, y_train and y_test should be copied. If
False, they may be overwritten.
fit_intercept : boolean
whether to calculate the intercept for this model. If set
to false, no intercept will be used in calculations
(e.g. data is expected to be already centered).
normalize : boolean, optional, default False
If True, the regressors X will be normalized before regression.
This parameter is ignored when `fit_intercept` is set to `False`.
When the regressors are normalized, note that this makes the
hyperparameters learnt more robust and almost independent of the number
of samples. The same property is not valid for standardized data.
However, if you wish to standardize, please use
`preprocessing.StandardScaler` before calling `fit` on an estimator
with `normalize=False`.
max_iter : integer, optional
Maximum numbers of iterations to perform, therefore maximum features
to include. 100 by default.
Returns
-------
2013-07-25 21:42:19 +08:00
residues: array, 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(LinearModel, RegressorMixin):
2015-01-16 04:09:35 +08:00
"""Cross-validated Orthogonal Matching Pursuit model (OMP)
Parameters
----------
copy : bool, optional
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 : boolean, optional
whether to calculate the intercept for this model. If set
to false, no intercept will be used in calculations
(e.g. data is expected to be already centered).
normalize : boolean, optional, default False
If True, the regressors X will be normalized before regression.
This parameter is ignored when `fit_intercept` is set to `False`.
When the regressors are normalized, note that this makes the
hyperparameters learnt more robust and almost independent of the number
of samples. The same property is not valid for standardized data.
However, if you wish to standardize, please use
`preprocessing.StandardScaler` before calling `fit` on an estimator
with `normalize=False`.
max_iter : integer, optional
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 an iterable, optional
Determines the cross-validation splitting strategy.
Possible inputs for cv are:
2015-11-05 08:21:50 +08:00
- None, to use the default 3-fold cross-validation,
- integer, to specify the number of folds.
- An object to be used as a cross-validation generator.
- An iterable yielding train/test splits.
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.
n_jobs : integer, optional
Number of CPUs to use during the cross validation. If ``-1``, use
all the CPUs
verbose : boolean or integer, optional
Sets the verbosity amount
2015-06-03 12:24:04 +08:00
Read more in the :ref:`User Guide <omp>`.
Attributes
----------
intercept_ : float or array, shape (n_targets,)
Independent term in decision function.
coef_ : array, shape (n_features,) or (n_features, n_targets)
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.
See also
--------
orthogonal_mp
orthogonal_mp_gram
lars_path
Lars
LassoLars
OrthogonalMatchingPursuit
LarsCV
LassoLarsCV
decomposition.sparse_encode
"""
def __init__(self, copy=True, fit_intercept=True, normalize=True,
max_iter=None, cv=None, n_jobs=1, 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
----------
2013-07-25 21:42:19 +08:00
X : array-like, shape [n_samples, n_features]
Training data.
2013-07-25 21:42:19 +08:00
y : array-like, shape [n_samples]
Target values.
Returns
-------
self : object
returns an instance of self.
"""
X, y = check_X_y(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