from evalml.pipelines.components import Imputer
df = pd.DataFrame({"a": [1, 2, 3], "b": ["1", "2", None]})
imputer = Imputer()
imputer.fit(df)
from evalml.pipelines.components import Imputer
df_with_bool = pd.DataFrame({"a": [1, 2, 3], "b": [True, False, None]})
imputer = Imputer()
imputer.fit(df_with_bool)
Beide haben den gleichen Stacktrace:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-69-9af4cfc17aec> in <module>
1 df_with_bool = pd.DataFrame({"a": [1, 2, 3], "b": [True, False, None]})
2 imputer = Imputer()
----> 3 imputer.fit(df_with_bool)
~/sources/evalml/evalml/utils/base_meta.py in _set_fit(self, X, y)
12 @wraps(method)
13 def _set_fit(self, X, y=None):
---> 14 return_value = method(self, X, y)
15 self._is_fitted = True
16 return return_value
~/sources/evalml/evalml/pipelines/components/transformers/imputers/imputer.py in fit(self, X, y)
76 X_categorical = X_null_dropped.select_dtypes(include=categorical_dtypes + boolean)
77 if len(X_categorical.columns) > 0:
---> 78 self._categorical_imputer.fit(X_categorical, y)
79 self._categorical_cols = X_categorical.columns
80 return self
~/sources/evalml/evalml/utils/base_meta.py in _set_fit(self, X, y)
12 @wraps(method)
13 def _set_fit(self, X, y=None):
---> 14 return_value = method(self, X, y)
15 self._is_fitted = True
16 return return_value
~/sources/evalml/evalml/pipelines/components/transformers/imputers/simple_imputer.py in fit(self, X, y)
42 if not isinstance(X, pd.DataFrame):
43 X = pd.DataFrame(X)
---> 44 self._component_obj.fit(X, y)
45 self._all_null_cols = set(X.columns) - set(X.dropna(axis=1, how='all').columns)
46 return self
~/miniconda3/envs/evalml/lib/python3.8/site-packages/sklearn/impute/_base.py in fit(self, X, y)
300 fill_value)
301 else:
--> 302 self.statistics_ = self._dense_fit(X,
303 self.strategy,
304 self.missing_values,
~/miniconda3/envs/evalml/lib/python3.8/site-packages/sklearn/impute/_base.py in _dense_fit(self, X, strategy, missing_values, fill_value)
384 row_mask = np.logical_not(row_mask).astype(np.bool)
385 row = row[row_mask]
--> 386 most_frequent[i] = _most_frequent(row, np.nan, 0)
387
388 return most_frequent
~/miniconda3/envs/evalml/lib/python3.8/site-packages/sklearn/impute/_base.py in _most_frequent(array, extra_value, n_repeat)
40 # has already been NaN-masked.
41 warnings.simplefilter("ignore", RuntimeWarning)
---> 42 mode = stats.mode(array)
43
44 most_frequent_value = mode[0][0]
~/miniconda3/envs/evalml/lib/python3.8/site-packages/scipy/stats/stats.py in mode(a, axis, nan_policy)
498 counts = np.zeros(a_view.shape[:-1], dtype=np.int)
499 for ind in inds:
--> 500 modes[ind], counts[ind] = _mode1D(a_view[ind])
501 newshape = list(a.shape)
502 newshape[axis] = 1
~/miniconda3/envs/evalml/lib/python3.8/site-packages/scipy/stats/stats.py in _mode1D(a)
485
486 def _mode1D(a):
--> 487 vals, cnts = np.unique(a, return_counts=True)
488 return vals[cnts.argmax()], cnts.max()
489
<__array_function__ internals> in unique(*args, **kwargs)
~/miniconda3/envs/evalml/lib/python3.8/site-packages/numpy/lib/arraysetops.py in unique(ar, return_index, return_inverse, return_counts, axis)
259 ar = np.asanyarray(ar)
260 if axis is None:
--> 261 ret = _unique1d(ar, return_index, return_inverse, return_counts)
262 return _unpack_tuple(ret)
263
~/miniconda3/envs/evalml/lib/python3.8/site-packages/numpy/lib/arraysetops.py in _unique1d(ar, return_index, return_inverse, return_counts)
320 aux = ar[perm]
321 else:
--> 322 ar.sort()
323 aux = ar
324 mask = np.empty(aux.shape, dtype=np.bool_)
TypeError: '<' not supported between instances of 'NoneType' and 'bool'
Dies funktioniert, wenn es np.nan
anstelle von None
@freddyaboulton danke für den klaren Reproduzierer! Es scheint, dass dies auch einen anderen Fehler #1092 erklärt.
Problem
Wenn irgendeine Funktion in der Pandas hat Datenrahmen object
Typen und enthält einen None
Wert, unser Imputer
ausfällt.
X = pd.DataFrame({'feature1': [False, True, None, np.nan]})
erstellt ein Feature mit dem Typ object
. Imputer.fit
schlägt fehl.X = pd.DataFrame({'feature1': [False, True, np.nan]})
erstellt ein Feature mit dem Typ object
. Imputer.fit
funktioniert.X = pd.DataFrame({'feature1': [False, True]})
erstellt ein Feature mit dem Typ bool
. Imputer.fit
funktioniert.Das gleiche gilt für den Typ category
. Eine ähnliche Situation tritt für Zeichenfolgentypen auf, obwohl der letzte Fall nicht zutrifft.
Anmerkungen
Das Verwirrende hier ist, dass None
verschiedene Bedeutungen haben kann. Es könnte dasselbe wie nan
oder als eigene Kategorie gedacht sein.
Ich denke, es ist in Ordnung, es als nan
zu behandeln, solange wir diese Konvention dokumentieren und erklären.
Problemumgehung
Bereinigen Sie None
aus Bool-/Kategorie-/String-Features: df = df.fillna(value=np.nan)
Fix
Kurzfristig:
Imputer
aktualisieren, um None
durch np.nan
zu ersetzenImputer
API-Dokument und das automl-Benutzerhandbuch, um dies zu erwähnen.Imputer
fügen Sie None
in die Daten ein.Wir könnten stattdessen ein DataCheck
hinzufügen, welches Fehler enthält, wenn es None
s in den Daten gibt. Dies fühlt sich jedoch unnötig an, da None
s leicht konvertiert werden können.
Langfristig:
Sobald wir evalml so aktualisiert haben, dass es die neue DataTable
Datenstruktur verwendet, können Benutzer die Typen jeder Funktion im Voraus konfigurieren. Ich hoffe, dies bedeutet, dass die Standardisierung diese Art von Fehlern irrelevant macht.
Hat das mit #540 zu tun?
@angela97lin 🤦 100% verwandt ... in der Tat ist es ein Dup. Haha. Dort haben wir sogar beschlossen, dass der Imputer None
s in np.nan
s umwandelt.
Schließe #540 dafür, weil die Zuschreibungen hier aktueller sind.
Vielen Dank!