8000 ENH Adds get_feature_names to manifold module by thomasjpfan · Pull Request #22254 · scikit-learn/scikit-learn · GitHub
[go: up one dir, main page]

Skip to content

ENH Adds get_feature_names to manifold module #22254

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions doc/whats_new/v1.1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,9 @@ Changelog
preserve this dtype.
:pr:`21534` by :user:`Andrew Knyazev <lobpcg>`.

- |Enhancement| Adds `get_feature_names_out` to :class:`manifold.Isomap`
and :class:`manifold.LocallyLinearEmbedding`. :pr:`22254` by `Thomas Fan`_.

- |Fix| :func:`manifold.spectral_embedding` now uses Gaussian instead of
the previous uniform on [0, 1] random initial approximations to eigenvectors
in eigen_solvers `lobpcg` and `amg` to improve their numerical stability.
Expand Down
5 changes: 3 additions & 2 deletions sklearn/manifold/_isomap.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from scipy.sparse.csgraph import shortest_path
from scipy.sparse.csgraph import connected_components

from ..base import BaseEstimator, TransformerMixin
from ..base import BaseEstimator, TransformerMixin, _ClassNamePrefixFeaturesOutMixin
from ..neighbors import NearestNeighbors, kneighbors_graph
from ..utils.validation import check_is_fitted
from ..decomposition import KernelPCA
Expand All @@ -19,7 +19,7 @@
from ..externals._packaging.version import parse as parse_version


class Isomap(TransformerMixin, BaseEstimator):
class Isomap(_ClassNamePrefixFeaturesOutMixin, TransformerMixin, BaseEstimator):
"""Isomap Embedding.

Non-linear dimensionality reduction through Isometric Mapping
Expand Down Expand Up @@ -257,6 +257,7 @@ def _fit_transform(self, X):
G *= -0.5

self.embedding_ = self.kernel_pca_.fit_transform(G)
self._n_features_out = self.embedding_.shape[1]

def reconstruction_error(self):
"""Compute the reconstruction error for the embedding.
Expand Down
15 changes: 13 additions & 2 deletions sklearn/manifold/_locally_linear.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@
from scipy.sparse import eye, csr_matrix
from scipy.sparse.linalg import eigsh

from ..base import BaseEstimator, TransformerMixin, _UnstableArchMixin
from ..base import (
BaseEstimator,
TransformerMixin,
_UnstableArchMixin,
_ClassNamePrefixFeaturesOutMixin,
)
from ..utils import check_random_state, check_array
from ..utils._arpack import _init_arpack_v0
from ..utils.extmath import stable_cumsum
Expand Down Expand Up @@ -542,7 +547,12 @@ def locally_linear_embedding(
)


class LocallyLinearEmbedding(TransformerMixin, _UnstableArchMixin, BaseEstimator):
class LocallyLinearEmbedding(
_ClassNamePrefixFeaturesOutMixin,
TransformerMixin,
_UnstableArchMixin,
BaseEstimator,
):
"""Locally Linear Embedding.

Read more in the :ref:`User Guide <locally_linear_embedding>`.
Expand Down Expand Up @@ -728,6 +738,7 @@ def _fit_transform(self, X):
reg=self.reg,
n_jobs=self.n_jobs,
)
self._n_features_out = self.embedding_.shape[1]

def fit(self, X, y=None):
"""Compute the embedding vectors for data X.
Expand Down
18 changes: 17 additions & 1 deletion sklearn/manifold/tests/test_isomap.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
from itertools import product
import numpy as np
from numpy.testing import assert_almost_equal, assert_array_almost_equal
from numpy.testing import (
assert_almost_equal,
assert_array_almost_equal,
assert_array_equal,
)
import pytest

from sklearn import datasets
from sklearn import manifold
from sklearn import neighbors
from sklearn import pipeline
from sklearn import preprocessing
from sklearn.datasets import make_blobs
from sklearn.metrics.pairwise import pairwise_distances

from scipy.sparse import rand as sparse_rand
Expand Down Expand Up @@ -220,3 +225,14 @@ def test_multiple_connected_components_metric_precomputed():
X_graph = neighbors.kneighbors_graph(X, n_neighbors=2, mode="distance")
with pytest.raises(RuntimeError, match="number of connected components"):
manifold.Isomap(n_neighbors=1, metric="precomputed").fit(X_graph)


def test_get_feature_names_out():
"""Check get_feature_names_out for Isomap."""
X, y = make_blobs(random_state=0, n_features=4)
n_components = 2

iso = manifold.Isomap(n_components=n_components)
iso.fit_transform(X)
names = iso.get_feature_names_out()
assert_array_equal([f"isomap{i}" for i in range(n_components)], names)
20 changes: 19 additions & 1 deletion sklearn/manifold/tests/test_locally_linear.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
from itertools import product

import numpy as np
from numpy.testing import assert_almost_equal, assert_array_almost_equal
from numpy.testing import (
assert_almost_equal,
assert_array_almost_equal,
assert_array_equal,
)
from scipy import linalg
import pytest

from sklearn import neighbors, manifold
from sklearn.datasets import make_blobs
from sklearn.manifold._locally_linear import barycenter_kneighbors_graph
from sklearn.utils._testing import ignore_warnings

Expand Down Expand Up @@ -159,3 +164,16 @@ def test_integer_input():
for method in ["standard", "hessian", "modified", "ltsa"]:
clf = manifold.LocallyLinearEmbedding(method=method, n_neighbors=10)
clf.fit(X) # this previously raised a TypeError


def test_get_feature_names_out():
"""Check get_feature_names_out for LocallyLinearEmbedding."""
X, y = make_blobs(random_state=0, n_features=4)
n_components = 2

iso = manifold.LocallyLinearEmbedding(n_components=n_components)
iso.fit(X)
names = iso.get_feature_names_out()
assert_array_equal(
[f"locallylinearembedding{i}" for i in range(n_components)], names
)
1 change: 0 additions & 1 deletion sklearn/tests/test_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,6 @@ def test_pandas_column_name_consistency(estimator):
"isotonic",
"kernel_approximation",
"preprocessing",
"manifold",
"neural_network",
]

Expand Down
0