Repository: automl/auto-sklearn

Issue:
Fit for AutoSklearn2Classifier fails whens input matrix is in CSR sparse Format
## Describe the bug ##
When fitting a CSR matrix on the AutoSklearn2Classifier, the method fails and returns `Trying to set illegal value 'gradient_boosting'`

python version: 3.9
auto-sklearn version: 0.13.0

## To Reproduce ##
Steps to reproduce the behavior:
```
import sklearn.datasets
from scipy import sparse
from autosklearn.experimental.askl2 import AutoSklearn2Classifier

X, y = sklearn.datasets.load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = \
    sklearn.model_selection.train_test_split(X, y, random_state=1)

X_train = sparse.csr_matrix(X_train)
automl = AutoSklearn2Classifier(
    time_left_for_this_task=120,
    per_run_time_limit=30
)
automl.fit(X_train, y_train, dataset_name='breast_cancer')
```

Note, the above works fine when using `autosklearn.classification.AutoSklearnClassifier`.

The use case for a CSR matrix is fitting text classification models after the text has been transformed into a TF-IDF format.



Discussion:
Hi @JohnnyC08, thanks for the bug report and the reproducible code. I can confirm this causes the same error but I can't immediately tell why. 

I will address it as soon as I can as sparsity is a frequency culprit of issues, but in the meantime I'm afraid you will have to go with the non-experimental version. 
I am getting the same  scipy versioning error.

```python
IncorrectPackageVersionError              Traceback (most recent call last)
<ipython-input-18-d5ddfef4f125> in <module>
      1 # !pip install scipy
      2 from sklearn import metrics
----> 3 from autosklearn import regression
      4 from autosklearn.estimators import AutoSklearnRegressor
      5 import matplotlib.pyplot as plt

/opt/conda/lib/python3.7/site-packages/autosklearn/__init__.py in <module>
     11 requirements = requirements.decode('utf-8')
     12 
---> 13 dependencies.verify_packages(requirements)
     14 
     15 if os.name != 'posix':

/opt/conda/lib/python3.7/site-packages/autosklearn/util/dependencies.py in verify_packages(packages)
     23             operation = match.group('operation1')
     24             version = match.group('version1')
---> 25             _verify_package(name, operation, version)
     26         else:
     27             raise ValueError('Unable to read requirement: %s' % package)

/opt/conda/lib/python3.7/site-packages/autosklearn/util/dependencies.py in _verify_package(name, operation, version)
     60     if not check:
     61         raise IncorrectPackageVersionError(name, installed_version, operation,
---> 62                                            required_version)
     63 
     64 

IncorrectPackageVersionError: found 'scipy' version 1.6.3 but requires scipy version >=1.7.0
```

Resolving patch:
diff --git a/autosklearn/automl.py b/autosklearn/automl.py
--- a/autosklearn/automl.py
+++ b/autosklearn/automl.py
@@ -1187,7 +1187,7 @@ def refit(self, X, y):
                             budget_type=self._budget_type,
                             logger=self._logger,
                             model=model,
-                            train_indices=np.arange(len(X), dtype=int),
+                            train_indices=np.arange(X.shape[0], dtype=int),
                             task_type=self._task,
                         )
                     break
diff --git a/autosklearn/experimental/askl2.py b/autosklearn/experimental/askl2.py
--- a/autosklearn/experimental/askl2.py
+++ b/autosklearn/experimental/askl2.py
@@ -6,6 +6,7 @@
 from typing import Any, Dict, List, Optional, Union
 
 import dask.distributed
+import scipy.sparse
 
 from ConfigSpace import Configuration
 import numpy as np
@@ -92,9 +93,14 @@ def __call__(
 
         scenario = Scenario(scenario_dict)
 
-        initial_configurations = [
-            Configuration(configuration_space=scenario.cs, values=member)
-            for member in self.portfolio.values()]
+        initial_configurations = []
+        for member in self.portfolio.values():
+            try:
+                initial_configurations.append(
+                    Configuration(configuration_space=scenario.cs, values=member)
+                )
+            except ValueError:
+                pass
 
         rh2EPM = RunHistory2EPM4LogCost
         return SMAC4AC(
@@ -134,9 +140,15 @@ def __call__(
         from smac.scenario.scenario import Scenario
 
         scenario = Scenario(scenario_dict)
-        initial_configurations = [
-            Configuration(configuration_space=scenario.cs, values=member)
-            for member in self.portfolio.values()]
+
+        initial_configurations = []
+        for member in self.portfolio.values():
+            try:
+                initial_configurations.append(
+                    Configuration(configuration_space=scenario.cs, values=member)
+                )
+            except ValueError:
+                pass
 
         rh2EPM = RunHistory2EPM4LogCost
         ta_kwargs['budget_type'] = self.budget_type
@@ -341,6 +353,25 @@ def fit(self, X, y,
             feat_type=None,
             dataset_name=None):
 
+        # TODO
+        # regularly check https://github.com/scikit-learn/scikit-learn/issues/15336 whether
+        # histogram gradient boosting in scikit-learn finally support sparse data
+        is_sparse = scipy.sparse.issparse(X)
+        if is_sparse:
+            include_estimators = [
+                'extra_trees', 'passive_aggressive', 'random_forest', 'sgd', 'mlp',
+            ]
+        else:
+            include_estimators = [
+                'extra_trees',
+                'passive_aggressive',
+                'random_forest',
+                'sgd',
+                'gradient_boosting',
+                'mlp',
+            ]
+        self.include['classifier'] = include_estimators
+
         if self.metric is None:
             if len(y.shape) == 1 or y.shape[1] == 1:
                 self.metric = accuracy


Test patch:
diff --git a/test/test_automl/test_estimators.py b/test/test_automl/test_estimators.py
--- a/test/test_automl/test_estimators.py
+++ b/test/test_automl/test_estimators.py
@@ -816,6 +816,31 @@ def test_autosklearn2_classification_methods_returns_self(dask_client):
     pickle.dumps(automl_fitted)
 
 
+def test_autosklearn2_classification_methods_returns_self_sparse(dask_client):
+    X_train, y_train, X_test, y_test = putil.get_dataset('breast_cancer', make_sparse=True)
+    automl = AutoSklearn2Classifier(time_left_for_this_task=60, ensemble_size=0,
+                                    delete_tmp_folder_after_terminate=False,
+                                    dask_client=dask_client)
+
+    automl_fitted = automl.fit(X_train, y_train)
+    assert automl is automl_fitted
+
+    automl_ensemble_fitted = automl.fit_ensemble(y_train, ensemble_size=5)
+    assert automl is automl_ensemble_fitted
+
+    automl_refitted = automl.refit(X_train.copy(), y_train.copy())
+    assert automl is automl_refitted
+
+    predictions = automl_fitted.predict(X_test)
+    assert sklearn.metrics.accuracy_score(
+        y_test, predictions
+    ) >= 2 / 3, print_debug_information(automl)
+
+    assert "boosting" not in str(automl.get_configuration_space(X=X_train, y=y_train))
+
+    pickle.dumps(automl_fitted)
+
+
 @pytest.mark.parametrize("class_", [AutoSklearnClassifier, AutoSklearnRegressor,
                                     AutoSklearn2Classifier])
 def test_check_estimator_signature(class_):