From 02ca6251189066badc80936f83ebbebf8a3ba5d6 Mon Sep 17 00:00:00 2001 From: Guillaume Lemaitre Date: Sun, 16 Jan 2022 18:56:58 +0100 Subject: [PATCH 1/2] MAINT deprecate n_jobs in over-sampling algorithms --- doc/whats_new/v0.10.rst | 13 ++++++ imblearn/over_sampling/_adasyn.py | 17 ++++++++ imblearn/over_sampling/_smote/base.py | 48 ++++++++++++++++++++- imblearn/over_sampling/_smote/filter.py | 32 ++++++++++++++ imblearn/over_sampling/tests/test_common.py | 20 +++++++++ 5 files changed, 129 insertions(+), 1 deletion(-) diff --git a/doc/whats_new/v0.10.rst b/doc/whats_new/v0.10.rst index ff37d151a..3ffff51c2 100644 --- a/doc/whats_new/v0.10.rst +++ b/doc/whats_new/v0.10.rst @@ -6,6 +6,19 @@ Version 0.10.0 (ongoing) Changelog --------- +Deprecation +........... + +- The parameter `n_jobs` has been deprecated from the classes + :class:`~imblearn.over_sampling.ADASYN`, + :class:`~imblearn.over_sampling.BorderlineSMOTE`, + :class:`~imblearn.over_sampling.SMOTE`, + :class:`~imblearn.over_sampling.SMOTENC`, + :class:`~imblearn.over_sampling.SMOTEN`, and + :class:`~imblearn.over_sampling.SVMSMOTE`. Instead, pass a nearest neighbors + estimator where `n_jobs` is set. + :pr:`xxx` by :user:`Guillaume Lemaitre `. + Enhancements ............ diff --git a/imblearn/over_sampling/_adasyn.py b/imblearn/over_sampling/_adasyn.py index bd50378c2..23939ef25 100644 --- a/imblearn/over_sampling/_adasyn.py +++ b/imblearn/over_sampling/_adasyn.py @@ -4,6 +4,8 @@ # Christos Aridas # License: MIT +import warnings + import numpy as np from scipy import sparse @@ -53,6 +55,12 @@ class ADASYN(BaseOverSampler): {n_jobs} + .. deprecated:: 0.10 + `n_jobs` has been deprecated in 0.10 and will be removed in 0.12. + It was previously used to set `n_jobs` of nearest neighbors + algorithm. From now on, you can pass an estimator where `n_jobs` is + already set instead. + Attributes ---------- sampling_strategy_ : dict @@ -133,6 +141,15 @@ def _validate_estimator(self): ) def _fit_resample(self, X, y): + # FIXME: to be removed in 0.12 + if self.n_jobs is not None: + warnings.warn( + "The parameter `n_jobs` has been deprecated in 0.10 and will be " + "removed in 0.12. You can pass an nearest neighbors estimator where " + "`n_jobs` is already set instead.", + FutureWarning, + ) + self._validate_estimator() random_state = check_random_state(self.random_state) diff --git a/imblearn/over_sampling/_smote/base.py b/imblearn/over_sampling/_smote/base.py index 01540e19f..6249dc876 100644 --- a/imblearn/over_sampling/_smote/base.py +++ b/imblearn/over_sampling/_smote/base.py @@ -7,6 +7,7 @@ # License: MIT import math +import warnings from collections import Counter import numpy as np @@ -238,6 +239,12 @@ class SMOTE(BaseSMOTE): {n_jobs} + .. deprecated:: 0.10 + `n_jobs` has been deprecated in 0.10 and will be removed in 0.12. + It was previously used to set `n_jobs` of nearest neighbors + algorithm. From now on, you can pass an estimator where `n_jobs` is + already set instead. + Attributes ---------- sampling_strategy_ : dict @@ -316,6 +323,15 @@ def __init__( ) def _fit_resample(self, X, y): + # FIXME: to be removed in 0.12 + if self.n_jobs is not None: + warnings.warn( + "The parameter `n_jobs` has been deprecated in 0.10 and will be " + "removed in 0.12. You can pass an nearest neighbors estimator where " + "`n_jobs` is already set instead.", + FutureWarning, + ) + self._validate_estimator() X_resampled = [X.copy()] @@ -388,6 +404,12 @@ class SMOTENC(SMOTE): {n_jobs} + .. deprecated:: 0.10 + `n_jobs` has been deprecated in 0.10 and will be removed in 0.12. + It was previously used to set `n_jobs` of nearest neighbors + algorithm. From now on, you can pass an estimator where `n_jobs` is + already set instead. + See Also -------- SMOTE : Over-sample using SMOTE. @@ -496,6 +518,15 @@ def _validate_estimator(self): ) def _fit_resample(self, X, y): + # FIXME: to be removed in 0.12 + if self.n_jobs is not None: + warnings.warn( + "The parameter `n_jobs` has been deprecated in 0.10 and will be " + "removed in 0.12. You can pass an nearest neighbors estimator where " + "`n_jobs` is already set instead.", + FutureWarning, + ) + self.n_features_ = X.shape[1] self._validate_estimator() @@ -636,7 +667,7 @@ def _generate_samples(self, X, nn_data, nn_num, rows, cols, steps): class SMOTEN(SMOTE): """Synthetic Minority Over-sampling Technique for Nominal. - This method is refered as SMOTEN in [1]_. It expects that the data to + This method is referred as SMOTEN in [1]_. It expects that the data to resample are only made of categorical features. Read more in the :ref:`User Guide `. @@ -664,6 +695,12 @@ class SMOTEN(SMOTE): {n_jobs} + .. deprecated:: 0.10 + `n_jobs` has been deprecated in 0.10 and will be removed in 0.12. + It was previously used to set `n_jobs` of nearest neighbors + algorithm. From now on, you can pass an estimator where `n_jobs` is + already set instead. + Attributes ---------- sampling_strategy_ : dict @@ -755,6 +792,15 @@ def _make_samples(self, X_class, klass, y_dtype, nn_indices, n_samples): return X_new, y_new def _fit_resample(self, X, y): + # FIXME: to be removed in 0.12 + if self.n_jobs is not None: + warnings.warn( + "The parameter `n_jobs` has been deprecated in 0.10 and will be " + "removed in 0.12. You can pass an nearest neighbors estimator where " + "`n_jobs` is already set instead.", + FutureWarning, + ) + self._validate_estimator() X_resampled = [X.copy()] diff --git a/imblearn/over_sampling/_smote/filter.py b/imblearn/over_sampling/_smote/filter.py index 93aebc235..df01e9b2b 100644 --- a/imblearn/over_sampling/_smote/filter.py +++ b/imblearn/over_sampling/_smote/filter.py @@ -6,6 +6,8 @@ # Dzianis Dudnik # License: MIT +import warnings + import numpy as np from scipy import sparse @@ -61,6 +63,12 @@ class BorderlineSMOTE(BaseSMOTE): {n_jobs} + .. deprecated:: 0.10 + `n_jobs` has been deprecated in 0.10 and will be removed in 0.12. + It was previously used to set `n_jobs` of nearest neighbors + algorithm. From now on, you can pass an estimator where `n_jobs` is + already set instead. + m_neighbors : int or object, default=10 The nearest neighbors used to determine if a minority sample is in "danger". You can pass: @@ -176,6 +184,15 @@ def _validate_estimator(self): ) def _fit_resample(self, X, y): + # FIXME: to be removed in 0.12 + if self.n_jobs is not None: + warnings.warn( + "The parameter `n_jobs` has been deprecated in 0.10 and will be " + "removed in 0.12. You can pass an nearest neighbors estimator where " + "`n_jobs` is already set instead.", + FutureWarning, + ) + self._validate_estimator() X_resampled = X.copy() @@ -289,6 +306,12 @@ class SVMSMOTE(BaseSMOTE): {n_jobs} + .. deprecated:: 0.10 + `n_jobs` has been deprecated in 0.10 and will be removed in 0.12. + It was previously used to set `n_jobs` of nearest neighbors + algorithm. From now on, you can pass an estimator where `n_jobs` is + already set instead. + m_neighbors : int or object, default=10 The nearest neighbors used to determine if a minority sample is in "danger". You can pass: @@ -416,6 +439,15 @@ def _validate_estimator(self): self.svm_estimator_ = clone(self.svm_estimator) def _fit_resample(self, X, y): + # FIXME: to be removed in 0.12 + if self.n_jobs is not None: + warnings.warn( + "The parameter `n_jobs` has been deprecated in 0.10 and will be " + "removed in 0.12. You can pass an nearest neighbors estimator where " + "`n_jobs` is already set instead.", + FutureWarning, + ) + self._validate_estimator() random_state = check_random_state(self.random_state) X_resampled = X.copy() diff --git a/imblearn/over_sampling/tests/test_common.py b/imblearn/over_sampling/tests/test_common.py index 804382c08..c2c046317 100644 --- a/imblearn/over_sampling/tests/test_common.py +++ b/imblearn/over_sampling/tests/test_common.py @@ -116,3 +116,23 @@ def test_numerical_smote_extra_custom_nn(numerical_data, smote): assert X_res.shape == (120, 2) assert Counter(y_res) == {0: 60, 1: 60} + + +# FIXME: to be removed in 0.12 +@pytest.mark.parametrize( + "sampler", + [ + ADASYN(random_state=0), + BorderlineSMOTE(random_state=0), + SMOTE(random_state=0), + SMOTEN(random_state=0), + SMOTENC([0], random_state=0), + SVMSMOTE(random_state=0), + ], +) +def test_n_jobs_deprecation_warning(numerical_data, sampler): + X, y = numerical_data + sampler.set_params(n_jobs=2) + warning_msg = "The parameter `n_jobs` has been deprecated" + with pytest.warns(FutureWarning, match=warning_msg): + sampler.fit_resample(X, y) From 11f503138121e272bb9b6d0060c7890f4c416377 Mon Sep 17 00:00:00 2001 From: Guillaume Lemaitre Date: Sun, 16 Jan 2022 18:58:14 +0100 Subject: [PATCH 2/2] update changelog --- doc/whats_new/v0.10.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/whats_new/v0.10.rst b/doc/whats_new/v0.10.rst index 3ffff51c2..96bbd5671 100644 --- a/doc/whats_new/v0.10.rst +++ b/doc/whats_new/v0.10.rst @@ -17,7 +17,7 @@ Deprecation :class:`~imblearn.over_sampling.SMOTEN`, and :class:`~imblearn.over_sampling.SVMSMOTE`. Instead, pass a nearest neighbors estimator where `n_jobs` is set. - :pr:`xxx` by :user:`Guillaume Lemaitre `. + :pr:`887` by :user:`Guillaume Lemaitre `. Enhancements ............