Repository: scikit-activeml/scikit-activeml (language: python)

Issue:
codecov for uncertainty, qbc and epistemic
- [ ] uncertainty
- [ ] qbc
- [ ] epistemic


Discussion / hints:

Fix patch:
diff --git a/skactiveml/pool/_epistemic_uncertainty.py b/skactiveml/pool/_epistemic_uncertainty.py
index b160d0c9..653a60f4 100644
--- a/skactiveml/pool/_epistemic_uncertainty.py
+++ b/skactiveml/pool/_epistemic_uncertainty.py
@@ -165,7 +165,7 @@ def _epistemic_uncertainty_pwc(freq, precompute_array=None):
         Discovery Science. Springer, Cham, 2019.
     """
     if freq.shape[1] != 2:
-        raise ValueError('epistemic is only implemented for two-class '
+        raise ValueError('Epistemic is only implemented for two-class '
                          'problems, {} classes were given.'
                          ''.format(freq.shape[1]))
     n = freq[:, 0]
diff --git a/skactiveml/pool/_qbc.py b/skactiveml/pool/_qbc.py
index 2577186a..a3faed1e 100644
--- a/skactiveml/pool/_qbc.py
+++ b/skactiveml/pool/_qbc.py
@@ -35,15 +35,15 @@ class QBC(SingleAnnotPoolBasedQueryStrategy):
         implementing the methods 'fit', 'predict'(for vote entropy) and
         'predict_proba'(for KL divergence).
     ensemble : BaseEnsemble, default=None
-        wrapped sklear.ensemble used as committee. If None, baggingClassifier
-        is used.
+        sklearn.ensemble used to construct the committee. If None,
+        baggingClassifier is used.
     method : string, default='KL_divergence'
         The method to calculate the disagreement.
         'vote_entropy' or 'KL_divergence' are possible.
     random_state : numeric | np.random.RandomState
         Random state to use.
     ensemble_dict : dictionary
-        will be passed on to the ensemble.
+        Will be passed on to the ensemble.
 
     Attributes
     ----------
@@ -119,7 +119,7 @@ def query(self, X_cand, X, y, sample_weight=None,  batch_size=1,
 
         # Check if the attribute clf is valid
         if not isinstance(self._clf, SkactivemlClassifier):
-            raise TypeError('clf as to be from type SkactivemlClassifier. The #'
+            raise TypeError('clf has to be from type SkactivemlClassifier. The '
                             'given type is {}. Use the wrapper in '
                             'skactiveml.classifier to use a sklearn '
                             'classifier/ensemble.'.format(type(self.clf)))
@@ -137,19 +137,16 @@ def query(self, X_cand, X, y, sample_weight=None,  batch_size=1,
             raise ValueError(
                 "The given method {} is not valid. Supported methods are "
                 "'KL_divergence' and 'vote_entropy'".format(self.method))
-        if self.method == 'vote_entropy' and \
-                ((getattr(self._clf, 'fit', None) is None or
-                  getattr(self._clf, 'predict', None) is None)):
-            raise TypeError(
-                "'clf' must implement the methods 'fit' and 'predict'")
-        elif self.method == 'KL_divergence' and \
-                ((getattr(self._clf, 'fit', None) is None or
-                  getattr(self._clf, 'predict_proba', None) is None)):
+
+        if self.method == 'KL_divergence' and \
+                getattr(self._clf, 'predict_proba', None) is None:
             raise TypeError(
-                "'clf' must implement the methods 'fit' and 'predict_proba'")
+                "'clf' must implement the method 'predict_proba'")
 
+        # Build ensemble if necessary.
         if not isinstance(self._clf, SklearnClassifier) or \
                 not isinstance(self._clf.estimator, BaseEnsemble):
+            # Validate 'ensemble'.
             if self.ensemble is None:
                 warnings.warn('\'ensemble\' is not specified, '
                               '\'BaggingClassifier\' will be used.')
@@ -162,6 +159,7 @@ def query(self, X_cand, X, y, sample_weight=None,  batch_size=1,
                                 "'self.ensemble'.".format(type(self.ensemble)))
             else:
                 ensemble = self.ensemble
+            # Build ensemble.
             parameters = inspect.signature(ensemble.__init__).parameters
             if not isinstance(ensemble_dict, dict):
                 raise TypeError("ensemble_dict is not a dictionary.")


Test patch:
diff --git a/skactiveml/pool/tests/test_epistemic_uncertainty.py b/skactiveml/pool/tests/test_epistemic_uncertainty.py
index 873f2919..e6dbfb25 100644
--- a/skactiveml/pool/tests/test_epistemic_uncertainty.py
+++ b/skactiveml/pool/tests/test_epistemic_uncertainty.py
@@ -175,6 +175,19 @@ def test_epistemic_uncertainty_pwc(self):
         np.testing.assert_array_equal(
             val_utilities, precompute_array[:11, :11].flatten())
 
+        class Dummy_PWC(PWC):
+            def predict_freq(self, X):
+                return freq
+
+        selector = EpistemicUncertainty(
+            clf=Dummy_PWC(classes=self.classes), precompute=True)
+        _, utilities = selector.query(**self.kwargs, return_utilities=True)
+        np.testing.assert_array_equal(val_utilities, utilities[0])
+
+        selector = EpistemicUncertainty(clf=PWC(classes=[0, 1, 2]))
+        self.assertRaises(ValueError, selector.query, **self.kwargs)
+
+
     # tests for epistemic logistic regression
     def test_loglike_logreg(self):
         w = np.array([0, 0])
diff --git a/skactiveml/pool/tests/test_qbc.py b/skactiveml/pool/tests/test_qbc.py
index 44d6aafc..332fcefa 100644
--- a/skactiveml/pool/tests/test_qbc.py
+++ b/skactiveml/pool/tests/test_qbc.py
@@ -30,6 +30,8 @@ def test_init_param_clf(self):
 
         selector = QBC(clf=GaussianProcessClassifier())
         self.assertRaises(TypeError, selector.query, **self.kwargs)
+        selector = QBC(clf=SklearnClassifier(GaussianProcessRegressor()))
+        self.assertRaises(TypeError, selector.query, **self.kwargs)
         selector = QBC(clf='string')
         self.assertRaises(TypeError, selector.query, **self.kwargs)
         selector = QBC(clf=None)
@@ -44,6 +46,9 @@ def test_init_param_ensemble(self):
         selector = QBC(clf=self.clf, ensemble='String')
         self.assertRaises(TypeError, selector.query, **self.kwargs)
 
+        selector = QBC(clf=self.clf, ensemble=PWC)
+        self.assertRaises(TypeError, selector.query, **self.kwargs)
+
     def test_init_param_method(self):
         selector = QBC(clf=self.clf)
         self.assertTrue(hasattr(selector, 'method'))
diff --git a/skactiveml/pool/tests/test_uncertainty.py b/skactiveml/pool/tests/test_uncertainty.py
index 3012d6ea..aae0b471 100644
--- a/skactiveml/pool/tests/test_uncertainty.py
+++ b/skactiveml/pool/tests/test_uncertainty.py
@@ -1,7 +1,8 @@
 import unittest
 
 import numpy as np
-from sklearn.gaussian_process import GaussianProcessClassifier
+from sklearn.gaussian_process import GaussianProcessClassifier, \
+    GaussianProcessRegressor
 
 from skactiveml.classifier import SklearnClassifier, PWC
 from skactiveml.pool import UncertaintySampling, expected_average_precision
@@ -35,6 +36,12 @@ def test_init_param_clf(self):
         self.assertRaises(TypeError, selector.query, **self.kwargs)
         selector = UncertaintySampling(clf=1)
         self.assertRaises(TypeError, selector.query, **self.kwargs)
+        selector = UncertaintySampling(clf=GaussianProcessClassifier())
+        self.assertRaises(TypeError, selector.query, **self.kwargs)
+        selector = UncertaintySampling(
+            clf=SklearnClassifier(GaussianProcessRegressor())
+        )
+        self.assertRaises(TypeError, selector.query, **self.kwargs)
 
     def test_init_param_method(self):
         selector = UncertaintySampling(clf=self.clf)
@@ -162,6 +169,14 @@ def test_query(self):
         selector.query(X_cand=[[1]], X=[[1]], y=[MISSING_LABEL])
         compare_list.append(selector.query(**self.kwargs))
 
+        selector = UncertaintySampling(clf=clf, method='margin_sampling',
+                                       cost_matrix=[[0, 1], [1, 0]])
+        selector.query(X_cand=[[1]], X=[[1]], y=[MISSING_LABEL])
+
+        selector = UncertaintySampling(clf=clf, method='least_confident',
+                                       cost_matrix=[[0, 1], [1, 0]])
+        selector.query(X_cand=[[1]], X=[[1]], y=[MISSING_LABEL])
+
         for x in compare_list:
             self.assertEqual(compare_list[0], x)