Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
649d858
add inverse transform and update tests
rflamary Dec 9, 2024
c2e295a
Merge branch 'scikit-learn:main' into invers_transform_dl
rflamary Dec 9, 2024
9949d1f
Merge branch 'main' into invers_transform_dl
rflamary Dec 9, 2024
0670501
add whats new
rflamary Dec 9, 2024
76f7cba
Merge branch 'invers_transform_dl' of github.com:rflamary/scikit-lear…
rflamary Dec 9, 2024
fbb8986
fix test
rflamary Dec 9, 2024
5a77b55
add split sign test
rflamary Dec 9, 2024
4ee03d3
Merge branch 'main' into invers_transform_dl
rflamary Dec 9, 2024
3890d40
make test better
rflamary Dec 9, 2024
a63120e
Merge branch 'invers_transform_dl' of github.com:rflamary/scikit-lear…
rflamary Dec 9, 2024
e2c0491
Merge branch 'main' into invers_transform_dl
rflamary Dec 10, 2024
714ffd6
Merge branch 'main' into invers_transform_dl
rflamary Dec 12, 2024
b2fa0c0
Merge branch 'main' into invers_transform_dl
rflamary Dec 12, 2024
c176288
change whatsnew
rflamary Dec 12, 2024
3f7fbfa
add awhatsnew
rflamary Dec 12, 2024
c6522ea
add method to SparseCoder and test it
rflamary Dec 12, 2024
ff5c489
Merge branch 'main' into invers_transform_dl
rflamary Dec 12, 2024
f345498
Update sklearn/decomposition/_dict_learning.py
rflamary Dec 12, 2024
2172b97
Update sklearn/decomposition/_dict_learning.py
rflamary Dec 12, 2024
87b57fa
Update sklearn/decomposition/_dict_learning.py
rflamary Dec 12, 2024
a852863
Apply suggestions from code review
rflamary Dec 12, 2024
cb9bdd7
add cjeck_array
rflamary Dec 12, 2024
43cbf0e
add check + test
rflamary Dec 12, 2024
503398c
fix shape
rflamary Dec 12, 2024
8b8827e
Merge branch 'main' into invers_transform_dl
rflamary Dec 12, 2024
238594a
Update sklearn/decomposition/_dict_learning.py
rflamary Dec 12, 2024
30596f8
better name
rflamary Dec 12, 2024
f963516
Merge branch 'invers_transform_dl' of github.com:rflamary/scikit-lear…
rflamary Dec 12, 2024
f2aeca0
add matching for test
rflamary Dec 13, 2024
1a1a69e
Merge branch 'main' into invers_transform_dl
rflamary Dec 16, 2024
e072b70
Merge branch 'main' into invers_transform_dl
rflamary Dec 17, 2024
ce8ff50
Merge branch 'main' into invers_transform_dl
rflamary Dec 18, 2024
f36eeee
Merge branch 'main' into invers_transform_dl
rflamary Dec 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- :class:`~sklearn.decomposition.DictionaryLearning`,
:class:`~sklearn.decomposition.SparseCoder` and
:class:`~sklearn.decomposition.MiniBatchDictionaryLearning` now have a
``inverse_transform`` method. By :user:`Rémi Flamary <rflamary>`
54 changes: 54 additions & 0 deletions sklearn/decomposition/_dict_learning.py
Original file line number Diff line number Diff line change
Expand Up @@ -1142,6 +1142,44 @@ def transform(self, X):
check_is_fitted(self)
return self._transform(X, self.components_)

def _inverse_transform(self, code, dictionary):
"""Private method allowing to accommodate both DictionaryLearning and
SparseCoder."""
code = check_array(code)
# compute number of expected features in code
expected_n_components = dictionary.shape[0]
if self.split_sign:
expected_n_components += expected_n_components
if not code.shape[1] == expected_n_components:
raise ValueError(
"The number of components in the code is different from the "
"number of components in the dictionary."
f"Expected {expected_n_components}, got {code.shape[1]}."
)
if self.split_sign:
n_samples, n_features = code.shape
n_features //= 2
code = code[:, :n_features] - code[:, n_features:]

return code @ dictionary

def inverse_transform(self, X):
"""Transform data back to its original space.

Parameters
----------
X : array-like of shape (n_samples, n_components)
Data to be transformed back. Must have the same number of
components as the data used to train the model.

Returns
-------
X_new : ndarray of shape (n_samples, n_features)
Transformed data.
"""
check_is_fitted(self)
return self._inverse_transform(X, self.components_)


class SparseCoder(_BaseSparseCoding, BaseEstimator):
"""Sparse coding.
Expand Down Expand Up @@ -1329,6 +1367,22 @@ def transform(self, X, y=None):
"""
return super()._transform(X, self.dictionary)

def inverse_transform(self, X):
"""Transform data back to its original space.

Parameters
----------
X : array-like of shape (n_samples, n_components)
Data to be transformed back. Must have the same number of
components as the data used to train the model.

Returns
-------
X_new : ndarray of shape (n_samples, n_features)
Transformed data.
"""
return self._inverse_transform(X, self.dictionary)

def __sklearn_tags__(self):
tags = super().__sklearn_tags__()
tags.requires_fit = False
Expand Down
20 changes: 17 additions & 3 deletions sklearn/decomposition/tests/test_dict_learning.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,10 +202,16 @@ def test_dict_learning_reconstruction():
)
code = dico.fit(X).transform(X)
assert_array_almost_equal(np.dot(code, dico.components_), X)
assert_array_almost_equal(dico.inverse_transform(code), X)

dico.set_params(transform_algorithm="lasso_lars")
code = dico.transform(X)
assert_array_almost_equal(np.dot(code, dico.components_), X, decimal=2)
assert_array_almost_equal(dico.inverse_transform(code), X, decimal=2)

# test error raised for wrong code size
with pytest.raises(ValueError, match="Expected 12, got 11."):
dico.inverse_transform(code[:, :-1])

# used to test lars here too, but there's no guarantee the number of
# nonzero atoms is right.
Expand Down Expand Up @@ -268,13 +274,18 @@ def test_dict_learning_split():
n_components, transform_algorithm="threshold", random_state=0
)
code = dico.fit(X).transform(X)
Xr = dico.inverse_transform(code)

dico.split_sign = True
split_code = dico.transform(X)

assert_array_almost_equal(
split_code[:, :n_components] - split_code[:, n_components:], code
)

Xr2 = dico.inverse_transform(split_code)
assert_array_almost_equal(Xr, Xr2)


def test_dict_learning_online_shapes():
rng = np.random.RandomState(0)
Expand Down Expand Up @@ -591,9 +602,12 @@ def test_sparse_coder_estimator():
V /= np.sum(V**2, axis=1)[:, np.newaxis]
coder = SparseCoder(
dictionary=V, transform_algorithm="lasso_lars", transform_alpha=0.001
).transform(X)
assert not np.all(coder == 0)
assert np.sqrt(np.sum((np.dot(coder, V) - X) ** 2)) < 0.1
)
code = coder.fit_transform(X)
Xr = coder.inverse_transform(code)
assert not np.all(code == 0)
assert np.sqrt(np.sum((np.dot(code, V) - X) ** 2)) < 0.1
np.testing.assert_allclose(Xr, np.dot(code, V))


def test_sparse_coder_estimator_clone():
Expand Down
Loading