From 75e03da854cbf9a5b7287cfedda3a0ecafe60ced Mon Sep 17 00:00:00 2001 From: Philip Loche Date: Thu, 13 Feb 2025 14:05:20 +0100 Subject: [PATCH] fix some tests --- .gitignore | 1 + pyproject.toml | 3 - src/skmatter/_selection.py | 22 ++-- src/skmatter/utils/_pcovr_utils.py | 109 +++++++++++------- ...e.tsf-492-wpa-0-247.epfl.ch.11311.XpjwIfdx | Bin 53248 -> 0 bytes tests/test_feature_pcov_fps.py | 5 +- tests/test_kernel_pcovr.py | 2 +- tests/test_pcovr.py | 9 +- tests/test_sample_pcov_fps.py | 5 +- 9 files changed, 90 insertions(+), 66 deletions(-) delete mode 100644 tests/.coverage.tsf-492-wpa-0-247.epfl.ch.11311.XpjwIfdx diff --git a/.gitignore b/.gitignore index 226933088..8e48d2752 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ build/ dist/ docs/src/examples sg_execution_times.rst +.coverage* \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index db7056b63..63e02955f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,9 +75,6 @@ include = [ [tool.coverage.xml] output = 'tests/coverage.xml' -[tool.pytest.ini_options] -testpaths = "tests" - [tool.isort] skip = "__init__.py" profile = "black" diff --git a/src/skmatter/_selection.py b/src/skmatter/_selection.py index 50e55cff3..224c020a7 100644 --- a/src/skmatter/_selection.py +++ b/src/skmatter/_selection.py @@ -561,8 +561,7 @@ def score(self, X, y=None): Parameters ---------- - X : numpy.ndarray of shape [n_samples, n_features] - The input samples. + X : ignored y : ignored Returns @@ -570,8 +569,7 @@ def score(self, X, y=None): score : numpy.ndarray of (n_to_select_from_) :math:`\pi` importance for the given samples or features """ - X, y = validate_data(self, X, y, reset=False) - + validate_data(self, X, y, reset=False) # present for API consistency return self.pi_ def _init_greedy_search(self, X, y, n_to_select): @@ -746,8 +744,7 @@ def score(self, X, y=None): score : numpy.ndarray of (n_to_select_from_) :math:`\pi` importance for the given samples or features """ - X, y = validate_data(self, X, y, reset=False) - + validate_data(self, X, y, reset=False) # present for API consistency return self.pi_ def _init_greedy_search(self, X, y, n_to_select): @@ -941,8 +938,7 @@ def score(self, X, y=None): ------- hausdorff : Hausdorff distances """ - X, y = validate_data(self, X, y, reset=False) - + validate_data(self, X, y, reset=False) return self.hausdorff_ def get_distance(self): @@ -1079,15 +1075,16 @@ def __init__( ) def fit(self, X, y=None, warm_start=False): - if self.mixing == 1.0: raise ValueError( - "Mixing = 1.0 corresponds to traditional FPS." - "Please use the FPS class." + "Mixing = 1.0 corresponds to traditional FPS. Please use the FPS class." ) return super().fit(X, y) + # docstring is inherited and set from the base class + fit.__doc__ = GreedySelector.fit.__doc__ + def score(self, X, y=None): """Returns the Hausdorff distances of all samples to previous selections. @@ -1104,8 +1101,7 @@ def score(self, X, y=None): ------- hausdorff : Hausdorff distances """ - X, y = validate_data(self, X, y, reset=False) - + validate_data(self, X, y, reset=False) return self.hausdorff_ def get_distance(self): diff --git a/src/skmatter/utils/_pcovr_utils.py b/src/skmatter/utils/_pcovr_utils.py index 15286e341..8852a6386 100644 --- a/src/skmatter/utils/_pcovr_utils.py +++ b/src/skmatter/utils/_pcovr_utils.py @@ -9,18 +9,30 @@ def check_lr_fit(regressor, X, y): - r""" + """ Checks that a (linear) regressor is fitted, and if not, - fits it with the provided data - - :param regressor: sklearn-style regressor - :type regressor: object - :param X: feature matrix with which to fit the regressor - if it is not already fitted - :type X: array - :param y: target values with which to fit the regressor - if it is not already fitted - :type y: array + fits it with the provided data. + + Parameters + ---------- + regressor : object + sklearn-style regressor + X : array-like + Feature matrix with which to fit the regressor if it is not already fitted + y : array-like + Target values with which to fit the regressor if it is not already fitted + + Returns + ------- + fitted_regressor : object + The fitted regressor. If input regressor was already fitted and compatible with + the data, returns a deep copy. Otherwise returns a newly fitted regressor. + + Raises + ------ + ValueError + If the fitted regressor's coefficients dimensions are incompatible with the + target space. """ try: check_is_fitted(regressor) @@ -32,18 +44,18 @@ def check_lr_fit(regressor, X, y): # Check compatibility with y if fitted_regressor.coef_.ndim != y.ndim: raise ValueError( - "The regressor coefficients have a dimension incompatible " - "with the supplied target space. " - "The coefficients have dimension %d and the targets " - "have dimension %d" % (fitted_regressor.coef_.ndim, y.ndim) + "The regressor coefficients have a dimension incompatible with the " + "supplied target space. The coefficients have dimension " + f"{fitted_regressor.coef_.ndim} and the targets have dimension " + f"{y.ndim}" ) elif y.ndim == 2: if fitted_regressor.coef_.shape[0] != y.shape[1]: raise ValueError( - "The regressor coefficients have a shape incompatible " - "with the supplied target space. " - "The coefficients have shape %r and the targets " - "have shape %r" % (fitted_regressor.coef_.shape, y.shape) + "The regressor coefficients have a shape incompatible with the " + "supplied target space. The coefficients have shape " + f"{fitted_regressor.coef_.shape} and the targets have shape " + f"{y.shape}" ) except NotFittedError: @@ -54,20 +66,37 @@ def check_lr_fit(regressor, X, y): def check_krr_fit(regressor, K, X, y): - r""" + """ Checks that a (kernel ridge) regressor is fitted, and if not, - fits it with the provided data - - :param regressor: sklearn-style regressor - :type regressor: object - :param K: kernel matrix with which to fit the regressor - if it is not already fitted - :type K: array - :param X: feature matrix with which to check the regressor - :type X: array - :param y: target values with which to fit the regressor - if it is not already fitted - :type y: array + fits it with the provided data. + + Parameters + ---------- + regressor : object + sklearn-style regressor + K : array-like + Kernel matrix with which to fit the regressor if it is not already fitted + X : array-like + Feature matrix with which to check the regressor + y : array-like + Target values with which to fit the regressor if it is not already fitted + + Returns + ------- + fitted_regressor : object + The fitted regressor. If input regressor was already fitted and compatible with + the data, returns a deep copy. Otherwise returns a newly fitted regressor. + + Raises + ------ + ValueError + If the fitted regressor's coefficients dimensions are incompatible with the + target space. + + Notes + ----- + For unfitted regressors, sets the kernel to "precomputed" before fitting with the + provided kernel matrix K to avoid recomputation. """ try: check_is_fitted(regressor) @@ -79,18 +108,18 @@ def check_krr_fit(regressor, K, X, y): # Check compatibility with y if fitted_regressor.dual_coef_.ndim != y.ndim: raise ValueError( - "The regressor coefficients have a dimension incompatible " - "with the supplied target space. " - "The coefficients have dimension %d and the targets " - "have dimension %d" % (fitted_regressor.dual_coef_.ndim, y.ndim) + "The regressor coefficients have a dimension incompatible with the " + "supplied target space. The coefficients have dimension " + f"{fitted_regressor.dual_coef_.ndim} and the targets have dimension " + f"{y.ndim}" ) elif y.ndim == 2: if fitted_regressor.dual_coef_.shape[1] != y.shape[1]: raise ValueError( - "The regressor coefficients have a shape incompatible " - "with the supplied target space. " - "The coefficients have shape %r and the targets " - "have shape %r" % (fitted_regressor.dual_coef_.shape, y.shape) + "The regressor coefficients have a shape incompatible with the " + "supplied target space. The coefficients have shape " + f"{fitted_regressor.dual_coef_.shape} and the targets have shape " + f"{y.shape}" ) except NotFittedError: diff --git a/tests/.coverage.tsf-492-wpa-0-247.epfl.ch.11311.XpjwIfdx b/tests/.coverage.tsf-492-wpa-0-247.epfl.ch.11311.XpjwIfdx deleted file mode 100644 index 5d637632bf921d7fd0c0dfe157ca23af76774c48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53248 zcmeI)O>Y}T7zglOyYv4m3ax6_rXM;(~-bUXPOn@2<1E z&dUKIr$~{I_y&mY#5dsB6E{v=c%GddubsqIZ&l5I6+8PfGduH}XJ(vi+Hamc@e(Bl zVdTq1yl<^rwrxEU!m_L~z1HYuHivfZm;?H5&+ISSEnDr&M{Bijt!n8vtM>ic)7oD3 z_qF#{|E&7uUswNdWZ9()*dPD_2teTfEiidjb?RGN_T^8B>w!J;EFQV{Fj8r5B-cSiI=zFeAyx>SA$I7H0$Ewc@9i5}4juW=i z{Jhuo`jjhCM^wZp@_ZRxh#%EOD@~ByEm7x*K0$>j?4s_YYm;qoAP)-1-W6==i2uo8MwzPZV5SUp&L>?&lBC+ zDD)pBp%{8W+RPyK5-$vdI#=#EQTx;-z6r#t1jpqZXt5ITH)aoq4InGX^kMZ=*82kDUE+(LH_Mf2>K zd0;SP!~;!)SwgDm8;v%uEY(5uhGB0$*3yWH6%7!Y3rw=XIB$S@+yC+ zF7{64kYH_j(V^67?X>uCgUxjh( z(Xz_RR{XI!D;mc#=2<9ih+Y^Dl??RSKsg@AbWbl9X&r8^N}uLs#1~w~(P<;ClUZDN znm?pLXT}%p_`VGK*?Psxur8J6ejc2BA3cdsM$w=_8PgEGR;DR5yUH_`DZf1;6E4-4 zeLdW{Q)Ws$J61P})2q=JGEs@=E5S+9%A|pHCS&17iZ0Sx+H4eG6$ac}-44I=PsuC% zQEswhJN5hb?a4SBjC!8w#3$X z_R^}oto`#=HV~DD00bZa0SG_<0uX=z1Rwwb2tZ&eP%YlG&94CpmEv|e`z=8F5B%4s z$*=z{}fB*y_009U<00Izz00c4tJpV^1KmY;|fB*y_009U<00Izz00fp_ z0MGxIzmL&E2tWV=5P$##AOHafKmY;|fB>HVBL*M<0SG_<0uX=z1Rwwb2tWV=%P)ZE z|I6RUXdwh3009U<00Izz00bZa0SG_<&;Jnv5P$##AOHafKmY;|fB*y_0De diff --git a/tests/test_feature_pcov_fps.py b/tests/test_feature_pcov_fps.py index 321cc78ee..e6910f9a1 100644 --- a/tests/test_feature_pcov_fps.py +++ b/tests/test_feature_pcov_fps.py @@ -24,11 +24,12 @@ def test_restart(self): def test_no_mixing_1(self): """Check that the model throws an error when mixing = 1.0.""" + selector = PCovFPS(n_to_select=1, mixing=1.0) with self.assertRaises(ValueError) as cm: - _ = PCovFPS(n_to_select=1, mixing=1.0) + selector.fit(self.X, y=self.y) self.assertEqual( str(cm.exception), - "Mixing = 1.0 corresponds to traditional FPS." "Please use the FPS class.", + "Mixing = 1.0 corresponds to traditional FPS. Please use the FPS class.", ) diff --git a/tests/test_kernel_pcovr.py b/tests/test_kernel_pcovr.py index e4bbda52e..4a39bddc8 100644 --- a/tests/test_kernel_pcovr.py +++ b/tests/test_kernel_pcovr.py @@ -255,7 +255,7 @@ def test_incompatible_coef_shape(self): # Dimension mismatch with self.assertRaises(ValueError) as cm: - kpcovr.fit(self.X, self.Y[:, 0]) + kpcovr.fit(self.X, np.zeros(self.Y.shape[0] + (2,))) self.assertTrue( str(cm.exception), "The regressor coefficients have a dimension incompatible " diff --git a/tests/test_pcovr.py b/tests/test_pcovr.py index e589978d2..2059eed44 100644 --- a/tests/test_pcovr.py +++ b/tests/test_pcovr.py @@ -491,13 +491,12 @@ def test_incompatible_coef_shape(self): # Dimension mismatch with self.assertRaises(ValueError) as cm: - pcovr.fit(self.X, self.Y.squeeze()) + pcovr.fit(self.X, np.zeros((self.Y.shape[0], 2))) self.assertEqual( str(cm.exception), - "The regressor coefficients have a dimension incompatible " - "with the supplied target space. " - "The coefficients have dimension %d and the targets " - "have dimension %d" % (regressor.coef_.ndim, self.Y.squeeze().ndim), + "The regressor coefficients have a dimension incompatible with the " + "supplied target space. The coefficients have dimension 1 and the targets " + "have dimension 2", ) # Shape mismatch (number of targets) diff --git a/tests/test_sample_pcov_fps.py b/tests/test_sample_pcov_fps.py index 7679abb0a..b6ed08662 100644 --- a/tests/test_sample_pcov_fps.py +++ b/tests/test_sample_pcov_fps.py @@ -24,11 +24,12 @@ def test_restart(self): def test_no_mixing_1(self): """Check that the model throws an error when mixing = 1.0.""" + selector = PCovFPS(n_to_select=1, mixing=1.0) with self.assertRaises(ValueError) as cm: - _ = PCovFPS(n_to_select=1, mixing=1.0) + selector.fit(self.X, y=self.y) self.assertEqual( str(cm.exception), - "Mixing = 1.0 corresponds to traditional FPS." "Please use the FPS class.", + "Mixing = 1.0 corresponds to traditional FPS. Please use the FPS class.", )