diff --git a/doc/whats_new/v1.2.rst b/doc/whats_new/v1.2.rst index 5ebb719761564..5ddc24e0500ad 100644 --- a/doc/whats_new/v1.2.rst +++ b/doc/whats_new/v1.2.rst @@ -192,6 +192,11 @@ Changelog :pr:`11860` by :user:`Pierre Ablin `, :pr:`22527` by :user:`Meekail Zain ` and `Thomas Fan`_. +- |API| The `n_features_` attribute of + :class:`decomposition.PCA` is deprecated in favor of + `n_features_in_` and will be removed in 1.4. :pr:`24421` by + :user:`Kshitij Mathur `. + :mod:`sklearn.discriminant_analysis` .................................... diff --git a/sklearn/decomposition/_pca.py b/sklearn/decomposition/_pca.py index 9a0a736bc74c6..38087dde5e97c 100644 --- a/sklearn/decomposition/_pca.py +++ b/sklearn/decomposition/_pca.py @@ -22,6 +22,7 @@ from ._base import _BasePCA from ..utils import check_random_state from ..utils._arpack import _init_arpack_v0 +from ..utils.deprecation import deprecated from ..utils.extmath import fast_logdet, randomized_svd, svd_flip from ..utils.extmath import stable_cumsum from ..utils.validation import check_is_fitted @@ -402,6 +403,16 @@ def __init__( self.power_iteration_normalizer = power_iteration_normalizer self.random_state = random_state + # TODO(1.4): remove in 1.4 + # mypy error: Decorated property not supported + @deprecated( # type: ignore + "Attribute `n_features_` was deprecated in version 1.2 and will be " + "removed in 1.4. Use `n_features_in_` instead." + ) + @property + def n_features_(self): + return self.n_features_in_ + def fit(self, X, y=None): """Fit the model with X. @@ -552,7 +563,7 @@ def _fit_full(self, X, n_components): else: self.noise_variance_ = 0.0 - self.n_samples_, self.n_features_ = n_samples, n_features + self.n_samples_ = n_samples self.components_ = components_[:n_components] self.n_components_ = n_components self.explained_variance_ = explained_variance_[:n_components] @@ -614,7 +625,7 @@ def _fit_truncated(self, X, n_components, svd_solver): random_state=random_state, ) - self.n_samples_, self.n_features_ = n_samples, n_features + self.n_samples_ = n_samples self.components_ = Vt self.n_components_ = n_components diff --git a/sklearn/decomposition/tests/test_sparse_pca.py b/sklearn/decomposition/tests/test_sparse_pca.py index 64c3cd82c6443..cf237014c6049 100644 --- a/sklearn/decomposition/tests/test_sparse_pca.py +++ b/sklearn/decomposition/tests/test_sparse_pca.py @@ -289,6 +289,13 @@ def test_spca_n_iter_deprecation(): assert model.n_iter_ <= max_iter +def test_pca_n_features_deprecation(): + X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]]) + pca = PCA(n_components=2).fit(X) + with pytest.warns(FutureWarning, match="`n_features_` was deprecated"): + pca.n_features_ + + def test_spca_early_stopping(global_random_seed): """Check that `tol` and `max_no_improvement` act as early stopping.""" rng = np.random.RandomState(global_random_seed)