2011-08-03 22:59:30 +08:00
|
|
|
"""Orthogonal matching pursuit algorithms
|
2011-07-25 18:57:42 +08:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
# Author: Vlad Niculae
|
|
|
|
|
#
|
2013-04-30 14:23:46 +08:00
|
|
|
# License: BSD 3 clause
|
2011-07-25 18:57:42 +08:00
|
|
|
|
2012-05-06 01:59:03 +08:00
|
|
|
import warnings
|
2017-11-17 05:42:47 +08:00
|
|
|
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
|
2011-07-30 06:03:26 +08:00
|
|
|
from scipy.linalg.lapack import get_lapack_funcs
|
2020-09-21 22:59:42 +08:00
|
|
|
from joblib import Parallel
|
2011-07-25 18:57:42 +08:00
|
|
|
|
2021-06-18 05:24:40 +08:00
|
|
|
from ._base import LinearModel, _pre_fit, _deprecate_normalize
|
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
|
2020-09-21 22:59:42 +08:00
|
|
|
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
|
|
|
|
2021-03-12 22:46:50 +08:00
|
|
|
premature = (
|
|
|
|
|
"Orthogonal matching pursuit ended prematurely due to linear"
|
|
|
|
|
" dependence in the dictionary. The requested precision might"
|
|
|
|
|
" not have been met."
|
|
|
|
|
)
|
2011-08-02 05:40:05 +08:00
|
|
|
|
|
|
|
|
|
2012-08-19 19:02:11 +08:00
|
|
|
def _cholesky_omp(X, y, n_nonzero_coefs, tol=None, copy_X=True, return_path=False):
|
2011-08-08 21:12:32 +08:00
|
|
|
"""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
|
|
|
|
|
----------
|
2020-08-06 18:05:46 +08:00
|
|
|
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.
|
|
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
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
|
2020-08-06 18:05:46 +08:00
|
|
|
Targeted number of non-zero elements.
|
2011-07-25 18:57:42 +08:00
|
|
|
|
2020-08-06 18:05:46 +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
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
copy_X : bool, default=True
|
2011-09-21 18:40:22 +08:00
|
|
|
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
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
return_path : bool, default=False
|
2012-08-19 19:02:11 +08:00
|
|
|
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
|
|
|
|
|
-------
|
2020-08-06 18:05:46 +08:00
|
|
|
gamma : ndarray of shape (n_nonzero_coefs,)
|
|
|
|
|
Non-zero elements of the solution.
|
2011-07-25 18:57:42 +08:00
|
|
|
|
2020-08-06 18:05:46 +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
|
2020-08-06 18:05:46 +08:00
|
|
|
vector.
|
2011-07-25 18:57:42 +08:00
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
coef : ndarray of shape (n_features, n_nonzero_coefs)
|
2012-08-19 19:02:11 +08:00
|
|
|
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
|
|
|
"""
|
2011-09-21 18:40:22 +08:00
|
|
|
if copy_X:
|
2011-08-03 17:52:57 +08:00
|
|
|
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
|
2011-08-03 17:52:57 +08:00
|
|
|
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
|
2012-01-09 06:39:03 +08:00
|
|
|
gamma = np.empty(0)
|
2011-07-30 05:24:34 +08:00
|
|
|
n_active = 0
|
2012-03-16 04:35:42 +08:00
|
|
|
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
|
2018-02-28 06:00:34 +08:00
|
|
|
|
|
|
|
|
L = np.empty((max_features, max_features), dtype=X.dtype)
|
2015-03-18 09:54:51 +08:00
|
|
|
|
2012-08-19 19:02:11 +08:00
|
|
|
if return_path:
|
|
|
|
|
coefs = np.empty_like(L)
|
2011-07-30 05:24:34 +08:00
|
|
|
|
2011-08-08 21:12:32 +08:00
|
|
|
while True:
|
2011-08-02 23:00:20 +08:00
|
|
|
lam = np.argmax(np.abs(np.dot(X.T, residual)))
|
2011-08-03 17:52:57 +08:00
|
|
|
if lam < n_active or alpha[lam] ** 2 < min_float:
|
2011-07-30 19:33:41 +08:00
|
|
|
# atom already selected or inner product too small
|
2012-05-06 01:59:03 +08:00
|
|
|
warnings.warn(premature, RuntimeWarning, stacklevel=2)
|
2011-07-30 19:33:41 +08:00
|
|
|
break
|
2017-11-17 05:42:47 +08:00
|
|
|
|
2011-07-30 07:00:16 +08:00
|
|
|
if n_active > 0:
|
2011-07-30 19:33:41 +08:00
|
|
|
# Updates the Cholesky decomposition of X' X
|
2011-08-03 17:52:57 +08:00
|
|
|
L[n_active, :n_active] = np.dot(X[:, :n_active].T, X[:, lam])
|
2014-03-04 03:24:18 +08:00
|
|
|
linalg.solve_triangular(
|
|
|
|
|
L[:n_active, :n_active],
|
|
|
|
|
L[n_active, :n_active],
|
|
|
|
|
trans=0,
|
|
|
|
|
lower=1,
|
|
|
|
|
overwrite_b=True,
|
2018-02-28 06:00:34 +08:00
|
|
|
check_finite=False,
|
|
|
|
|
)
|
2011-08-08 01:39:56 +08:00
|
|
|
v = nrm2(L[n_active, :n_active]) ** 2
|
2017-11-17 05:42:47 +08:00
|
|
|
Lkk = linalg.norm(X[:, lam]) ** 2 - v
|
|
|
|
|
if Lkk <= min_float: # selected atoms are dependent
|
2012-05-06 01:59:03 +08:00
|
|
|
warnings.warn(premature, RuntimeWarning, stacklevel=2)
|
2011-07-30 19:33:41 +08:00
|
|
|
break
|
2017-11-17 05:42:47 +08:00
|
|
|
L[n_active, n_active] = sqrt(Lkk)
|
|
|
|
|
else:
|
|
|
|
|
L[0, 0] = linalg.norm(X[:, lam])
|
|
|
|
|
|
2011-08-03 17:52:57 +08:00
|
|
|
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]
|
2011-10-20 03:45:54 +08:00
|
|
|
indices[n_active], indices[lam] = indices[lam], indices[n_active]
|
2011-07-30 05:24:34 +08:00
|
|
|
n_active += 1
|
2017-11-17 05:42:47 +08:00
|
|
|
|
|
|
|
|
# solves LL'x = X'y as a composition of two triangular systems
|
2011-08-03 17:52:57 +08:00
|
|
|
gamma, _ = potrs(
|
|
|
|
|
L[:n_active, :n_active], alpha[:n_active], lower=True, overwrite_b=False
|
2011-07-30 07:00:16 +08:00
|
|
|
)
|
2017-11-17 05:42:47 +08:00
|
|
|
|
2012-08-19 19:02:11 +08:00
|
|
|
if return_path:
|
|
|
|
|
coefs[:n_active, n_active - 1] = gamma
|
2011-08-03 17:52:57 +08:00
|
|
|
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
|
|
|
|
|
|
2012-08-19 19:02:11 +08:00
|
|
|
if return_path:
|
2014-07-21 07:03:46 +08:00
|
|
|
return gamma, indices[:n_active], coefs[:, :n_active], n_active
|
2012-08-19 19:02:11 +08:00
|
|
|
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,
|
2012-08-19 19:02:11 +08:00
|
|
|
copy_Gram=True,
|
|
|
|
|
copy_Xy=True,
|
|
|
|
|
return_path=False,
|
|
|
|
|
):
|
2011-08-08 21:12:32 +08:00
|
|
|
"""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
|
|
|
|
|
----------
|
2020-08-06 18:05:46 +08:00
|
|
|
Gram : ndarray of shape (n_features, n_features)
|
|
|
|
|
Gram matrix of the input data matrix.
|
2011-07-25 18:57:42 +08:00
|
|
|
|
2020-08-06 18:05:46 +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
|
2020-08-06 18:05:46 +08:00
|
|
|
Targeted number of non-zero elements.
|
2011-07-25 18:57:42 +08:00
|
|
|
|
2020-08-06 18:05:46 +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
|
|
|
|
2020-08-06 18:05:46 +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
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
copy_Gram : bool, default=True
|
2011-09-21 18:40:22 +08:00
|
|
|
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
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
copy_Xy : bool, default=True
|
2011-09-21 18:40:22 +08:00
|
|
|
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
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
return_path : bool, default=False
|
2012-08-19 19:02:11 +08:00
|
|
|
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
|
|
|
|
|
-------
|
2020-08-06 18:05:46 +08:00
|
|
|
gamma : ndarray of shape (n_nonzero_coefs,)
|
|
|
|
|
Non-zero elements of the solution.
|
2011-07-25 18:57:42 +08:00
|
|
|
|
2020-08-06 18:05:46 +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
|
2020-08-06 18:05:46 +08:00
|
|
|
vector.
|
2011-07-25 18:57:42 +08:00
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
coefs : ndarray of shape (n_features, n_nonzero_coefs)
|
2012-08-19 19:02:11 +08:00
|
|
|
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
|
|
|
"""
|
2011-09-21 18:40:22 +08:00
|
|
|
Gram = Gram.copy("F") if copy_Gram else np.asfortranarray(Gram)
|
2011-08-03 21:18:16 +08:00
|
|
|
|
2018-06-23 18:16:59 +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
|
|
|
|
2012-03-16 04:35:42 +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
|
2012-01-09 06:39:03 +08:00
|
|
|
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
|
2018-02-28 06:00:34 +08:00
|
|
|
|
|
|
|
|
L = np.empty((max_features, max_features), dtype=Gram.dtype)
|
|
|
|
|
|
2011-07-30 05:24:34 +08:00
|
|
|
L[0, 0] = 1.0
|
2012-08-19 19:02:11 +08:00
|
|
|
if return_path:
|
|
|
|
|
coefs = np.empty_like(L)
|
2011-07-30 05:24:34 +08:00
|
|
|
|
2011-08-08 21:12:32 +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:
|
2011-07-30 19:33:41 +08:00
|
|
|
# selected same atom twice, or inner product too small
|
2013-11-29 23:40:23 +08:00
|
|
|
warnings.warn(premature, RuntimeWarning, stacklevel=3)
|
2011-07-30 19:33:41 +08:00
|
|
|
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]
|
2014-03-04 03:24:18 +08:00
|
|
|
linalg.solve_triangular(
|
|
|
|
|
L[:n_active, :n_active],
|
|
|
|
|
L[n_active, :n_active],
|
|
|
|
|
trans=0,
|
|
|
|
|
lower=1,
|
|
|
|
|
overwrite_b=True,
|
2018-02-28 06:00:34 +08:00
|
|
|
check_finite=False,
|
|
|
|
|
)
|
2011-08-08 01:39:56 +08:00
|
|
|
v = nrm2(L[n_active, :n_active]) ** 2
|
2017-11-17 05:42:47 +08:00
|
|
|
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)
|
2011-07-30 19:33:41 +08:00
|
|
|
break
|
2017-11-17 05:42:47 +08:00
|
|
|
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])
|
2011-10-20 03:45:54 +08:00
|
|
|
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
|
2017-11-17 05:42:47 +08:00
|
|
|
# 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, overwrite_b=False
|
2011-07-30 07:00:16 +08:00
|
|
|
)
|
2012-08-19 19:02:11 +08:00
|
|
|
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
|
|
|
|
2012-08-19 19:02:11 +08:00
|
|
|
if return_path:
|
2014-07-21 07:03:46 +08:00
|
|
|
return gamma, indices[:n_active], coefs[:, :n_active], n_active
|
2012-08-19 19:02:11 +08:00
|
|
|
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
|
|
|
|
2020-04-20 04:58:47 +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,
|
|
|
|
|
):
|
2020-08-06 18:05:46 +08:00
|
|
|
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
|
|
|
|
|
----------
|
2020-08-06 18:05:46 +08:00
|
|
|
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
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
y : ndarray of shape (n_samples,) or (n_samples, n_targets)
|
|
|
|
|
Input targets.
|
2011-07-25 18:57:42 +08:00
|
|
|
|
2020-06-07 05:15:14 +08:00
|
|
|
n_nonzero_coefs : int, default=None
|
2011-08-08 21:12:32 +08:00
|
|
|
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
|
|
|
|
2020-06-07 05:15:14 +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
|
|
|
|
2020-08-06 18:05:46 +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.
|
|
|
|
|
|
2020-06-07 05:15:14 +08:00
|
|
|
copy_X : bool, default=True
|
2011-09-21 18:40:22 +08:00
|
|
|
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
|
|
|
|
2020-06-07 05:15:14 +08:00
|
|
|
return_path : bool, default=False
|
2012-08-19 19:02:11 +08:00
|
|
|
Whether to return every value of the nonzero coefficients along the
|
|
|
|
|
forward path. Useful for cross-validation.
|
|
|
|
|
|
2020-06-07 05:15:14 +08:00
|
|
|
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
|
|
|
|
|
-------
|
2020-08-06 18:05:46 +08:00
|
|
|
coef : ndarray of shape (n_features,) or (n_features, n_targets)
|
2012-08-19 19:02:11 +08:00
|
|
|
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
|
2022-02-17 00:05:01 +08:00
|
|
|
iterating over the last axis generates coefficients in increasing order
|
2012-08-19 19:02:11 +08:00
|
|
|
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.
|
|
|
|
|
|
2020-09-04 22:35:01 +08:00
|
|
|
See Also
|
2011-07-25 18:57:42 +08:00
|
|
|
--------
|
2022-02-17 00:05:01 +08:00
|
|
|
OrthogonalMatchingPursuit : Orthogonal Matching Pursuit model.
|
|
|
|
|
orthogonal_mp_gram : Solve OMP problems using Gram matrix and the product X.T * y.
|
|
|
|
|
lars_path : Compute Least Angle Regression or Lasso path using LARS algorithm.
|
|
|
|
|
sklearn.decomposition.sparse_encode : Sparse coding.
|
2011-07-25 18:57:42 +08:00
|
|
|
|
2011-08-03 22:59:30 +08:00
|
|
|
Notes
|
|
|
|
|
-----
|
2016-10-23 16:54:58 +08:00
|
|
|
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.
|
2018-10-06 00:50:31 +08:00
|
|
|
https://www.cs.technion.ac.il/~ronrubin/Publications/KSVD-OMP-v2.pdf
|
2011-07-25 18:57:42 +08:00
|
|
|
"""
|
2014-07-20 19:31:45 +08:00
|
|
|
X = check_array(X, order="F", copy=copy_X)
|
2012-08-26 03:37:32 +08:00
|
|
|
copy_X = False
|
2011-07-25 18:57:42 +08:00
|
|
|
if y.ndim == 1:
|
2014-07-20 19:31:45 +08:00
|
|
|
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
|
2011-09-21 18:40:22 +08:00
|
|
|
copy_X = True
|
2012-12-22 20:02:50 +08:00
|
|
|
if n_nonzero_coefs is None and tol is None:
|
2012-11-10 23:53:50 +08:00
|
|
|
# default for n_nonzero_coefs is 0.1 * n_features
|
|
|
|
|
# but at least one.
|
2012-11-02 01:40:48 +08:00
|
|
|
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)
|
2011-08-04 01:21:02 +08:00
|
|
|
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
|
2020-04-20 04:58:47 +08:00
|
|
|
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
|
|
|
|
2012-08-19 19:02:11 +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 = []
|
2012-08-19 19:02:11 +08:00
|
|
|
|
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(
|
2015-03-18 09:54:51 +08:00
|
|
|
X, y[:, k], n_nonzero_coefs, tol, copy_X=copy_X, return_path=return_path
|
|
|
|
|
)
|
2012-08-19 19:02:11 +08:00
|
|
|
if return_path:
|
2014-07-21 07:03:46 +08:00
|
|
|
_, idx, coefs, n_iter = out
|
2012-08-19 19:02:11 +08:00
|
|
|
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
|
2012-08-19 19:02:11 +08:00
|
|
|
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
|
|
|
|
|
|
|
|
|
2020-04-20 04:58:47 +08:00
|
|
|
def orthogonal_mp_gram(
|
|
|
|
|
Gram,
|
|
|
|
|
Xy,
|
|
|
|
|
*,
|
|
|
|
|
n_nonzero_coefs=None,
|
|
|
|
|
tol=None,
|
2011-09-21 18:40:22 +08:00
|
|
|
norms_squared=None,
|
|
|
|
|
copy_Gram=True,
|
2014-07-21 07:03:46 +08:00
|
|
|
copy_Xy=True,
|
|
|
|
|
return_path=False,
|
|
|
|
|
return_n_iter=False,
|
|
|
|
|
):
|
2020-08-06 18:05:46 +08:00
|
|
|
"""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
|
|
|
|
|
----------
|
2020-08-06 18:05:46 +08:00
|
|
|
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
|
|
|
|
2020-08-06 18:05:46 +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
|
|
|
|
2020-06-07 05:15:14 +08:00
|
|
|
n_nonzero_coefs : int, default=None
|
2011-08-08 21:12:32 +08:00
|
|
|
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
|
|
|
|
2020-06-07 05:15:14 +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
|
|
|
|
2020-08-06 18:05:46 +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
|
|
|
|
2020-06-07 05:15:14 +08:00
|
|
|
copy_Gram : bool, default=True
|
2011-09-21 18:40:22 +08:00
|
|
|
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
|
|
|
|
2020-06-07 05:15:14 +08:00
|
|
|
copy_Xy : bool, default=True
|
2011-09-21 18:40:22 +08:00
|
|
|
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
|
|
|
|
2020-06-07 05:15:14 +08:00
|
|
|
return_path : bool, default=False
|
2012-08-19 19:02:11 +08:00
|
|
|
Whether to return every value of the nonzero coefficients along the
|
|
|
|
|
forward path. Useful for cross-validation.
|
|
|
|
|
|
2020-06-07 05:15:14 +08:00
|
|
|
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
|
|
|
|
|
-------
|
2020-08-06 18:05:46 +08:00
|
|
|
coef : ndarray of shape (n_features,) or (n_features, n_targets)
|
2012-08-19 19:02:11 +08:00
|
|
|
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.
|
|
|
|
|
|
2020-09-04 22:35:01 +08:00
|
|
|
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
|
2020-09-04 22:35:01 +08:00
|
|
|
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.
|
2018-10-06 00:50:31 +08:00
|
|
|
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
|
|
|
"""
|
2014-07-20 19:31:45 +08:00
|
|
|
Gram = check_array(Gram, order="F", copy=copy_Gram)
|
2011-10-21 18:42:02 +08:00
|
|
|
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
|
2012-08-26 03:37:32 +08:00
|
|
|
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:
|
2011-07-30 06:03:26 +08:00
|
|
|
norms_squared = [norms_squared]
|
2018-06-23 18:16:59 +08:00
|
|
|
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 of features"
|
2012-12-22 20:02:50 +08:00
|
|
|
)
|
2012-08-19 19:02:11 +08:00
|
|
|
|
|
|
|
|
if return_path:
|
2021-12-30 19:16:41 +08:00
|
|
|
coef = np.zeros((len(Gram), Xy.shape[1], len(Gram)), dtype=Gram.dtype)
|
2012-08-19 19:02:11 +08:00
|
|
|
else:
|
2021-12-30 19:16:41 +08:00
|
|
|
coef = np.zeros((len(Gram), Xy.shape[1]), dtype=Gram.dtype)
|
2012-08-19 19:02:11 +08:00
|
|
|
|
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,
|
2018-06-23 18:16:59 +08:00
|
|
|
copy_Gram=copy_Gram,
|
|
|
|
|
copy_Xy=False,
|
2015-03-18 09:54:51 +08:00
|
|
|
return_path=return_path,
|
|
|
|
|
)
|
2012-08-19 19:02:11 +08:00
|
|
|
if return_path:
|
2014-07-21 07:03:46 +08:00
|
|
|
_, idx, coefs, n_iter = out
|
2012-08-19 19:02:11 +08:00
|
|
|
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
|
2012-08-19 19:02:11 +08:00
|
|
|
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]
|
2012-08-19 19:02:11 +08:00
|
|
|
|
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
|
|
|
|
|
|
|
|
|
2019-09-05 16:13:30 +08:00
|
|
|
class OrthogonalMatchingPursuit(MultiOutputMixin, RegressorMixin, LinearModel):
|
2020-08-06 18:05:46 +08:00
|
|
|
"""Orthogonal Matching Pursuit model (OMP).
|
2011-07-29 07:54:23 +08:00
|
|
|
|
2017-07-12 00:42:10 +08:00
|
|
|
Read more in the :ref:`User Guide <omp>`.
|
|
|
|
|
|
2011-07-29 07:54:23 +08:00
|
|
|
Parameters
|
|
|
|
|
----------
|
2020-06-07 05:15:14 +08:00
|
|
|
n_nonzero_coefs : int, default=None
|
2011-08-08 21:12:32 +08:00
|
|
|
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
|
|
|
|
2020-06-07 05:15:14 +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.
|
|
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
fit_intercept : bool, default=True
|
2021-10-20 23:24:56 +08:00
|
|
|
Whether to calculate the intercept for this model. If set
|
2011-07-29 07:54:23 +08:00
|
|
|
to false, no intercept will be used in calculations
|
2019-08-08 07:18:43 +08:00
|
|
|
(i.e. data is expected to be centered).
|
2011-07-29 07:55:48 +08:00
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
normalize : bool, default=True
|
2017-03-30 17:19:21 +08:00
|
|
|
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
|
2020-06-16 16:44:13 +08:00
|
|
|
:class:`~sklearn.preprocessing.StandardScaler` before calling ``fit``
|
2017-03-30 17:19:21 +08:00
|
|
|
on an estimator with ``normalize=False``.
|
2011-07-29 07:54:23 +08:00
|
|
|
|
2021-06-18 05:24:40 +08:00
|
|
|
.. deprecated:: 1.0
|
|
|
|
|
``normalize`` was deprecated in version 1.0. It will default
|
|
|
|
|
to False in 1.2 and be removed in 1.4.
|
|
|
|
|
|
2020-08-06 18:05:46 +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
|
2019-09-05 17:37:05 +08:00
|
|
|
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
|
|
|
|
|
----------
|
2020-08-06 18:05:46 +08:00
|
|
|
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
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
intercept_ : float or ndarray of shape (n_targets,)
|
|
|
|
|
Independent term in decision function.
|
2011-07-29 07:54:23 +08:00
|
|
|
|
2014-07-28 17:04:59 +08:00
|
|
|
n_iter_ : int or array-like
|
2014-07-21 07:03:46 +08:00
|
|
|
Number of active features across every target.
|
|
|
|
|
|
2020-11-05 22:11:04 +08:00
|
|
|
n_nonzero_coefs_ : int
|
|
|
|
|
The number of non-zero coefficients in the solution. If
|
|
|
|
|
`n_nonzero_coefs` is None and `tol` is None this value is either set
|
|
|
|
|
to 10% of `n_features` or 1, whichever is greater.
|
|
|
|
|
|
2021-06-09 22:58:03 +08:00
|
|
|
n_features_in_ : int
|
|
|
|
|
Number of features seen during :term:`fit`.
|
|
|
|
|
|
|
|
|
|
.. versionadded:: 0.24
|
|
|
|
|
|
2021-08-26 19:44:45 +08:00
|
|
|
feature_names_in_ : ndarray of shape (`n_features_in_`,)
|
|
|
|
|
Names of features seen during :term:`fit`. Defined only when `X`
|
|
|
|
|
has feature names that are all strings.
|
|
|
|
|
|
|
|
|
|
.. versionadded:: 1.0
|
|
|
|
|
|
2021-10-20 23:24:56 +08:00
|
|
|
See Also
|
2018-09-12 15:47:42 +08:00
|
|
|
--------
|
2021-10-20 23:24:56 +08:00
|
|
|
orthogonal_mp : Solves n_targets Orthogonal Matching Pursuit problems.
|
|
|
|
|
orthogonal_mp_gram : Solves n_targets Orthogonal Matching Pursuit
|
|
|
|
|
problems using only the Gram matrix X.T * X and the product X.T * y.
|
|
|
|
|
lars_path : Compute Least Angle Regression or Lasso path using LARS algorithm.
|
|
|
|
|
Lars : Least Angle Regression model a.k.a. LAR.
|
|
|
|
|
LassoLars : Lasso model fit with Least Angle Regression a.k.a. Lars.
|
|
|
|
|
sklearn.decomposition.sparse_encode : Generic sparse coding.
|
|
|
|
|
Each column of the result is the solution to a Lasso problem.
|
|
|
|
|
OrthogonalMatchingPursuitCV : Cross-validated
|
|
|
|
|
Orthogonal Matching Pursuit model (OMP).
|
2018-09-12 15:47: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.
|
2018-10-06 00:50:31 +08:00
|
|
|
https://www.cs.technion.ac.il/~ronrubin/Publications/KSVD-OMP-v2.pdf
|
2011-08-03 22:59:30 +08:00
|
|
|
|
2021-10-20 23:24:56 +08:00
|
|
|
Examples
|
2011-08-03 22:59:30 +08:00
|
|
|
--------
|
2021-10-20 23:24:56 +08:00
|
|
|
>>> from sklearn.linear_model import OrthogonalMatchingPursuit
|
|
|
|
|
>>> from sklearn.datasets import make_regression
|
|
|
|
|
>>> X, y = make_regression(noise=4, random_state=0)
|
|
|
|
|
>>> reg = OrthogonalMatchingPursuit(normalize=False).fit(X, y)
|
|
|
|
|
>>> reg.score(X, y)
|
|
|
|
|
0.9991...
|
|
|
|
|
>>> reg.predict(X[:1,])
|
|
|
|
|
array([-78.3854...])
|
2011-07-29 07:54:23 +08:00
|
|
|
"""
|
2021-06-18 02:21:09 +08:00
|
|
|
|
2020-04-20 04:58:47 +08:00
|
|
|
def __init__(
|
|
|
|
|
self,
|
|
|
|
|
*,
|
|
|
|
|
n_nonzero_coefs=None,
|
|
|
|
|
tol=None,
|
|
|
|
|
fit_intercept=True,
|
2021-06-18 05:24:40 +08:00
|
|
|
normalize="deprecated",
|
2014-07-17 16:47:07 +08:00
|
|
|
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
|
2013-07-26 00:32:22 +08:00
|
|
|
self.precompute = precompute
|
2011-07-29 07:54:23 +08:00
|
|
|
|
2014-07-17 17:23:28 +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
|
|
|
|
|
----------
|
2020-08-06 18:05:46 +08:00
|
|
|
X : array-like of shape (n_samples, n_features)
|
2011-07-29 07:54:23 +08:00
|
|
|
Training data.
|
|
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
y : array-like of shape (n_samples,) or (n_samples, n_targets)
|
2021-10-20 23:24:56 +08:00
|
|
|
Target values. Will be cast to X's dtype if necessary.
|
2011-07-29 07:54:23 +08:00
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
2014-12-01 09:59:42 +08:00
|
|
|
self : object
|
2021-10-20 23:24:56 +08:00
|
|
|
Returns an instance of self.
|
2011-07-29 07:54:23 +08:00
|
|
|
"""
|
2021-06-18 05:24:40 +08:00
|
|
|
_normalize = _deprecate_normalize(
|
|
|
|
|
self.normalize, default=True, estimator_name=self.__class__.__name__
|
|
|
|
|
)
|
|
|
|
|
|
2020-02-29 22:05:11 +08:00
|
|
|
X, y = self._validate_data(X, y, multi_output=True, y_numeric=True)
|
2011-08-10 23:12:17 +08:00
|
|
|
n_features = X.shape[1]
|
2011-07-29 07:54:23 +08:00
|
|
|
|
2015-10-19 21:59:59 +08:00
|
|
|
X, y, X_offset, y_offset, X_scale, Gram, Xy = _pre_fit(
|
2021-06-18 05:24:40 +08:00
|
|
|
X, y, None, self.precompute, _normalize, self.fit_intercept, copy=True
|
2014-07-17 23:32:19 +08:00
|
|
|
)
|
2011-08-08 21:12:32 +08:00
|
|
|
|
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:
|
2012-11-10 23:53:50 +08:00
|
|
|
# default for n_nonzero_coefs is 0.1 * n_features
|
|
|
|
|
# but at least one.
|
2013-02-10 22:39:23 +08:00
|
|
|
self.n_nonzero_coefs_ = max(int(0.1 * n_features), 1)
|
|
|
|
|
else:
|
|
|
|
|
self.n_nonzero_coefs_ = self.n_nonzero_coefs
|
2011-08-08 21:12:32 +08:00
|
|
|
|
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(
|
2020-04-20 04:58:47 +08:00
|
|
|
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-17 23:32:19 +08:00
|
|
|
|
2014-07-21 07:03:46 +08:00
|
|
|
coef_, self.n_iter_ = orthogonal_mp_gram(
|
2014-07-17 23:32:19 +08:00
|
|
|
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
|
2015-10-19 21:59:59 +08:00
|
|
|
self._set_intercept(X_offset, y_offset, X_scale)
|
2011-07-29 07:54:23 +08:00
|
|
|
return self
|
2013-07-25 02:00:10 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def _omp_path_residues(
|
|
|
|
|
X_train,
|
|
|
|
|
y_train,
|
|
|
|
|
X_test,
|
|
|
|
|
y_test,
|
|
|
|
|
copy=True,
|
|
|
|
|
fit_intercept=True,
|
|
|
|
|
normalize=True,
|
|
|
|
|
max_iter=100,
|
|
|
|
|
):
|
2020-08-06 18:05:46 +08:00
|
|
|
"""Compute the residues on left-out data for a full LARS path.
|
2013-07-25 02:00:10 +08:00
|
|
|
|
|
|
|
|
Parameters
|
2019-05-05 22:05:58 +08:00
|
|
|
----------
|
2020-08-06 18:05:46 +08:00
|
|
|
X_train : ndarray of shape (n_samples, n_features)
|
|
|
|
|
The data to fit the LARS on.
|
2013-07-25 02:00:10 +08:00
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
y_train : ndarray of shape (n_samples)
|
|
|
|
|
The target variable to fit LARS on.
|
2013-07-25 02:00:10 +08:00
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
X_test : ndarray of shape (n_samples, n_features)
|
|
|
|
|
The data to compute the residues on.
|
2013-07-25 02:00:10 +08:00
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
y_test : ndarray of shape (n_samples)
|
|
|
|
|
The target variable to compute the residues on.
|
2013-07-25 02:00:10 +08:00
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
copy : bool, default=True
|
2013-07-25 02:00:10 +08:00
|
|
|
Whether X_train, X_test, y_train and y_test should be copied. If
|
|
|
|
|
False, they may be overwritten.
|
|
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
fit_intercept : bool, default=True
|
|
|
|
|
Whether to calculate the intercept for this model. If set
|
2013-07-25 02:00:10 +08:00
|
|
|
to false, no intercept will be used in calculations
|
2019-08-08 07:18:43 +08:00
|
|
|
(i.e. data is expected to be centered).
|
2013-07-25 02:00:10 +08:00
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
normalize : bool, default=True
|
2017-03-30 17:19:21 +08:00
|
|
|
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
|
2020-06-16 16:44:13 +08:00
|
|
|
:class:`~sklearn.preprocessing.StandardScaler` before calling ``fit``
|
2017-03-30 17:19:21 +08:00
|
|
|
on an estimator with ``normalize=False``.
|
2013-07-25 02:00:10 +08:00
|
|
|
|
2021-06-18 05:24:40 +08:00
|
|
|
.. deprecated:: 1.0
|
|
|
|
|
``normalize`` was deprecated in version 1.0. It will default
|
|
|
|
|
to False in 1.2 and be removed in 1.4.
|
|
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
max_iter : int, default=100
|
2013-07-25 02:00:10 +08:00
|
|
|
Maximum numbers of iterations to perform, therefore maximum features
|
|
|
|
|
to include. 100 by default.
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
2020-08-06 18:05:46 +08:00
|
|
|
residues : ndarray of shape (n_samples, max_features)
|
|
|
|
|
Residues of the prediction on the test data.
|
2013-07-25 02:00:10 +08:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
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,
|
2013-07-25 02:00:10 +08:00
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
2019-09-05 16:13:30 +08:00
|
|
|
class OrthogonalMatchingPursuitCV(RegressorMixin, LinearModel):
|
2018-10-04 21:43:47 +08:00
|
|
|
"""Cross-validated Orthogonal Matching Pursuit model (OMP).
|
|
|
|
|
|
|
|
|
|
See glossary entry for :term:`cross-validation estimator`.
|
2013-07-25 02:00:10 +08:00
|
|
|
|
2017-07-12 00:42:10 +08:00
|
|
|
Read more in the :ref:`User Guide <omp>`.
|
|
|
|
|
|
2013-07-25 02:00:10 +08:00
|
|
|
Parameters
|
|
|
|
|
----------
|
2020-08-06 18:05:46 +08:00
|
|
|
copy : bool, default=True
|
2013-07-25 02:00:10 +08:00
|
|
|
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.
|
|
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
fit_intercept : bool, default=True
|
2021-10-23 18:58:36 +08:00
|
|
|
Whether to calculate the intercept for this model. If set
|
2013-07-25 02:00:10 +08:00
|
|
|
to false, no intercept will be used in calculations
|
2019-08-08 07:18:43 +08:00
|
|
|
(i.e. data is expected to be centered).
|
2013-07-25 02:00:10 +08:00
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
normalize : bool, default=True
|
2017-03-30 17:19:21 +08:00
|
|
|
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
|
2020-06-16 16:44:13 +08:00
|
|
|
:class:`~sklearn.preprocessing.StandardScaler` before calling ``fit``
|
2017-03-30 17:19:21 +08:00
|
|
|
on an estimator with ``normalize=False``.
|
2013-07-25 02:00:10 +08:00
|
|
|
|
2021-06-18 05:24:40 +08:00
|
|
|
.. deprecated:: 1.0
|
|
|
|
|
``normalize`` was deprecated in version 1.0. It will default
|
|
|
|
|
to False in 1.2 and be removed in 1.4.
|
|
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
max_iter : int, default=None
|
2013-07-25 02:00:10 +08:00
|
|
|
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.
|
2013-07-25 02:00:10 +08:00
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
cv : int, cross-validation generator or iterable, default=None
|
2015-09-10 11:45:13 +08:00
|
|
|
Determines the cross-validation splitting strategy.
|
|
|
|
|
Possible inputs for cv are:
|
2015-11-05 08:21:50 +08:00
|
|
|
|
2019-05-29 21:39:20 +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.
|
2018-11-13 04:10:15 +08:00
|
|
|
- :term:`CV splitter`,
|
|
|
|
|
- An iterable yielding (train, test) splits as arrays of indices.
|
2015-09-10 11:45:13 +08:00
|
|
|
|
|
|
|
|
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.
|
2013-07-25 02:00:10 +08:00
|
|
|
|
2019-05-29 21:39:20 +08:00
|
|
|
.. versionchanged:: 0.22
|
|
|
|
|
``cv`` default value if None changed from 3-fold to 5-fold.
|
2018-07-19 20:46:11 +08:00
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
n_jobs : int, default=None
|
2018-08-18 17:57:10 +08:00
|
|
|
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.
|
2013-07-25 02:00:10 +08:00
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
verbose : bool or int, default=False
|
|
|
|
|
Sets the verbosity amount.
|
2013-07-25 02:00:10 +08:00
|
|
|
|
|
|
|
|
Attributes
|
|
|
|
|
----------
|
2020-08-06 18:05:46 +08:00
|
|
|
intercept_ : float or ndarray of shape (n_targets,)
|
2014-06-07 22:48:48 +08:00
|
|
|
Independent term in decision function.
|
2013-07-25 02:00:10 +08:00
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
coef_ : ndarray of shape (n_features,) or (n_targets, n_features)
|
2014-06-07 22:48:48 +08:00
|
|
|
Parameter vector (w in the problem formulation).
|
2013-07-25 02:00:10 +08:00
|
|
|
|
2014-07-28 17:04:59 +08:00
|
|
|
n_nonzero_coefs_ : int
|
2014-06-07 22:48:48 +08:00
|
|
|
Estimated number of non-zero coefficients giving the best mean squared
|
|
|
|
|
error over the cross-validation folds.
|
2013-07-25 02:00:10 +08:00
|
|
|
|
2014-07-28 17:04:59 +08:00
|
|
|
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.
|
|
|
|
|
|
2021-06-09 22:58:03 +08:00
|
|
|
n_features_in_ : int
|
|
|
|
|
Number of features seen during :term:`fit`.
|
|
|
|
|
|
|
|
|
|
.. versionadded:: 0.24
|
|
|
|
|
|
2021-08-26 19:44:45 +08:00
|
|
|
feature_names_in_ : ndarray of shape (`n_features_in_`,)
|
|
|
|
|
Names of features seen during :term:`fit`. Defined only when `X`
|
|
|
|
|
has feature names that are all strings.
|
|
|
|
|
|
|
|
|
|
.. versionadded:: 1.0
|
|
|
|
|
|
2021-10-23 18:58:36 +08:00
|
|
|
See Also
|
|
|
|
|
--------
|
|
|
|
|
orthogonal_mp : Solves n_targets Orthogonal Matching Pursuit problems.
|
|
|
|
|
orthogonal_mp_gram : Solves n_targets Orthogonal Matching Pursuit
|
|
|
|
|
problems using only the Gram matrix X.T * X and the product X.T * y.
|
|
|
|
|
lars_path : Compute Least Angle Regression or Lasso path using LARS algorithm.
|
|
|
|
|
Lars : Least Angle Regression model a.k.a. LAR.
|
|
|
|
|
LassoLars : Lasso model fit with Least Angle Regression a.k.a. Lars.
|
|
|
|
|
OrthogonalMatchingPursuit : Orthogonal Matching Pursuit model (OMP).
|
|
|
|
|
LarsCV : Cross-validated Least Angle Regression model.
|
|
|
|
|
LassoLarsCV : Cross-validated Lasso model fit with Least Angle Regression.
|
|
|
|
|
sklearn.decomposition.sparse_encode : Generic sparse coding.
|
|
|
|
|
Each column of the result is the solution to a Lasso problem.
|
|
|
|
|
|
2022-01-28 23:40:17 +08:00
|
|
|
Notes
|
|
|
|
|
-----
|
|
|
|
|
In `fit`, once the optimal number of non-zero coefficients is found through
|
|
|
|
|
cross-validation, the model is fit again using the entire training set.
|
|
|
|
|
|
2018-09-12 15:47:42 +08:00
|
|
|
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)
|
2021-06-18 05:24:40 +08:00
|
|
|
>>> reg = OrthogonalMatchingPursuitCV(cv=5, normalize=False).fit(X, y)
|
2019-06-01 16:53:45 +08:00
|
|
|
>>> reg.score(X, y)
|
2018-09-12 15:47:42 +08:00
|
|
|
0.9991...
|
|
|
|
|
>>> reg.n_nonzero_coefs_
|
|
|
|
|
10
|
|
|
|
|
>>> reg.predict(X[:1,])
|
|
|
|
|
array([-78.3854...])
|
2013-07-25 02:00:10 +08:00
|
|
|
"""
|
2021-06-18 02:21:09 +08:00
|
|
|
|
2020-04-20 04:58:47 +08:00
|
|
|
def __init__(
|
|
|
|
|
self,
|
|
|
|
|
*,
|
|
|
|
|
copy=True,
|
|
|
|
|
fit_intercept=True,
|
2021-06-18 05:24:40 +08:00
|
|
|
normalize="deprecated",
|
2019-05-29 21:39:20 +08:00
|
|
|
max_iter=None,
|
|
|
|
|
cv=None,
|
|
|
|
|
n_jobs=None,
|
|
|
|
|
verbose=False,
|
|
|
|
|
):
|
2013-07-25 02:00:10 +08:00
|
|
|
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
|
|
|
|
|
----------
|
2020-08-06 18:05:46 +08:00
|
|
|
X : array-like of shape (n_samples, n_features)
|
2013-07-25 02:00:10 +08:00
|
|
|
Training data.
|
|
|
|
|
|
2020-08-06 18:05:46 +08:00
|
|
|
y : array-like of shape (n_samples,)
|
|
|
|
|
Target values. Will be cast to X's dtype if necessary.
|
2013-07-25 02:00:10 +08:00
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
self : object
|
2021-10-23 18:58:36 +08:00
|
|
|
Returns an instance of self.
|
2013-07-25 02:00:10 +08:00
|
|
|
"""
|
2021-06-18 05:24:40 +08:00
|
|
|
|
|
|
|
|
_normalize = _deprecate_normalize(
|
|
|
|
|
self.normalize, default=True, estimator_name=self.__class__.__name__
|
|
|
|
|
)
|
|
|
|
|
|
2021-10-29 21:59:57 +08:00
|
|
|
X, y = self._validate_data(X, y, y_numeric=True, ensure_min_features=2)
|
2015-01-21 05:08:58 +08:00
|
|
|
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
|
2013-07-25 02:00:10 +08:00
|
|
|
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,
|
2021-06-18 05:24:40 +08:00
|
|
|
_normalize,
|
2013-07-25 02:00:10 +08:00
|
|
|
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)
|
2021-06-18 02:21:09 +08:00
|
|
|
)
|
2013-07-25 02:00:10 +08:00
|
|
|
|
|
|
|
|
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,
|
2021-06-18 05:24:40 +08:00
|
|
|
normalize=_normalize,
|
2013-07-25 02:00:10 +08:00
|
|
|
)
|
|
|
|
|
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_
|
2013-07-25 02:00:10 +08:00
|
|
|
return self
|