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

Issue:
Add warnings to sklearn classifier wrapper. 
Warning in `fit` and `predict` method. Include information about the samples and class labels in the fit warning such that the user can decide whether the warning is okay or not.


Discussion / hints:

Fix patch:
diff --git a/skactiveml/classifier/_wrapper.py b/skactiveml/classifier/_wrapper.py
index 57e8e826..23428820 100644
--- a/skactiveml/classifier/_wrapper.py
+++ b/skactiveml/classifier/_wrapper.py
@@ -135,7 +135,7 @@ def predict(self, X, **predict_kwargs):
         check_is_fitted(self)
         X = check_array(X)
         self._check_n_features(X, reset=False)
-        try:
+        if self.is_fitted_:
             if self.cost_matrix is None:
                 y_pred = self.estimator_.predict(X, **predict_kwargs)
             else:
@@ -143,7 +143,7 @@ def predict(self, X, **predict_kwargs):
                 costs = np.dot(P, self.cost_matrix_)
                 y_pred = rand_argmin(costs, random_state=self._random_state,
                                      axis=1)
-        except Exception:
+        else:
             p = self.predict_proba([X[0]])[0]
             y_pred = self._random_state.choice(np.arange(len(self.classes_)),
                                                len(X),
@@ -173,7 +173,7 @@ def predict_proba(self, X, **predict_proba_kwargs):
         check_is_fitted(self)
         X = check_array(X)
         self._check_n_features(X, reset=False)
-        try:
+        if self.is_fitted_:
             P = self.estimator_.predict_proba(X, **predict_proba_kwargs)
             if len(self.estimator_.classes_) != len(self.classes_):
                 P_ext = np.zeros((len(X), len(self.classes_)))
@@ -181,7 +181,12 @@ def predict_proba(self, X, **predict_proba_kwargs):
                 P_ext[:, class_indices] = P
                 P = P_ext
             return P
-        except Exception:
+        else:
+            warnings.warn("Since the 'base_estimator' could not be fitted when"
+                          " calling the `fit` method, the class label "
+                          "distribution`_label_counts={}` is used to make "
+                          "the predictions."
+                          .format(self._label_counts))
             if sum(self._label_counts) == 0:
                 return np.ones([len(X), len(self.classes_)]) / len(
                     self.classes_)
@@ -244,10 +249,15 @@ def _fit(self, fit_function, X, y, sample_weight=None, **fit_kwargs):
                                         sample_weight=sample_weight[is_lbld],
                                         **fit_kwargs)
             self.is_fitted_ = True
-        except Exception:
+        except Exception as e:
             self.is_fitted_ = False
             self._label_counts = [np.sum(y[is_lbld] == c) for c in
                                   range(len(self._le.classes_))]
+            warnings.warn("The 'base_estimator' could not be fitted because of"
+                          " '{}'. Therefore, the class labels of the samples "
+                          "are counted and will be used to make predictions. "
+                          "The class label distribution is `_label_counts={}`."
+                          .format(e, self._label_counts))
         return self
 
     def __getattr__(self, item):


Test patch:
diff --git a/skactiveml/classifier/tests/test_wrapper.py b/skactiveml/classifier/tests/test_wrapper.py
index 6d5d3bee..09631bbe 100644
--- a/skactiveml/classifier/tests/test_wrapper.py
+++ b/skactiveml/classifier/tests/test_wrapper.py
@@ -1,4 +1,5 @@
 import unittest
+import warnings
 
 import numpy as np
 from sklearn.datasets import load_breast_cancer
@@ -65,7 +66,10 @@ def test_fit(self):
         np.testing.assert_array_equal(clf.classes_, ['new york', 'paris',
                                                      'tokyo'])
         self.assertEqual(clf.missing_label, 'nan')
-        clf.fit(self.X, self.y2)
+        with warnings.catch_warnings(record=True) as w:
+            warnings.simplefilter("always")
+            clf.fit(self.X, self.y2)
+            self.assertEqual(len(w), 1)
         self.assertFalse(clf.is_fitted_)
         self.assertFalse(hasattr(clf, "kernel_"))
         self.assertFalse(hasattr(clf, 'partial_fit'))
@@ -107,7 +111,10 @@ def test_predict_proba(self):
         np.testing.assert_array_equal(P_exp, P)
         np.testing.assert_array_equal(clf.classes_, est.classes_)
         clf.fit(X=self.X, y=self.y2)
-        P = clf.predict_proba(X=self.X)
+        with warnings.catch_warnings(record=True) as w:
+            warnings.simplefilter("always")
+            P = clf.predict_proba(X=self.X)
+            self.assertEqual(len(w), 1)
         P_exp = np.ones((len(self.X), 1))
         np.testing.assert_array_equal(P_exp, P)
         clf = SklearnClassifier(estimator=GaussianProcessClassifier(),
@@ -135,7 +142,10 @@ def test_predict(self):
         np.testing.assert_array_equal(y, y_exp)
         np.testing.assert_array_equal(clf.classes_, est.classes_)
         clf.fit(X=self.X, y=self.y2)
-        y = clf.predict(X=self.X)
+        with warnings.catch_warnings(record=True) as w:
+            warnings.simplefilter("always")
+            y = clf.predict(X=self.X)
+            self.assertEqual(len(w), 1)
         y_exp = ['tokyo'] * len(self.X)
         np.testing.assert_array_equal(y_exp, y)