parent
8f3f880afd
commit
89e5b9c2bf
@ -0,0 +1,34 @@
|
|||||||
|
# MIPLearn: Extensible Framework for Learning-Enhanced Mixed-Integer Optimization
|
||||||
|
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
|
||||||
|
# Released under the modified BSD license. See COPYING.md for more details.
|
||||||
|
|
||||||
|
from unittest.mock import Mock
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
from miplearn.classifiers import Classifier
|
||||||
|
from miplearn.classifiers.threshold import MinPrecisionThreshold
|
||||||
|
|
||||||
|
|
||||||
|
def test_threshold_dynamic():
|
||||||
|
clf = Mock(spec=Classifier)
|
||||||
|
clf.predict_proba = Mock(return_value=np.array([
|
||||||
|
[0.10, 0.90],
|
||||||
|
[0.10, 0.90],
|
||||||
|
[0.20, 0.80],
|
||||||
|
[0.30, 0.70],
|
||||||
|
]))
|
||||||
|
x_train = np.array([0, 1, 2, 3])
|
||||||
|
y_train = np.array([1, 1, 0, 0])
|
||||||
|
|
||||||
|
threshold = MinPrecisionThreshold(min_precision=1.0)
|
||||||
|
assert threshold.find(clf, x_train, y_train) == 0.90
|
||||||
|
|
||||||
|
threshold = MinPrecisionThreshold(min_precision=0.65)
|
||||||
|
assert threshold.find(clf, x_train, y_train) == 0.80
|
||||||
|
|
||||||
|
threshold = MinPrecisionThreshold(min_precision=0.50)
|
||||||
|
assert threshold.find(clf, x_train, y_train) == 0.70
|
||||||
|
|
||||||
|
threshold = MinPrecisionThreshold(min_precision=0.00)
|
||||||
|
assert threshold.find(clf, x_train, y_train) == 0.70
|
||||||
|
|
@ -0,0 +1,45 @@
|
|||||||
|
# MIPLearn: Extensible Framework for Learning-Enhanced Mixed-Integer Optimization
|
||||||
|
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
|
||||||
|
# Released under the modified BSD license. See COPYING.md for more details.
|
||||||
|
|
||||||
|
from abc import abstractmethod, ABC
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
from sklearn.metrics._ranking import _binary_clf_curve
|
||||||
|
|
||||||
|
|
||||||
|
class DynamicThreshold(ABC):
|
||||||
|
@abstractmethod
|
||||||
|
def find(self, clf, x_train, y_train):
|
||||||
|
"""
|
||||||
|
Given a trained binary classifier `clf` and a training data set,
|
||||||
|
returns the numerical threshold (float) satisfying some criterea.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class MinPrecisionThreshold(DynamicThreshold):
|
||||||
|
"""
|
||||||
|
The smallest possible threshold satisfying a minimum acceptable true
|
||||||
|
positive rate (also known as precision).
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, min_precision):
|
||||||
|
self.min_precision = min_precision
|
||||||
|
|
||||||
|
def find(self, clf, x_train, y_train):
|
||||||
|
proba = clf.predict_proba(x_train)
|
||||||
|
|
||||||
|
assert isinstance(proba, np.ndarray), \
|
||||||
|
"classifier should return numpy array"
|
||||||
|
assert proba.shape == (x_train.shape[0], 2), \
|
||||||
|
"classifier should return (%d,%d)-shaped array, not %s" % (
|
||||||
|
x_train.shape[0], 2, str(proba.shape))
|
||||||
|
|
||||||
|
fps, tps, thresholds = _binary_clf_curve(y_train, proba[:, 1])
|
||||||
|
precision = tps / (tps + fps)
|
||||||
|
|
||||||
|
for k in reversed(range(len(precision))):
|
||||||
|
if precision[k] >= self.min_precision:
|
||||||
|
return thresholds[k]
|
||||||
|
return 2.0
|
Loading…
Reference in new issue