Adapt the qunfold wrapper for composable methods to the changes between version 1.4 and the upcoming version 1.5
This commit is contained in:
parent
3129187df8
commit
1612b5124c
|
|
@ -28,7 +28,7 @@ jobs:
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip setuptools wheel
|
python -m pip install --upgrade pip setuptools wheel
|
||||||
python -m pip install "qunfold @ git+https://github.com/mirkobunse/qunfold@v0.1.4"
|
python -m pip install "qunfold @ git+https://github.com/mirkobunse/qunfold@main"
|
||||||
python -m pip install -e .[bayes,tests]
|
python -m pip install -e .[bayes,tests]
|
||||||
- name: Test with unittest
|
- name: Test with unittest
|
||||||
run: python -m unittest
|
run: python -m unittest
|
||||||
|
|
@ -47,7 +47,7 @@ jobs:
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip setuptools wheel "jax[cpu]"
|
python -m pip install --upgrade pip setuptools wheel "jax[cpu]"
|
||||||
python -m pip install "qunfold @ git+https://github.com/mirkobunse/qunfold@v0.1.4"
|
python -m pip install "qunfold @ git+https://github.com/mirkobunse/qunfold@main"
|
||||||
python -m pip install -e .[neural,docs]
|
python -m pip install -e .[neural,docs]
|
||||||
- name: Build documentation
|
- name: Build documentation
|
||||||
run: sphinx-build -M html docs/source docs/build
|
run: sphinx-build -M html docs/source docs/build
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,26 @@
|
||||||
"""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.
|
from dataclasses import dataclass
|
||||||
|
from .base import BaseQuantifier
|
||||||
|
|
||||||
|
# what to display when an ImportError is thrown
|
||||||
|
_IMPORT_ERROR_MESSAGE = """qunfold, the back-end of quapy.method.composable, is not properly installed.
|
||||||
|
|
||||||
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"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# try to import members of qunfold as members of this module
|
||||||
try:
|
try:
|
||||||
import qunfold
|
import qunfold
|
||||||
from qunfold.quapy import QuaPyWrapper
|
from qunfold.base import BaseMixin
|
||||||
|
from qunfold.methods import AbstractMethod
|
||||||
from qunfold.sklearn import CVClassifier
|
from qunfold.sklearn import CVClassifier
|
||||||
from qunfold import (
|
from qunfold import (
|
||||||
|
LinearMethod, # methods
|
||||||
LeastSquaresLoss, # losses
|
LeastSquaresLoss, # losses
|
||||||
BlobelLoss,
|
BlobelLoss,
|
||||||
EnergyLoss,
|
EnergyLoss,
|
||||||
|
|
@ -21,46 +28,81 @@ try:
|
||||||
CombinedLoss,
|
CombinedLoss,
|
||||||
TikhonovRegularization,
|
TikhonovRegularization,
|
||||||
TikhonovRegularized,
|
TikhonovRegularized,
|
||||||
ClassTransformer, # transformers
|
ClassRepresentation, # representations
|
||||||
HistogramTransformer,
|
HistogramRepresentation,
|
||||||
DistanceTransformer,
|
DistanceRepresentation,
|
||||||
KernelTransformer,
|
KernelRepresentation,
|
||||||
EnergyKernelTransformer,
|
EnergyKernelRepresentation,
|
||||||
LaplacianKernelTransformer,
|
LaplacianKernelRepresentation,
|
||||||
GaussianKernelTransformer,
|
GaussianKernelRepresentation,
|
||||||
GaussianRFFKernelTransformer,
|
GaussianRFFKernelRepresentation,
|
||||||
)
|
)
|
||||||
|
|
||||||
__all__ = [ # control public members, e.g., for auto-documentation in sphinx; omit QuaPyWrapper
|
|
||||||
"ComposableQuantifier",
|
|
||||||
"CVClassifier",
|
|
||||||
"LeastSquaresLoss",
|
|
||||||
"BlobelLoss",
|
|
||||||
"EnergyLoss",
|
|
||||||
"HellingerSurrogateLoss",
|
|
||||||
"CombinedLoss",
|
|
||||||
"TikhonovRegularization",
|
|
||||||
"TikhonovRegularized",
|
|
||||||
"ClassTransformer",
|
|
||||||
"HistogramTransformer",
|
|
||||||
"DistanceTransformer",
|
|
||||||
"KernelTransformer",
|
|
||||||
"EnergyKernelTransformer",
|
|
||||||
"LaplacianKernelTransformer",
|
|
||||||
"GaussianKernelTransformer",
|
|
||||||
"GaussianRFFKernelTransformer",
|
|
||||||
]
|
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
raise ImportError(_import_error_message) from e
|
raise ImportError(_IMPORT_ERROR_MESSAGE) from e
|
||||||
|
|
||||||
def ComposableQuantifier(loss, transformer, **kwargs):
|
__all__ = [ # control public members, e.g., for auto-documentation in sphinx
|
||||||
|
"QUnfoldWrapper",
|
||||||
|
"ComposableQuantifier",
|
||||||
|
"CVClassifier",
|
||||||
|
"LeastSquaresLoss",
|
||||||
|
"BlobelLoss",
|
||||||
|
"EnergyLoss",
|
||||||
|
"HellingerSurrogateLoss",
|
||||||
|
"CombinedLoss",
|
||||||
|
"TikhonovRegularization",
|
||||||
|
"TikhonovRegularized",
|
||||||
|
"ClassRepresentation",
|
||||||
|
"HistogramRepresentation",
|
||||||
|
"DistanceRepresentation",
|
||||||
|
"KernelRepresentation",
|
||||||
|
"EnergyKernelRepresentation",
|
||||||
|
"LaplacianKernelRepresentation",
|
||||||
|
"GaussianKernelRepresentation",
|
||||||
|
"GaussianRFFKernelRepresentation",
|
||||||
|
]
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class QUnfoldWrapper(BaseQuantifier,BaseMixin):
|
||||||
|
"""A thin wrapper for using qunfold methods in QuaPy.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
_method: An instance of `qunfold.methods.AbstractMethod` to wrap.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
Here, we wrap an instance of ACC to perform a grid search with QuaPy.
|
||||||
|
|
||||||
|
>>> from qunfold import ACC
|
||||||
|
>>> qunfold_method = QUnfoldWrapper(ACC(RandomForestClassifier(obb_score=True)))
|
||||||
|
>>> quapy.model_selection.GridSearchQ(
|
||||||
|
>>> model = qunfold_method,
|
||||||
|
>>> param_grid = { # try both splitting criteria
|
||||||
|
>>> "representation__classifier__estimator__criterion": ["gini", "entropy"],
|
||||||
|
>>> },
|
||||||
|
>>> # ...
|
||||||
|
>>> )
|
||||||
|
"""
|
||||||
|
_method: AbstractMethod
|
||||||
|
def fit(self, data): # data is a qp.LabelledCollection
|
||||||
|
self._method.fit(*data.Xy, data.n_classes)
|
||||||
|
return self
|
||||||
|
def quantify(self, X):
|
||||||
|
return self._method.predict(X)
|
||||||
|
def set_params(self, **params):
|
||||||
|
self._method.set_params(**params)
|
||||||
|
return self
|
||||||
|
def get_params(self, deep=True):
|
||||||
|
return self._method.get_params(deep)
|
||||||
|
def __str__(self):
|
||||||
|
return self._method.__str__()
|
||||||
|
|
||||||
|
def ComposableQuantifier(loss, representation, **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.
|
||||||
|
|
||||||
This class represents any quantifier that can be described in terms of a loss function, a feature transformation, and a regularization term. In this implementation, the loss is minimized through unconstrained second-order minimization. Valid probability estimates are ensured through a soft-max trick by Bunse (2022).
|
This class represents any quantifier that can be described in terms of a loss function, a feature transformation, and a regularization term. In this implementation, the loss is minimized through unconstrained second-order minimization. Valid probability estimates are ensured through a soft-max trick by Bunse (2022).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
loss: An instance of a loss class from `quapy.methods.composable`.
|
loss: An instance of a loss class from `quapy.methods.composable`.
|
||||||
transformer: An instance of a transformer class from `quapy.methods.composable`.
|
representation: An instance of a representation class from `quapy.methods.composable`.
|
||||||
solver (optional): The `method` argument in `scipy.optimize.minimize`. Defaults to `"trust-ncg"`.
|
solver (optional): The `method` argument in `scipy.optimize.minimize`. Defaults to `"trust-ncg"`.
|
||||||
solver_options (optional): The `options` argument in `scipy.optimize.minimize`. Defaults to `{"gtol": 1e-8, "maxiter": 1000}`.
|
solver_options (optional): The `options` argument in `scipy.optimize.minimize`. Defaults to `{"gtol": 1e-8, "maxiter": 1000}`.
|
||||||
seed (optional): A random number generator seed from which a numpy RandomState is created. Defaults to `None`.
|
seed (optional): A random number generator seed from which a numpy RandomState is created. Defaults to `None`.
|
||||||
|
|
@ -72,12 +114,12 @@ def ComposableQuantifier(loss, transformer, **kwargs):
|
||||||
>>> ComposableQuantifier,
|
>>> ComposableQuantifier,
|
||||||
>>> TikhonovRegularized,
|
>>> TikhonovRegularized,
|
||||||
>>> LeastSquaresLoss,
|
>>> LeastSquaresLoss,
|
||||||
>>> ClassTransformer,
|
>>> ClassRepresentation,
|
||||||
>>> )
|
>>> )
|
||||||
>>> from sklearn.ensemble import RandomForestClassifier
|
>>> from sklearn.ensemble import RandomForestClassifier
|
||||||
>>> o_acc = ComposableQuantifier(
|
>>> o_acc = ComposableQuantifier(
|
||||||
>>> TikhonovRegularized(LeastSquaresLoss(), 0.01),
|
>>> TikhonovRegularized(LeastSquaresLoss(), 0.01),
|
||||||
>>> ClassTransformer(RandomForestClassifier(oob_score=True))
|
>>> ClassRepresentation(RandomForestClassifier(oob_score=True))
|
||||||
>>> )
|
>>> )
|
||||||
|
|
||||||
Here, we perform hyper-parameter optimization with the ordinal ACC.
|
Here, we perform hyper-parameter optimization with the ordinal ACC.
|
||||||
|
|
@ -85,7 +127,7 @@ def ComposableQuantifier(loss, transformer, **kwargs):
|
||||||
>>> quapy.model_selection.GridSearchQ(
|
>>> quapy.model_selection.GridSearchQ(
|
||||||
>>> model = o_acc,
|
>>> model = o_acc,
|
||||||
>>> param_grid = { # try both splitting criteria
|
>>> param_grid = { # try both splitting criteria
|
||||||
>>> "transformer__classifier__estimator__criterion": ["gini", "entropy"],
|
>>> "representation__classifier__estimator__criterion": ["gini", "entropy"],
|
||||||
>>> },
|
>>> },
|
||||||
>>> # ...
|
>>> # ...
|
||||||
>>> )
|
>>> )
|
||||||
|
|
@ -96,7 +138,7 @@ def ComposableQuantifier(loss, transformer, **kwargs):
|
||||||
>>> from sklearn.linear_model import LogisticRegression
|
>>> from sklearn.linear_model import LogisticRegression
|
||||||
>>> acc_lr = ComposableQuantifier(
|
>>> acc_lr = ComposableQuantifier(
|
||||||
>>> LeastSquaresLoss(),
|
>>> LeastSquaresLoss(),
|
||||||
>>> ClassTransformer(CVClassifier(LogisticRegression(), 10))
|
>>> ClassRepresentation(CVClassifier(LogisticRegression(), 10))
|
||||||
>>> )
|
>>> )
|
||||||
"""
|
"""
|
||||||
return QuaPyWrapper(qunfold.GenericMethod(loss, transformer, **kwargs))
|
return QUnfoldWrapper(LinearMethod(loss, representation, **kwargs))
|
||||||
|
|
|
||||||
|
|
@ -14,20 +14,20 @@ from quapy.method.composable import (
|
||||||
ComposableQuantifier,
|
ComposableQuantifier,
|
||||||
LeastSquaresLoss,
|
LeastSquaresLoss,
|
||||||
HellingerSurrogateLoss,
|
HellingerSurrogateLoss,
|
||||||
ClassTransformer,
|
ClassRepresentation,
|
||||||
HistogramTransformer,
|
HistogramRepresentation,
|
||||||
CVClassifier,
|
CVClassifier,
|
||||||
)
|
)
|
||||||
COMPOSABLE_METHODS = [
|
COMPOSABLE_METHODS = [
|
||||||
ComposableQuantifier( # ACC
|
ComposableQuantifier( # ACC
|
||||||
LeastSquaresLoss(),
|
LeastSquaresLoss(),
|
||||||
ClassTransformer(CVClassifier(LogisticRegression()))
|
ClassRepresentation(CVClassifier(LogisticRegression()))
|
||||||
),
|
),
|
||||||
ComposableQuantifier( # HDy
|
ComposableQuantifier( # HDy
|
||||||
HellingerSurrogateLoss(),
|
HellingerSurrogateLoss(),
|
||||||
HistogramTransformer(
|
HistogramRepresentation(
|
||||||
3, # 3 bins per class
|
3, # 3 bins per class
|
||||||
preprocessor = ClassTransformer(CVClassifier(LogisticRegression()))
|
preprocessor = ClassRepresentation(CVClassifier(LogisticRegression()))
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue