'''Feature mappings obtained using a threshold (Half planes).'''
import numpy as np
from sklearn.tree import DecisionTreeClassifier
from sklearn.utils import check_array, check_X_y
from sklearn.utils.validation import check_is_fitted
# Import the feature mapping base class
from MRCpy.phi import BasePhi
[docs]class ThresholdPhi(BasePhi):
'''
Threshold features
A threshold feature is a function, :math:`f(x_d,t)=1`
when :math:`x_d<t` and 0 otherwise,
for a given x in dimension d and threshold t in that dimension.
A product of threshold features is an indicator of a region
and its expectation is closely related to cumulative distributions.
This class obtains the thresholds fitting multiple one-dimensional
decision stumps on the training data.
.. seealso:: For more information about MRC, one can refer to the
following resources:
[1] `Mazuelas, S., Zanoni, A., & Pérez, A. (2020).
Minimax Classification with 0-1 Loss and Performance
Guarantees. Advances in Neural Information Processing
Systems, 33, 302-312. <https://arxiv.org/abs/2010.07964>`_
[2] `Mazuelas, S., Shen, Y., & Pérez, A. (2020).
Generalized Maximum Entropy for Supervised Classification.
arXiv preprint arXiv:2007.05447.
<https://arxiv.org/abs/2007.05447>`_
[3] `Bondugula, K., Mazuelas, S., & Pérez, A. (2021).
MRCpy: A Library for Minimax Risk Classifiers.
arXiv preprint arXiv:2108.01952.
<https://arxiv.org/abs/2108.01952>`_
Parameters
----------
n_classes : `int`
Number of classes in the dataset
fit_intercept : `bool`, default = `True`
Whether to calculate the intercept.
If set to false, no intercept will be used in calculations
(i.e. data is expected to be already centered).
one_hot : `bool`, default = `False`
Controls the method used for evaluating the features of the
given instances in the binary case.
Only applies in the binary case, namely, only when there are two
classes. If set to true, one-hot-encoding will be used. If set to
false a more efficient shorcut will be performed.
n_thresholds : `int`, default = `200`
Maximum number of allowed threshold values
for each dimension.
Attributes
----------
self.thrsVal : `array`-like of shape (`n_thresholds`)
Threshold values learned from the training data.
self.thrsDim : `array`-like of shape (`n_thresholds`)
Dimensions
corresponding to the learned threshold value in `self.thrsVal`.
is_fitted_ : `bool`
Whether the feature mappings has learned its hyperparameters (if any)
and the length of the feature mapping is set.
len_ : `int`
Length of the feature mapping vector.
'''
[docs] def __init__(self, n_classes, fit_intercept=True,
n_thresholds=200, one_hot=False):
# Call the base class init function.
super().__init__(n_classes=n_classes, fit_intercept=fit_intercept,
one_hot=one_hot)
self.n_thresholds = n_thresholds
[docs] def fit(self, X, Y=None):
'''
Learns the set of thresholds using one-dimensional decision stumps
obtained from the dataset.
Parameters
----------
X : `array`-like of shape (`n_samples`, `n_dimensions`)
Unlabeled training instances
used to learn the feature configurations.
Y : `array`-like of shape (`n_samples`,), default = `None`
Labels corresponding to the unlabeled instances X,
used for finding the thresholds from the dataset.
Returns
-------
self :
Fitted estimator
'''
X, Y = check_X_y(X, Y, accept_sparse=True)
# Obtain the thresholds from the instances-label pairs.
self.thrsDim_, self.thrsVal_ = self.d_tree_split(X, Y,
self.n_thresholds)
# Sets the length of the feature mapping
super().fit(X, Y)
return self
[docs] def d_tree_split(self, X, Y, n_thresholds=None):
'''
Learn the univariate thresholds
by using the split points of decision trees
for each dimension of data.
Parameters
----------
X : `array`-like of shape (`n_samples`, `n_dimensions`)
Unlabeled instances.
Y : `array`-like of shape (`n_samples`,)
Labels corresponding to the instances.
n_thresholds : `int`, default = `None`
Maximum limit on the number of thresholds obtained
Returns
-------
prodThrsDim : `array`-like of shape (`n_thresholds`)
Dimension in which the thresholds are defined.
prodThrsVal : `array`-like of shape (`n_thresholds`)
Threshold value in the corresponding dimension.
'''
(n, d) = X.shape
prodThrsVal = []
prodThrsDim = []
# One order thresholds: all the univariate thresholds
for dim in range(d):
if n_thresholds is None:
dt = DecisionTreeClassifier()
else:
dt = DecisionTreeClassifier(max_leaf_nodes=n_thresholds + 1)
dt.fit(np.reshape(X[:, dim], (n, 1)), Y)
dimThrsVal = np.sort(dt.tree_.threshold[dt.tree_.threshold != -2])
for t in dimThrsVal:
prodThrsVal.append([t])
prodThrsDim.append([dim])
return prodThrsDim, prodThrsVal