handling qunfold versioning, and more bug fix

This commit is contained in:
Alejandro Moreo Fernandez 2025-06-15 13:22:24 +02:00
parent 934750ea44
commit 5b7f7d4f70
4 changed files with 43 additions and 11 deletions

View File

@ -15,6 +15,7 @@ CLEAN TODO-FILE
my_acc.fit(the_data, fit_classifier=False) my_acc.fit(the_data, fit_classifier=False)
in which case the_data is to be used for validation purposes. However, the val_split could be set as a fraction in which case the_data is to be used for validation purposes. However, the val_split could be set as a fraction
indicating only part of the_data must be used for validation, and the rest wasted... it was certainly confusing. indicating only part of the_data must be used for validation, and the rest wasted... it was certainly confusing.
- This change imposes a versioning constrain with qunfold, which now must be >= 0.1.6
- EMQ has been modified, so that the representation function "classify" now only provides posterior - EMQ has been modified, so that the representation function "classify" now only provides posterior
probabilities and, if required, these are recalibrated (e.g., by "bcts") during the aggregation function. probabilities and, if required, these are recalibrated (e.g., by "bcts") during the aggregation function.
- A new parameter "on_calib_error" is passed to the constructor, which informs of the policy to follow - A new parameter "on_calib_error" is passed to the constructor, which informs of the policy to follow

View File

@ -1,3 +1,5 @@
Update READMEs, wiki, & examples for new fit-predict interface
Add the fix suggested by Alexander: Add the fix suggested by Alexander:
For a more general application, I would maybe first stablish a per-class threshold value of plausible prevalence For a more general application, I would maybe first stablish a per-class threshold value of plausible prevalence

View File

@ -1,13 +1,21 @@
"""This module allows the composition of quantification methods from loss functions and feature transformations. This functionality is realized through an integration of the qunfold package: https://github.com/mirkobunse/qunfold.""" """This module allows the composition of quantification methods from loss functions and feature transformations. This functionality is realized through an integration of the qunfold package: https://github.com/mirkobunse/qunfold."""
_import_error_message = """qunfold, the back-end of quapy.method.composable, is not properly installed. __install_istructions = """
To fix this error, call: To fix this error, call:
pip install --upgrade pip setuptools wheel pip install --upgrade pip setuptools wheel
pip install "jax[cpu]" pip install "jax[cpu]"
pip install "qunfold @ git+https://github.com/mirkobunse/qunfold@v0.1.4" pip install "qunfold @ git+https://github.com/mirkobunse/qunfold@v0.1.5"
""" """
__import_error_message = (
"qunfold, the back-end of quapy.method.composable, is not properly installed." + __install_istructions
)
__old_version_message = (
"The version of qunfold you have installed is not compatible with current quapy's version, "
"which requires qunfold>=0.1.5. " + __install_istructions
)
from packaging.version import Version
try: try:
import qunfold import qunfold
@ -51,7 +59,19 @@ try:
"GaussianRFFKernelTransformer", "GaussianRFFKernelTransformer",
] ]
except ImportError as e: except ImportError as e:
raise ImportError(_import_error_message) from e raise ImportError(__import_error_message) from e
def check_compatible_qunfold_version():
try:
version_str = qunfold.__version__
except AttributeError:
# versions of qunfold <= 0.1.4 did not declare __version__ in the __init__.py but only in the setup.py
version_str = "0.1.4"
compatible = Version(version_str) >= Version("0.1.5")
return compatible
def ComposableQuantifier(loss, transformer, **kwargs): def ComposableQuantifier(loss, transformer, **kwargs):
"""A generic quantification / unfolding method that solves a linear system of equations. """A generic quantification / unfolding method that solves a linear system of equations.
@ -99,4 +119,7 @@ def ComposableQuantifier(loss, transformer, **kwargs):
>>> ClassTransformer(CVClassifier(LogisticRegression(), 10)) >>> ClassTransformer(CVClassifier(LogisticRegression(), 10))
>>> ) >>> )
""" """
if not check_compatible_qunfold_version():
raise ImportError(__old_version_message)
return QuaPyWrapper(qunfold.GenericMethod(loss, transformer, **kwargs)) return QuaPyWrapper(qunfold.GenericMethod(loss, transformer, **kwargs))

View File

@ -17,6 +17,7 @@ from quapy.method.composable import (
ClassTransformer, ClassTransformer,
HistogramTransformer, HistogramTransformer,
CVClassifier, CVClassifier,
check_compatible_qunfold_version
) )
COMPOSABLE_METHODS = [ COMPOSABLE_METHODS = [
ComposableQuantifier( # ACC ComposableQuantifier( # ACC
@ -111,13 +112,18 @@ class TestMethods(unittest.TestCase):
self.assertTrue(check_prevalence_vector(estim_prevalences)) self.assertTrue(check_prevalence_vector(estim_prevalences))
def test_composable(self): def test_composable(self):
for dataset in TestMethods.datasets: from packaging.version import Version
for q in COMPOSABLE_METHODS: if check_compatible_qunfold_version():
print('testing', q) for dataset in TestMethods.datasets:
q.fit(*dataset.training.Xy) for q in COMPOSABLE_METHODS:
estim_prevalences = q.predict(dataset.test.X) print('testing', q)
print(estim_prevalences) q.fit(*dataset.training.Xy)
self.assertTrue(check_prevalence_vector(estim_prevalences)) estim_prevalences = q.predict(dataset.test.X)
print(estim_prevalences)
self.assertTrue(check_prevalence_vector(estim_prevalences))
else:
from quapy.method.composable import __old_version_message
print(__old_version_message)
if __name__ == '__main__': if __name__ == '__main__':