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)
Keduanya memiliki stacktrace yang sama:
---------------------------------------------------------------------------
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'
Ini berfungsi ketika np.nan
bukannya None
@freddyaboulton terima kasih untuk reproduksi yang jelas! Tampaknya ini menjelaskan bug lain # 1092 juga.
Masalah
Jika ada fitur dalam kerangka data pandas yang memiliki tipe object
dan berisi nilai None
, Imputer
gagal.
X = pd.DataFrame({'feature1': [False, True, None, np.nan]})
membuat fitur dengan tipe object
. Imputer.fit
gagal.X = pd.DataFrame({'feature1': [False, True, np.nan]})
membuat fitur dengan tipe object
. Imputer.fit
berfungsi.X = pd.DataFrame({'feature1': [False, True]})
membuat fitur dengan tipe bool
. Imputer.fit
berfungsi.Hal yang sama berlaku untuk tipe category
. Situasi serupa terjadi untuk tipe string, meskipun kasus terakhir tidak berlaku.
Catatan
Hal yang membingungkan di sini adalah bahwa None
dapat memiliki arti yang berbeda. Itu bisa sama dengan nan
, atau bisa juga dimaksudkan sebagai kategorinya sendiri.
Saya pikir tidak apa-apa untuk memperlakukannya sebagai nan
selama kita mendokumentasikan dan menjelaskan konvensi itu.
Solusi
Bersihkan None
dari fitur bool/category/string: df = df.fillna(value=np.nan)
Memperbaiki
Jangka pendek:
Imputer
untuk mengganti None
dengan np.nan
Imputer
dan panduan pengguna automl untuk menyebutkan ini.Imputer
dengan penyertaan None
dalam data, untuk semua tipe data yang dimaksud.Kita bisa menambahkan DataCheck
yang error jika ada None
s dalam data. Tapi ini terasa tidak perlu karena None
s dapat dengan mudah dikonversi.
Jangka panjang:
Setelah kami memperbarui evalml untuk menggunakan struktur data DataTable
, pengguna akan dapat mengonfigurasi jenis setiap fitur sebelumnya. Saya harap ini berarti standardisasi akan membuat kesalahan semacam ini tidak relevan.
Apakah ini terkait dengan #540?
@ angela97lin 100% terkait... sebenarnya ini adalah tipuan. Ha ha. Kami bahkan memutuskan untuk meminta imputer mengonversi None
s ke np.nan
s.
Menutup #540 mendukung ini karena tulisan di sini lebih mutakhir.
Terima kasih!