Repository: onnx/sklearn-onnx

Issue:
from sklearn.preprocessing import Imputer fails in scikit-learn 0.21



Discussion:

Resolving patch:
diff --git a/skl2onnx/_supported_operators.py b/skl2onnx/_supported_operators.py
--- a/skl2onnx/_supported_operators.py
+++ b/skl2onnx/_supported_operators.py
@@ -75,7 +75,11 @@
     # 0.19
     from sklearn.preprocessing import Imputer as SimpleImputer
 from sklearn.preprocessing import Binarizer
-from sklearn.preprocessing import Imputer
+try:
+    from sklearn.preprocessing import Imputer
+except ImportError:
+    # removed in 0.21
+    Imputer = None
 try:
     from sklearn.preprocessing import KBinsDiscretizer
 except ImportError:
diff --git a/skl2onnx/helpers/investigate.py b/skl2onnx/helpers/investigate.py
--- a/skl2onnx/helpers/investigate.py
+++ b/skl2onnx/helpers/investigate.py
@@ -13,7 +13,12 @@
 from sklearn.base import TransformerMixin, ClassifierMixin
 from sklearn.base import RegressorMixin, BaseEstimator
 from sklearn.pipeline import Pipeline, FeatureUnion
-from sklearn.compose import ColumnTransformer, TransformedTargetRegressor
+try:
+    from sklearn.compose import ColumnTransformer, TransformedTargetRegressor
+except ImportError:
+    # not avaiable in 0.19
+    ColumnTransformer = None
+    TransformedTargetRegressor = None
 from .. import convert_sklearn
 from ..helpers.onnx_helper import select_model_inputs_outputs
 
@@ -49,7 +54,7 @@ def enumerate_pipeline_models(pipe, coor=None, vs=None):
         for i, (_, model) in enumerate(pipe.steps):
             for couple in enumerate_pipeline_models(model, coor + (i,)):
                 yield couple
-    elif isinstance(pipe, ColumnTransformer):
+    elif ColumnTransformer is not None and isinstance(pipe, ColumnTransformer):
         for i, (_, fitted_transformer, column) in enumerate(pipe.transformers):
             for couple in enumerate_pipeline_models(
                     fitted_transformer, coor + (i,), column):
@@ -58,7 +63,8 @@ def enumerate_pipeline_models(pipe, coor=None, vs=None):
         for i, (_, model) in enumerate(pipe.transformer_list):
             for couple in enumerate_pipeline_models(model, coor + (i,)):
                 yield couple
-    elif isinstance(pipe, TransformedTargetRegressor):
+    elif TransformedTargetRegressor is not None and isinstance(
+            pipe, TransformedTargetRegressor):
         raise NotImplementedError(
             "Not yet implemented for TransformedTargetRegressor.")
     elif isinstance(pipe, (TransformerMixin, ClassifierMixin, RegressorMixin)):


Test patch:
diff --git a/tests/test_SklearnGradientBoostingConverters.py b/tests/test_SklearnGradientBoostingConverters.py
--- a/tests/test_SklearnGradientBoostingConverters.py
+++ b/tests/test_SklearnGradientBoostingConverters.py
@@ -19,9 +19,21 @@
 class TestSklearnGradientBoostingModels(unittest.TestCase):
     @unittest.skipIf(not onnx_built_with_ml(),
                      reason="Requires ONNX-ML extension.")
-    def test_gradient_boosting_classifier(self):
+    def test_gradient_boosting_classifier1(self):
+        model = GradientBoostingClassifier(n_estimators=1)
+        dump_binary_classification(
+            model, suffix="1",
+            allow_failure="StrictVersion(onnxruntime.__version__)"
+                          " <= StrictVersion('0.5.0')")
+
+    @unittest.skipIf(not onnx_built_with_ml(),
+                     reason="Requires ONNX-ML extension.")
+    def test_gradient_boosting_classifier3(self):
         model = GradientBoostingClassifier(n_estimators=3)
-        dump_binary_classification(model)
+        dump_binary_classification(
+            model, suffix="3",
+            allow_failure="StrictVersion(onnxruntime.__version__)"
+                          " <= StrictVersion('0.5.0')")
 
     @unittest.skipIf(not onnx_built_with_ml(),
                      reason="Requires ONNX-ML extension.")
@@ -30,7 +42,7 @@ def test_gradient_boosting_classifier_multi(self):
         dump_multiple_classification(
             model,
             allow_failure="StrictVersion(onnxruntime.__version__)"
-            "<= StrictVersion('0.3.0')",
+            "<= StrictVersion('0.5.0')",
         )
 
     def _fit_regression_model(self, model):
@@ -52,6 +64,8 @@ def test_gradient_boosting_regressor_ls_loss(self):
             model,
             model_onnx,
             basename="SklearnGradientBoostingRegressionLsLoss",
+            allow_failure="StrictVersion(onnxruntime.__version__)"
+                          " <= StrictVersion('0.5.0')"
         )
 
     def test_gradient_boosting_regressor_lad_loss(self):
diff --git a/tests/test_SklearnImputerConverter.py b/tests/test_SklearnImputerConverter.py
--- a/tests/test_SklearnImputerConverter.py
+++ b/tests/test_SklearnImputerConverter.py
@@ -3,7 +3,10 @@
 """
 import unittest
 import numpy as np
-from sklearn.preprocessing import Imputer
+try:
+    from sklearn.preprocessing import Imputer
+except ImportError:
+    Imputer = None
 
 try:
     from sklearn.impute import SimpleImputer
@@ -16,6 +19,8 @@
 
 
 class TestSklearnImputerConverter(unittest.TestCase):
+    @unittest.skipIf(Imputer is None,
+                     reason="Imputer removed in 0.21")
     def test_model_imputer(self):
         model = Imputer(missing_values="NaN", strategy="mean", axis=0)
         data = [[1, 2], [np.nan, 3], [7, 6]]
@@ -28,6 +33,8 @@ def test_model_imputer(self):
                                      [("input", Int64TensorType([1, 2]))])
         self.assertTrue(model_onnx is not None)
 
+    @unittest.skipIf(Imputer is None,
+                     reason="Imputer removed in 0.21")
     def test_imputer_int_inputs(self):
         model = Imputer(missing_values="NaN", strategy="mean", axis=0)
         data = [[1, 2], [np.nan, 3], [7, 6]]
@@ -42,6 +49,8 @@ def test_imputer_int_inputs(self):
         self.assertEqual(outputs[0].type.tensor_type.shape.dim[-1].dim_value,
                          2)
 
+    @unittest.skipIf(Imputer is None,
+                     reason="Imputer removed in 0.21")
     def test_imputer_float_inputs(self):
         model = Imputer(missing_values="NaN", strategy="mean", axis=0)
         data = [[1, 2], [np.nan, 3], [7, 6]]