我们的一个热编码器为原始分类特征的每个级别创建一个特征:
from evalml.pipelines import OneHotEncoder
import pandas as pd
df = pd.DataFrame({"category": ["a", "b"], "number": [4,5 ]})
OneHotEncoder().fit_transform(df).to_dataframe()
category_a
和category_b
列是完全共线的,这使得一个冗余。 这可能对估计器拟合产生不利影响。 我认为我们应该默认删除一个。
仅供参考@rpeck
💯 % 我们应该删除负数列。
如果我们先自己做 OHE,那么 sklearn 希望不会扩展它们。 正如弗雷迪所说,您可以将其视为生成具有完美共线性的两列。
将二进制文件扩展为两列而不是一列时,我看到了两个问题:
@freddyaboulton问:上面的 OHE 列数据
@rpeck是的!
@freddyaboulton什么? 那真是怪了。 除了真正的布尔值或 0/1 整数之外,我从未见过任何东西。 我想知道树模型实际上是如何处理这个问题的。 它对我有难闻的气味。
代码第三定律:你不应该做 == 与浮点数的比较
(好的,除非它与Math.NaN
)
嗯,我以为我们正在这样做!
我同意我们应该。 我认为这只是我们必须在底层实现中设置的标志。
@dsherry @freddyaboulton看起来我们通过我们的drop
参数支持它,但只考虑用户输入并且不被我们的 impl 使用,所以这个问题只是跟踪为drop
设置默认值除了None之外的东西?
https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html
我们可以选择first
或if_binary
,但不确定正确的调用是什么。
@angela97lin你说得对,更改默认值就足够了! 我认为first
是要走的路,因为即使类别数> 2,我们也应该避免完全共线的特征。你觉得@rpeck怎么
读了一点,发现这个链接: https :
关键要点:
RE @rpeck的第一条评论:“像其他形式的特征共线性一样,它在可解释性方面
这对于二进制情况是有意义的,但是在我们有多个类别的情况下,删除一个列仍然会出现这个问题。
也许我们不应该默认这样做,但如果估计器是线性回归器,则应该更新make_pipeline
以创建一个以first
作为参数的 OHE?
唉,我对做出判断的基础数学没有很强的把握,所以我很想听听你的想法, @ freddyaboulton @rpeck @dsherry
与@freddyaboulton @rpeck @dsherry @chukarsten @jeremyliweishih讨论后
@angela97lin听起来不错的 RE 默认行为。 另一个不错的选择:通过组件参数覆盖默认行为的能力
@dsherry如果我理解正确,因为我们正在更新drop
(一个参数)的默认值,用户将能够通过手动设置组件参数来覆盖它?
四处挖掘,看看实现这一点需要什么。 特别是,我很好奇在二进制情况下总是删除少数类是多么困难。
挖掘的结果是:
drop
参数的数组选项(https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html)来实现。 但是,在尝试之后,它要求为每一列指定一个索引值。 因此,以下内容试图删除在索引 0 处为第 0 列指定的类别,并且没有为第 1 列和第 2 列错误删除其他值:import pandas as pd
import numpy as np
from sklearn.preprocessing import OneHotEncoder
X = pd.DataFrame({'col_1': ["a", "b", "b", "a", "b"],
'col_2': ["a", "b", "a", "c", "b"],
'col_3': ["a", "a", "a", "a", "a"]})
indices_to_drop = np.array([0, None, None])
ohe = OneHotEncoder(drop=indices_to_drop)
ohe.fit(X)
ValueError Traceback (most recent call last)
<ipython-input-4-a099fa2fc4a7> in <module>
----> 1 ohe.fit(X)
~/Desktop/venv/lib/python3.7/site-packages/sklearn/preprocessing/_encoders.py in fit(self, X, y)
417 self._fit(X, handle_unknown=self.handle_unknown,
418 force_all_finite='allow-nan')
--> 419 self.drop_idx_ = self._compute_drop_idx()
420 return self
421
~/Desktop/venv/lib/python3.7/site-packages/sklearn/preprocessing/_encoders.py in _compute_drop_idx(self)
394 ["Category: {}, Feature: {}".format(c, v)
395 for c, v in missing_drops])))
--> 396 raise ValueError(msg)
397 return np.array(drop_indices, dtype=object)
398
ValueError: The following categories were supposed to be dropped, but were not found in the training data.
Category: 0, Feature: 0
Category: 1, Feature: None
Category: 2, Feature: None
我相信这也是这个问题指出的一半: https :
为了支持这一点,我们可以做的另一种方法是手动跟踪在拟合期间我们想要删除哪些列和哪些值。 将数据传递给 scikit-learn。 然后,修剪掉我们存储并指定要删除的列。 但是,这需要一些逻辑处理来从转换后的列名中确定原始(特征、值)。 (我们在get_feature_names
有这个逻辑,但这有助于我们连接列名,假设不应该删除任何内容......)
所有这一切都是说,也许现在只使用默认的 scikit-learn if_binary
就足够了,我们可以提交一个单独的问题来始终使用少数类。 老实说,考虑到我们必须围绕它进行大量工作,我们也赞成放弃 scikit-learn 的 OHE 实现。
有用的资源:
OHE 文档: https :
scikit-learn 中的代码导致不灵活: https :
相关问题: https :
对于使用if_binary
:scikit-learn 要求handle_unknown
是error
。 这不适用于我们的top_n
参数,它会丢弃除前 N 个类别之外的所有内容,因为要转换的数据不知道如何处理新类别。 正如 Becca 在https://github.com/alteryx/evalml/pull/830 中指出的那样,我们必须将top_n
为 None 才能使这些参数起作用。
考虑到这一点,也许最好只推出我们自己的 impl 🤔
最有用的评论
代码第三定律:你不应该做 == 与浮点数的比较