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)
Ambos tienen el mismo 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'
Esto funciona cuando es np.nan
lugar de None
@freddyaboulton ¡ gracias por el claro reproductor! Parece que esto también explica otro error # 1092.
Problema
Si alguna característica en el marco de datos de pandas tiene el tipo object
y contiene un None
, nuestro Imputer
falla.
X = pd.DataFrame({'feature1': [False, True, None, np.nan]})
crea una función con el tipo object
. Imputer.fit
falla.X = pd.DataFrame({'feature1': [False, True, np.nan]})
crea una función con el tipo object
. Imputer.fit
funciona.X = pd.DataFrame({'feature1': [False, True]})
crea una función con el tipo bool
. Imputer.fit
funciona.Lo mismo ocurre con el tipo category
. Una situación similar ocurre con los tipos de cadenas, aunque el último caso no se aplica.
Notas
Lo confuso aquí es que None
puede significar cosas diferentes. Podría ser lo mismo que nan
, o podría ser su propia categoría.
Creo que está bien tratarlo como nan
siempre que documentemos y expliquemos esa convención.
Solución alterna
Limpiar None
de características bool / categoría / cadena: df = df.fillna(value=np.nan)
Reparar
Término corto:
Imputer
para reemplazar None
con np.nan
Imputer
API doc y automl user guide para mencionar esto.Imputer
con la inclusión de None
en los datos, para todos los tipos de datos previstos.En su lugar, podríamos agregar un DataCheck
que errores si hay None
s en los datos. Pero esto parece innecesario ya que None
s se pueden convertir fácilmente.
A largo plazo:
Una vez que actualicemos evalml para usar la nueva estructura de datos DataTable
, los usuarios podrán configurar los tipos de cada característica con anticipación. Espero que esto signifique que la estandarización hará que este tipo de errores sean irrelevantes.
¿Está esto relacionado con el n. ° 540?
@ angela97lin 🤦 100% relacionado ... de hecho es un dup. Ja ja. Incluso decidimos que el imputador convirtiera None
s en np.nan
s.
Cerrando el n. ° 540 a favor de esto porque los informes aquí están más actualizados.
¡Gracias!