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
|
||||
run: |
|
||||
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]
|
||||
- name: Test with unittest
|
||||
run: python -m unittest
|
||||
|
|
@ -47,7 +47,7 @@ jobs:
|
|||
- name: Install dependencies
|
||||
run: |
|
||||
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]
|
||||
- name: Build documentation
|
||||
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."""
|
||||
|
||||
_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:
|
||||
|
||||
pip install --upgrade pip setuptools wheel
|
||||
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:
|
||||
import qunfold
|
||||
from qunfold.quapy import QuaPyWrapper
|
||||
from qunfold.base import BaseMixin
|
||||
from qunfold.methods import AbstractMethod
|
||||
from qunfold.sklearn import CVClassifier
|
||||
from qunfold import (
|
||||
LinearMethod, # methods
|
||||
LeastSquaresLoss, # losses
|
||||
BlobelLoss,
|
||||
EnergyLoss,
|
||||
|
|
@ -21,17 +28,20 @@ try:
|
|||
CombinedLoss,
|
||||
TikhonovRegularization,
|
||||
TikhonovRegularized,
|
||||
ClassTransformer, # transformers
|
||||
HistogramTransformer,
|
||||
DistanceTransformer,
|
||||
KernelTransformer,
|
||||
EnergyKernelTransformer,
|
||||
LaplacianKernelTransformer,
|
||||
GaussianKernelTransformer,
|
||||
GaussianRFFKernelTransformer,
|
||||
ClassRepresentation, # representations
|
||||
HistogramRepresentation,
|
||||
DistanceRepresentation,
|
||||
KernelRepresentation,
|
||||
EnergyKernelRepresentation,
|
||||
LaplacianKernelRepresentation,
|
||||
GaussianKernelRepresentation,
|
||||
GaussianRFFKernelRepresentation,
|
||||
)
|
||||
except ImportError as e:
|
||||
raise ImportError(_IMPORT_ERROR_MESSAGE) from e
|
||||
|
||||
__all__ = [ # control public members, e.g., for auto-documentation in sphinx; omit QuaPyWrapper
|
||||
__all__ = [ # control public members, e.g., for auto-documentation in sphinx
|
||||
"QUnfoldWrapper",
|
||||
"ComposableQuantifier",
|
||||
"CVClassifier",
|
||||
"LeastSquaresLoss",
|
||||
|
|
@ -41,26 +51,58 @@ try:
|
|||
"CombinedLoss",
|
||||
"TikhonovRegularization",
|
||||
"TikhonovRegularized",
|
||||
"ClassTransformer",
|
||||
"HistogramTransformer",
|
||||
"DistanceTransformer",
|
||||
"KernelTransformer",
|
||||
"EnergyKernelTransformer",
|
||||
"LaplacianKernelTransformer",
|
||||
"GaussianKernelTransformer",
|
||||
"GaussianRFFKernelTransformer",
|
||||
]
|
||||
except ImportError as e:
|
||||
raise ImportError(_import_error_message) from e
|
||||
"ClassRepresentation",
|
||||
"HistogramRepresentation",
|
||||
"DistanceRepresentation",
|
||||
"KernelRepresentation",
|
||||
"EnergyKernelRepresentation",
|
||||
"LaplacianKernelRepresentation",
|
||||
"GaussianKernelRepresentation",
|
||||
"GaussianRFFKernelRepresentation",
|
||||
]
|
||||
|
||||
def ComposableQuantifier(loss, transformer, **kwargs):
|
||||
@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.
|
||||
|
||||
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:
|
||||
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_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`.
|
||||
|
|
@ -72,12 +114,12 @@ def ComposableQuantifier(loss, transformer, **kwargs):
|
|||
>>> ComposableQuantifier,
|
||||
>>> TikhonovRegularized,
|
||||
>>> LeastSquaresLoss,
|
||||
>>> ClassTransformer,
|
||||
>>> ClassRepresentation,
|
||||
>>> )
|
||||
>>> from sklearn.ensemble import RandomForestClassifier
|
||||
>>> o_acc = ComposableQuantifier(
|
||||
>>> TikhonovRegularized(LeastSquaresLoss(), 0.01),
|
||||
>>> ClassTransformer(RandomForestClassifier(oob_score=True))
|
||||
>>> ClassRepresentation(RandomForestClassifier(oob_score=True))
|
||||
>>> )
|
||||
|
||||
Here, we perform hyper-parameter optimization with the ordinal ACC.
|
||||
|
|
@ -85,7 +127,7 @@ def ComposableQuantifier(loss, transformer, **kwargs):
|
|||
>>> quapy.model_selection.GridSearchQ(
|
||||
>>> model = o_acc,
|
||||
>>> 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
|
||||
>>> acc_lr = ComposableQuantifier(
|
||||
>>> 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,
|
||||
LeastSquaresLoss,
|
||||
HellingerSurrogateLoss,
|
||||
ClassTransformer,
|
||||
HistogramTransformer,
|
||||
ClassRepresentation,
|
||||
HistogramRepresentation,
|
||||
CVClassifier,
|
||||
)
|
||||
COMPOSABLE_METHODS = [
|
||||
ComposableQuantifier( # ACC
|
||||
LeastSquaresLoss(),
|
||||
ClassTransformer(CVClassifier(LogisticRegression()))
|
||||
ClassRepresentation(CVClassifier(LogisticRegression()))
|
||||
),
|
||||
ComposableQuantifier( # HDy
|
||||
HellingerSurrogateLoss(),
|
||||
HistogramTransformer(
|
||||
HistogramRepresentation(
|
||||
3, # 3 bins per class
|
||||
preprocessor = ClassTransformer(CVClassifier(LogisticRegression()))
|
||||
preprocessor = ClassRepresentation(CVClassifier(LogisticRegression()))
|
||||
)
|
||||
),
|
||||
]
|
||||
|
|
|
|||
Loading…
Reference in New Issue