diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index f3ab89e..104cf82 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -55,7 +55,7 @@ jobs: strategy: max-parallel: 4 matrix: - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + python-version: ["3.9", "3.10", "3.11", "3.12"] fail-fast: false diff --git a/RELEASES.md b/RELEASES.md index 01efa41..eaca2a6 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,6 +1,10 @@ # History of changes -## 1.1.0 (Latest) +## 1.1.1 (Latest) + ++ Minor bug fix to ensure that all prediction calls can be carried. + +## 1.1.0 + Updating documentation introduction of the package + Added the chi square divergence in GEMINIs: `gemclus.gemini.ChiSquareGEMINI` diff --git a/gemclus/__init__.py b/gemclus/__init__.py index 97b2294..98b440c 100644 --- a/gemclus/__init__.py +++ b/gemclus/__init__.py @@ -5,4 +5,4 @@ __all__ = ['linear', 'mlp', 'sparse', 'data', 'nonparametric', 'gemini', 'tree', 'add_mlcl_constraint', '__version__', 'DiscriminativeModel'] -__version__ = '1.1.0' +__version__ = '1.1.1' diff --git a/gemclus/_base_gemini.py b/gemclus/_base_gemini.py index 45449e9..5c63405 100644 --- a/gemclus/_base_gemini.py +++ b/gemclus/_base_gemini.py @@ -8,9 +8,9 @@ import numpy as np from sklearn.base import ClusterMixin, BaseEstimator from sklearn.neural_network._stochastic_optimizers import AdamOptimizer, SGDOptimizer -from sklearn.utils import check_array, check_random_state +from sklearn.utils import check_random_state from sklearn.utils._param_validation import Interval, StrOptions -from sklearn.utils.validation import check_is_fitted +from sklearn.utils.validation import check_is_fitted, validate_data from gemclus.gemini import AVAILABLE_GEMINIS from .gemini._base_loss import _GEMINI @@ -230,8 +230,7 @@ def fit(self, X, y=None): self._validate_params() # Check that X has the correct shape - X = check_array(X) - X = self._validate_data(X, accept_sparse=True, dtype=np.float64, ensure_min_samples=self.n_clusters) + X = validate_data(self, X, accept_sparse=False, dtype=np.float64, ensure_min_samples=self.n_clusters) # Fix the random seed random_state = check_random_state(self.random_state) @@ -314,7 +313,7 @@ def predict_proba(self, X): check_is_fitted(self) # Input validation - X = check_array(X) + X = validate_data(self, X, accept_sparse=False, dtype=np.float64, reset=False) y_pred = self._infer(X, retain=False) return y_pred @@ -337,7 +336,7 @@ def predict(self, X): check_is_fitted(self) # Input validation - X = check_array(X) + X = validate_data(self, X, accept_sparse=True, dtype=np.float64, reset=False) return np.argmax(self.predict_proba(X), axis=1) diff --git a/gemclus/linear/_linear_geminis.py b/gemclus/linear/_linear_geminis.py index 79455f8..01bc225 100644 --- a/gemclus/linear/_linear_geminis.py +++ b/gemclus/linear/_linear_geminis.py @@ -7,7 +7,7 @@ from sklearn.neural_network._stochastic_optimizers import AdamOptimizer, SGDOptimizer from sklearn.utils._param_validation import Interval, StrOptions from sklearn.utils.extmath import softmax -from sklearn.utils.validation import check_is_fitted, check_array +from sklearn.utils.validation import check_is_fitted, check_array, validate_data from .._base_gemini import DiscriminativeModel from ..gemini import MMDGEMINI, WassersteinGEMINI @@ -579,5 +579,7 @@ def _compute_grads(self, X, y_pred, gradient): def predict_proba(self, X): + check_is_fitted(self) + X = validate_data(self, X, accept_sparse=False, reset=False) kernel = self._compute_kernel(X) return self._infer(kernel) diff --git a/gemclus/sparse/_linear_sparse.py b/gemclus/sparse/_linear_sparse.py index 9cd4db2..2c4b132 100644 --- a/gemclus/sparse/_linear_sparse.py +++ b/gemclus/sparse/_linear_sparse.py @@ -5,6 +5,7 @@ from sklearn.metrics.pairwise import PAIRWISE_KERNEL_FUNCTIONS from sklearn.neural_network._stochastic_optimizers import SGDOptimizer from sklearn.utils._param_validation import Interval, StrOptions +from sklearn.utils.validation import validate_data from ._base_sparse import _path, check_groups from ._prox_grad import linear_prox_grad, group_linear_prox_grad @@ -151,7 +152,7 @@ def _group_lasso_penalty(self): return np.linalg.norm(self.W_, axis=1, ord=2).sum() def fit(self, X, y=None): - self._validate_data(X) + X = validate_data(self, X, accept_sparse=False, dtype=np.float64) self.groups_ = check_groups(self.groups, X.shape[1]) # Intercept to check that group forms a partition return super().fit(X, y) diff --git a/gemclus/sparse/_mlp_sparse.py b/gemclus/sparse/_mlp_sparse.py index f22bb42..ed26591 100644 --- a/gemclus/sparse/_mlp_sparse.py +++ b/gemclus/sparse/_mlp_sparse.py @@ -6,6 +6,7 @@ from sklearn.neural_network._stochastic_optimizers import SGDOptimizer from sklearn.utils._param_validation import Interval, StrOptions from sklearn.utils.extmath import softmax +from sklearn.utils.validation import validate_data from ._base_sparse import _path, check_groups from ._prox_grad import group_mlp_prox_grad, mlp_prox_grad @@ -203,7 +204,7 @@ def _group_lasso_penalty(self): return np.linalg.norm(self.W_skip_, axis=1, ord=2).sum() def fit(self, X, y=None): - self._validate_data(X) + X = validate_data(self, X, accept_sparse=False, dtype=np.float64) self.groups_ = check_groups(self.groups, X.shape[1]) # Intercept to check that group forms a partition return super().fit(X, y) diff --git a/gemclus/tree/kauri.py b/gemclus/tree/kauri.py index 5b7253c..7a7930d 100644 --- a/gemclus/tree/kauri.py +++ b/gemclus/tree/kauri.py @@ -9,7 +9,7 @@ from sklearn.metrics.pairwise import PAIRWISE_KERNEL_FUNCTIONS, pairwise_kernels from sklearn.utils import check_array, check_random_state from sklearn.utils._param_validation import Interval, StrOptions -from sklearn.utils.validation import check_is_fitted +from sklearn.utils.validation import check_is_fitted, validate_data from ._utils import find_best_split, gemini_objective, Split from .._constraints import constraint_params @@ -187,8 +187,7 @@ def fit(self, X, y=None): self._validate_params() # Check that X has the correct shape - X = check_array(X) - X = self._validate_data(X, accept_sparse=True, dtype=np.float64, ensure_min_samples=self.min_samples_leaf) + X = validate_data(self, X, accept_sparse=False, dtype=np.float64, ensure_min_samples=self.min_samples_leaf) # Create the random state random_state = check_random_state(self.random_state) @@ -352,7 +351,7 @@ def predict(self, X): check_is_fitted(self) # Input validation - X = check_array(X) + X = validate_data(self, X, accept_sparse=False, reset=False) return self.tree_.predict(X) diff --git a/pyproject.toml b/pyproject.toml index 61fbc5f..6f0a15e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "gemclus" -version = "1.1.0" +version = "1.1.1" authors = [ {name = "Louis Ohl", email = "louis.ohl@liu.se"}, ]