Scikit-learn: 重新思考 CategoricalEncoder API ?

创建于 2018-01-23  ·  63评论  ·  资料来源: scikit-learn/scikit-learn

基于我们在这里进行的一些讨论和打开的问题,我们怀疑CategoricalEncoder (https://github.com/scikit-learn/scikit-learn/pull/9151) 是否是好的名称的选择(由于它还没有发布,我们有一些改变的空间)。

所以总结一下现在的情况:

  • 类名CategoricalEncoder表示它接受什么类型的数据(分类数据)
  • 关键字参数encoding指定如何编码这些数据

目前我们已经有了encoding='onehot'|'onehot-dense'|'ordinal'

但是在以下情况下该怎么办:

  • 我们想添加更多的编码选项(例如二进制编码、平均目标编码、一元编码等)。 我们是否继续将这些作为encoding kwarg 的新值添加到一个大CategoricalEncoder类中?
  • 我们想添加一个特定于其中一个编码的选项(例如,对于“onehot”编码以删除第一列(冗余),或者对于“序数”编码基于频率的类别顺序,...)。 这里的问题是,然后我们需要向CategoricalEncoder添加额外的关键字参数,这些参数是否处于活动状态取决于您为encoding kwarg 传递的内容,这不是最好的 API 设计。

对于最后一个问题,我们已经用sparse=True/False选项解决了这个问题,它只与 'onehot' 相关,与 'ordinal' 无关,我们通过同时使用 'onehot' 和 'onehot-dense' 解决了这个问题编码选项而不是sparse关键字。 但这种方法也没有规模。

与此相关,有一个 PR 添加UnaryEncoder (https://github.com/scikit-learn/scikit-learn/pull/8652)。 在那个 PR 中有一个关于命名的相关讨论,因为目前名称说明它是


有哪些选择:

1) 保持我们现在在 master 中拥有的东西,并且可以为单个类添加一些新选项(现在很难回答的一个重要问题是我们将来要添加多少新功能) .
2)切换命名方案并拥有一堆“分类编码器”,其中名称说明了它的编码方式(OnehotEncoder、OrdinalEncoder,以及后来的 BinaryEncoder、UnaryEncoder,...)

所以这有点权衡潜在的类数量与单个类中关键字参数的数量。


第二种方法的一个问题(也是我们首先使用CategoricalEncoder的原因之一,甚至在我们添加多个编码选项之前),是已经有一个OnehotEncoder ,它具有与CategoricalEncoder不同的 API。 而且,对于执行单热编码的编码器,我们真的没有其他好的名称可以使用。
但是,我认为,通过一些临时性丑陋的 hack,我们可以重用名称,如果我们可以弃用当前属性(我认为我们同意它不是最有用的属性)。 这个想法是,如果你用字符串数据拟合类,你会得到新的行为,如果你用整数数据拟合类,你会得到一个弃用警告,指示默认行为将改变(并指示要指定哪个关键字来获取)摆脱警告)。

抄送@jnothman @amueller @GaelVaroquaux @rth

最有用的评论

恢复 CategoricalEncoder 的想法让我很伤心,但我认为
你是对的,未来的用户不会对选项 2 感到困惑。我的主要
令人担忧的是,我们已尝试将此作为对 OHE 的更改来实施
很长一段时间,它从未飞过。 也许最好尝试一下
根据建议修改 OneHotEncoder 文档字符串
改变,所以我们可以看看它看起来是否正常。

所有63条评论

感谢@jorisvandenbossche 的总结。 我想我赞成选项 2:重用OneHotEncoder类,弃用奇怪的属性并添加一个构造函数参数来选择行为,未来警告说默认行为会改变但很容易沉默仅通过为该选项传递值来发出警告。

恢复 CategoricalEncoder 的想法让我很伤心,但我认为
你是对的,未来的用户不会对选项 2 感到困惑。我的主要
令人担忧的是,我们已尝试将此作为对 OHE 的更改来实施
很长一段时间,它从未飞过。 也许最好尝试一下
根据建议修改 OneHotEncoder 文档字符串
改变,所以我们可以看看它看起来是否正常。

+1 乔尔所说的

来自我的手机。 请原谅打字错误和简短。

在2018年1月23日,12:28,12:28,乔尔Nothman [email protected]写道:

恢复 CategoricalEncoder 的想法让我很伤心,但我
思考
你是对的,未来的用户不会对选项 2 感到困惑。我的
主要的
令人担忧的是,我们已尝试将此作为对 OHE 的更改来实施
一种
很长一段时间,它从未飞过。 也许最好尝试一下
根据建议修改 OneHotEncoder 文档字符串
改变,所以我们可以看看它看起来是否正常。

——
你收到这个是因为你被提到了。
直接回复此邮件或在 GitHub 上查看:
https://github.com/scikit-learn/scikit-learn/issues/10521#issuecomment -359761818

恢复 CategoricalEncoder 的想法让我很伤心

需要明确的是,这不是还原,而是保留所有功能的重构/重命名!
但我也喜欢“CategoricalEncoder”这个名字,那确实会让人伤心。

也就是说,我将很快尝试进行更改,以了解将其集成到 OnehotEncoder 中的可能性有多大。

好的,我用概念证明开了一个 PR: https :
它尚未完成(没有弃用警告,旧行为中尚未计算新属性)。

API 的主要问题是关于输入数据的格式。
因此,回顾一下,我们目前

1)作为实际,尚未编码(整数或字符串),分类数据(如何在CategoricalEncoder )-> 从训练数据中的唯一值推断类别
2)作为整数,已经编码的数据(如何在当前OneHotEncoder )-> 从训练数据中的最大值推断类别

问题是:我们认为这两个案例都值得支持吗? 因此,在可能合并的 OneHotEncoder 中,我们是保留两者的能力,还是完全弃用然后删除处理序数输入的能力?

如果想要同时处理两者,我们可以添加一个布尔关键字来指定输入数据类型(现在我使用encoded_input=False/True ,但其他想法是ordinal_input ,...)

对于弃用期,无论如何我们都必须支持,并且还必须引入一个关键字来选择行为(能够使警告静音并选择新行为)。
所以原则上我们可以在之后保留关键字。

鉴于我们想要同时处理两者,OneHotEncoder 如何工作的概述:

  • 现在encoded_input=None ,我们根据数据推断默认值
  • 如果类似 int 的数据(之前由 OneHotEncoder 处理) encoded_input在内部设置为 True 并引发弃用警告。 如果用户想保留当前行为,可以手动将其指定为OneHotEncoder(encoded_input=True)以消除警告。
  • 如果输入不是 int-like,我们将encoded_input内部设置为 False 并且没有警告地使用新行为(=当前的 CategoricalEncoder 行为)
  • 将来我们将encoded_input的默认值从 None 更改为 False(默认情况下新行为,也适用于类似 int 的数据)

我仍然不确定您的建议是由于从最大值推断类别而导致的实际差异。

@jnothman我想你承认有可能在实践中有区别吗? (您获得的输出取决于您拥有的数据)

但这种差异在实践中是否重要,我不知道。 这就是我希望看到反馈的地方。 是否有人真的想要这种基于“最大值”的方法,或者我们是否可以(在未来,弃用后)只使用基于“唯一值”的方法。

我认为我个人永远不会需要这种基于最大值的方法,但 OneHotEncoder 多年来一直如此(有充分的理由吗?)。

实际上弃用基于最大值的分类肯定会使实现(弃用后)更简单。
如果我们选择这条路线,我同意该选项应该是legacy_mode=True/False而不是encoded_input / ordinal_input

提醒我输出的实际差异是什么,当 n_values='auto' 时,
请? 我原以为 active_features_ 的东西让他们基本上
相同,但我可能忘记了一些东西。

啊哈,这澄清了我们的误解:-)
我误解了当前 OneHotEncoder 的实际工作方式。 假设您有一个值为 [2, 3, 5, 2] 的特征。 我认为当前的 OneHotEncoder 会有类别 [0, 1, 2, 3, 4, 5] (而当前的 CategoricalEncoder 会有类别 [2, 3, 5])。 但是您说得对, active_features_也只有 [2, 3, 5] ,基本上使它们与n_values='auto'的默认值相同。

因此,只有在您将整数传递给n_values (例如在上述情况下,类别=[0, 1, 2, 3, 4, 5] 的n_values=6 )来指定实际上将成为 API 更改(已弃用/删除)的类别数量。
这将很容易被用户用categories=range(6)替换

对困惑感到抱歉。
有鉴于此,我认为我们甚至不需要legacy_mode选项。 我们可以在内部将n_values=6categories=range(6)并为此发出警告(但需要通过实际测试进行检查)。

另一个区别是对看不见的类别的处理。 根据 OneHotEncoder 的当前行为,如果看不见的值在范围 (0, max) 内,即使handle_unknow='error' (默认值)也不会引发错误。 但也可以通过在这种情况下发出警告来单独解决,即用户应该手动设置handle_unknown='ignore'以保持现有行为。

我们将失去的唯一特征是范围内的未知类别之间的区别(0,最大值)(当前 OneHotEncoder 不被视为“未知”)和那些大于该范围的未知类别(> max,那些目前已经被视为OneHotEncoder 未知)。

不,那是我们以前尝试过的那种事情,而且太
挑剔。 除非有充分的理由保持当前的行为,否则我们
应该有一个 legacy_mode 慢慢地把我们带到未来。

不,这是我们以前尝试过的那种事情,而且太挑剔了。

你能澄清这个“不”是指哪个方面?
对于我认为不需要legacy_mode的事实?

是的,你可以做一些倒退的东西的想法
兼容以及我们想要的未来

是的,对于您可以制作既向后兼容又我们想要的东西的想法

这不是我试图建议的。 我想明确指出,没有legacy_mode关键字是可能的,不是通过神奇地向后兼容和我们未来想要的,而是通过弃用现有关键字的行为。

所以具体来说: n_values的非默认值可以被弃用,必须由categories规范替换。 handle_unknow在整数数据的情况下应由用户明确设置以选择完全忽略或完全错误而不是当前混合(否则会引发弃用警告)。

因此,如果我执行 .fit([[5]]).transform([[4]]),对于 n_values 的值,
category 和 handle_umknown 会引发错误吗?

2018 年 1 月 25 日上午 9:32,“Joris Van den Bossche”通知@github.com
写道:

是的,你可以做一些倒退的东西的想法
兼容以及我们想要的未来

这不是我试图建议的。 我想明确表示认为
可能没有 legacy_mode 关键字,而不是神奇地拥有它
向后兼容和我们未来想要的,但通过弃用
现有关键字的行为。

所以具体来说:可以弃用 n_values 的非默认值,并且
必须由类别规范替换。 handle_unknow 的情况下
用户应明确设置整数数据以选择完整的
忽略或完全错误而不是当前的混合(以及其他弃用
发出警告)。


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/scikit-learn/scikit-learn/issues/10521#issuecomment-360296569
或静音线程
https://github.com/notifications/unsubscribe-auth/AAEz6-DrQWep22_gs-hg9cC0u19B1_PSks5tN6-HgaJpZM4RpUE8
.

我们可以让它在弃用期间必须设置类别吗
显式,带有警告的旧模式是否有效? 就是它
你在建议什么?

我们能不能让它在弃用期间,必须明确设置类别,否则带有警告的旧模式是否有效? 这就是你的建议吗?

是的,它可能仍然缺少案例,但我认为这是可能的(下周将通过实际编码进行检查)。

不同的“遗留”案例:

  • n_values='auto'(默认)

    • handle_unknown='ignore' -> 很好,行为没有变化

    • handle_unknown='error' -> 问题,范围内的值仍然被忽略,值超出范围错误



      • 可能的解决方案:





        • 在合适的情况下,如果范围是连续的 => 很好,则行为没有变化(对于现在将 LabelEncoder 与其结合的所有人,我认为这是一个典型的用例)



        • 如果不是这种情况:提出弃用警告,他们必须明确设置类别以保持此行为(并在内部使用旧模式)






  • n_values=值

    • 这可以在内部转换为 category=[range(value)] ,并引发弃用警告,用户将来应该自己这样做

    • 在这种情况下handle_unknown='error' / 'ignore'按预期工作

n_values='auto'情况下的弃用警告只会在fit而不是在构造时引发(这不是很理想),但只有在我们知道用户正在传递它时才合适数字数据而不是字符串数据。

在任何情况下,我们通常不会在合适之前发出警告,所以不要担心
那。

这个策略听起来大多不错。

我实际上不确定我们是否应该嗅探数据中的字符串,
尽管。 您基本上希望它是:如果类别是,则传统模式处于活动状态
没有设置如果数据都是整数?

一个问题:如果 category 和 n_values 参数是它们的默认值,请执行
我们发布类别_? 如果明确设置了 n_values,我们是否发布
类别_?

2018 年 1 月 29 日上午 10:00,“Joris Van den Bossche”通知@github.com
写道:

我们可以让它在弃用期间必须设置类别吗
显式,带有警告的旧模式是否有效? 就是它
你在建议什么?

是的,它可能仍然缺少案例,但我认为这是可能的(将
下周通过实际编码进行检查)。

不同的“遗留”案例:

  • n_values='auto'(默认)

    • handle_unknown='ignore' -> 很好,行为没有变化

    • handle_unknown='error' -> 问题,范围内的值仍然存在

      忽略,值超出范围错误



      • 可能的解决方案:





        • 适合,如果范围是连续的 => 很好,没有变化



          行为(对于现在将 LabelEncoder 与其结合的所有人,这是



          我认为的一个典型用例)



        • 如果不是这种情况:提出弃用警告



          他们必须明确设置类别以保持这种行为(并且



          内部使用传统模式)





      • n_values=值



    • 这可以在内部转换为 category=[range(value)],

      并提出弃用警告,用户应该在

      未来

    • 在这种情况下 handle_unknown='error' / 'ignore' 按预期工作

在 n_values='auto' 情况下的弃用警告只会在
适合而不是在构造上(这不是很理想),但它只是
在合适的情况下,我们知道用户正在传递数字数据而不是字符串
数据。


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/scikit-learn/scikit-learn/issues/10521#issuecomment-361104495
或静音线程
https://github.com/notifications/unsubscribe-auth/AAEz6x8xnyZXBLij-DCC45JyYNf8pA5kks5tPPwXgaJpZM4RpUE8
.

您基本上希望它是:如果未设置类别数据均为整数

确实是(实际上它或多或少会相同)

一个问题:如果categories 和n_values 参数是它们的默认值,我们是否发布categories_? 如果明确设置了 n_values,我们是否发布类别_?

我个人已经尽可能多地提供新界面的属性,即使在传统模式下也是如此。 所以在这两种情况下,我都会计算categories_ (即使它会多一点工作)


因此,我尝试将上述逻辑放入代码中(将向 PR 推送一些更新),并且对于未设置n_valuescategories时的整数数据情况,我还有一个问题( 'legacy_mode' 的典型案例)。 问题在于,如果推断的类别只是一个连续的范围 (0, 1, 2, 3, ... max),则新旧(遗留)行为之间没有区别,我们不会必然需要提出弃用警告。
在这种特定情况下可以做的一些可能性:

1)检测这种情况(推断类别是连续范围),在这种情况下不发出警告。
- 这是可以检测到的(有一点额外的代码复杂性),因为我们已经适应了
- 我认为这将是使用带有整数数据的 OneHotEncoder 的常见情况,并且用户实际上不需要担心我们的重构,因此最好不要用警告打扰他/她
2)总是发出警告,并在警告消息中指出如果你在这种情况下该怎么做(除了解释如果你没有连续范围怎么办):
- 如果他们知道他们只有连续的范围作为类别,他们想忽略警告,所以我们可以在警告消息中添加一个解释如何做到这一点(添加一个带有过滤器警告的代码示例,他们可以复制粘贴)
- 这样做的一个潜在优势是我们还可以添加警告消息,如果他们使用 LabelEncoder 创建整数,他们现在可以直接使用 OneHotEncoder(我认为这是目前典型的使用模式)。 这样,警告也会消失
3) 总是提出警告但提供一个关键字来使其静音(例如legacy_mode=False
- 如果我们发现使用filterwarnings语句的建议(见上面的第 2 点)太麻烦,我们也可以添加一个关键字来获得相同的结果
- 这样做的缺点是引入了一个关键字,当清除弃用时,在一些版本中将不再需要该关键字。

我个人赞成选项 1 或 2。在 OneHotEncoder 之前使用 LabelEncoder 似乎是一种典型模式(来自快速 github 搜索),在这种情况下,您总是有连续的范围,并且永远不会改变行为新的实现,所以我们不应该为此发出警告。 另一方面,如果我们警告我们可以指出如果他们使用 LabelEncoder,他们就不再需要这样做了。 实际上明确地给出这个建议会很好。
问题是用户在没有使用 LabelEncoder 作为上一步的情况下,将此类连续整数作为类别的频率有多高..

嗯,我忘记的一种情况是,当您有连续的整数推断类别(比方说 [1,3,5]),但您想要新行为而不是遗留行为(因此在这种情况下,您不能忽略警告,因为这将在转换步骤中以不同的方式处理看不见的值,即范围之间的值(例如 2)不会引发错误)。
如果我们不提供legacy_mode=False关键字,获得新行为的唯一方法是手动传递categories=[1,3,5] ,这可能会带来一些不便。 这可能是支持选项 3 并放弃我对引入临时关键字legacy_mode=False反对的原因(但也不完全确定它是否值得,因为这将是此类关键字实际上是唯一的情况*需要)

* 这唯一的情况 = 推断类别不是连续范围的整数数据,并且您不能/不想手动设置类别或将 handle_unknown 设置为忽略。

很抱歉所有的长文本,但它非常复杂:)

我们只讨论 n_values 未设置的情况,对吗?

我对 1. 没问题,而且不会更贵,因为汽车
已经需要检查标签集。 我也可以接受,因为
简单性,是 3. 的变体,这只是“运行在旧版中的 OneHotEncoder
模式。 为稍有不同的行为设置 category='auto'
警告。”

我们只讨论 n_values 未设置的情况,对吗?

是(另一种情况很容易转换为等效的categories值,带有很好的弃用警告,并且新旧行为没有不同)

3. 的变体,这只是“在传统模式下运行的 OneHotEncoder。在没有警告的情况下为稍微不同的行为设置 category='auto'。”

啊,这听起来是个好主意! (无论是否检测到连续类别的情况)。 因此,我们在代码中将categories的默认值设置为 None(不更改其默认值的语义),因此我们知道用户是否明确设置了它,这样就可以很好地指示legacy_mode=False不需要额外的关键字。

是的,但前提是我们想在每次有人使用它而不通过时发出警告
类别。 这是廉价的实现方法,但它可能是
对用户来说不必要的冗长,这就是为什么我更喜欢 1 如果它
可以简单地完成。

这是什么新鲜的地狱:-/

或者我们可以将新命名为DummyEncoder ;)(尽管这与 DummyClassifier 有点冲突)

@amueller不要阅读以上所有内容!
我只是打算为这个问题的新读者做一个很好的总结。 上面的讨论过于复杂(也是因为我还没有完全理解 OneHotEncoder 当前复杂的行为...... :-))

或者我们可以命名新的 DummyEncoder ;)

我认为@GaelVaroquaux反对这一点,因为在更多领域中“one-hot”是众所周知的(并且我们已经在 scikit-learn 中将“Dummy”用于其他事物......)

恕我直言,为了命名的一致性而重做此操作是不值得的。 我们在任何地方命名都不一致。 您能否总结一下导致此问题的讨论?

我认为“虚拟”是统计学家使用的,也是熊猫使用的。

顶帖仍然准确且值得一读,它总结了不保留 CategoricalEncoder 的原因(这并不意味着我们需要使用 OneHotEncoder 而不是 DummyEncoder,这是一个单独的问题)

我读了顶帖。 这就是我在说“为了一致性而重做这是不值得的”时所指的。

打开的问题

你能解释一下吗?

“为了一致性而重做是不值得的”

保持一致,您是否指向“它接受什么”与“它做什么”的命名方案? 如果是这样,那只是次要原因。 对我来说,这主要是向单个类添加更多功能的可扩展性问题。

打开的问题

我们遇到了关于如何处理缺失值的问题 (https://github.com/scikit-learn/scikit-learn/issues/10465),为此,您可能需要不同的顺序和单热编码行为(或不所有选项都对两者都有效,..)。 我们也已经有了现有的handle_unknown ,它只与 one-hot 编码相关,而不与序数相关。 还有https://github.com/scikit-learn/scikit-learn/issues/10518关于onehot编码的特征权重,但也与序数无关(这个问题最终不是问题,你可以这样做ColumnTransformer 的transformer_weights 参数的权重)。 我们还有一个功能请求,为 one-hot 添加类似drop_first东西,这又与序数编码无关。

我看不出提议的更改对缺失值有多大帮助。 在 scikit-learn 中经常会出现不兼容的选项。 不理想,但也没什么大不了的。

我看不出提议的更改对缺失值有多大帮助。

它不利于这样,但它使得它不太复杂有专门针对不同的编码类型的特定选项。

在 scikit-learn 中经常会出现不兼容的选项。 不理想,但也没什么大不了的。

目前它肯定还可以,没有太多不兼容的选项(但部分原因是我将sparse=True/False移到了encoding选项中)。 但问题是我们未来希望在多大程度上扩展 scikit-learn 中的编码功能。 这当然是一个现在很难回答的问题。
我们已经有了“一元编码”的 PR。 这不应该添加到 CategoricalEncoder 而不是添加一个新类 UnaryEncoder 吗? 如果有人想添加“二进制编码”怎么办? 还是“(平均)目标编码器”?

“平均目标编码器”是CountTransformer ,有一个 PR ;)

你有那个链接吗? 搜索“CountTransformer”没有任何结果

抱歉,CountFeaturizer #9614

它当然相关,但不完全是平均目标编码。 此外,它添加了列,而不是替换,因此对于字符串分类数据还不能开箱即用(但这是对该 PR 的更多反馈,不在这里讨论)。

为什么不是mean target encoding? 但是,是的,让我们不要在这里转移太多;)

因此,作为我们需要回答的实际问题的摘要(按此顺序!):

  1. 我们是否保留当前的CategoricalEncoder ? 如果没有,我们的想法是将它分成不同的类,每种类型的编码(当前为“onehot”和“ordinal”编码)一个类。

  2. 如果我们分成多个类,我们可以(理想情况下?)使用 OneHotEncoder 进行“onehot”编码,但是这个类已经存在。 那么,我们是否在现有的 OneHotEncoder 类中集成了新的“onehot”编码(支持字符串并具有不同的参数)? 或者我们选择另一个名字? (例如 DummyEncoder)

  3. 如果我们选择集成到现有的 OneHotEncoder 中,我们是否可以接受以下后果:我们弃用了 OneHotEncoder 的一堆关键字/属性,并且特定用例(自动忽略可见值范围的未见值)将无法实现弃用期后不再使用。

上面的大部分讨论都是关于问题 3(如何将 CategoricalEncoder(encoding='onehot') 集成到 OneHotEncoder 中的复杂细节)。 但让我们首先就前两个问题的决定达成一致。

对我来说另一个因素是每个人都认为当前的自动模式
OneHotEncoder 很奇怪。 它的实现将 coo 转换为 csr 也是
奇怪的。 它值得重新设计。 并告诉人们“如果你想要一个热
编码字符串,改为使用 CategoricalEncoder” 很尴尬,因为 OHE
已经用于分类......

小时。 我想我们保留 OneHotEncoder 是因为当它可以使用时效率更高......理想情况下我们会摆脱所有奇怪的行为。 我有点想弃用它,但后来我们没有......

我有点想弃用它,但后来我们没有......

在我的 POC PR (https://github.com/scikit-learn/scikit-learn/pull/10523) 中,我弃用了 OneHotEncoder 的几乎所有内容,除了它的名字......

它的效率并不高。 如果 LabelEncoder 有整数的快速路径
在 [0, n_values-1] 范围内,如果合理,那就足够了。

@amueller ,您是否被我们最终需要不同的附加参数(例如 drop_first、nan 处理)取决于编码的问题所说服,并且这证明为每种编码格式使用不同的离散编码器是合理的?

我会试着在两周后的春假里看看这个,好吗? 不知道在那之前我是否有时间:-/

我希望这不是问错的地方,但是当前的实现对在一列中混合分类和非分类的表有什么作用? 以https://github.com/pandas-dev/pandas/issues/17418为例

考虑数据框df = pd.DataFrame([{'apple': 1, 'pear':'a', 'carrot': 1}, {'apple':'a', 'pear':2, 'carrot':3}, {'apple': 2, 'pear':3, 'carrot':1}, {'apple': 3, 'pear':'b', 'carrot': 1}, {'apple': 4, 'pear':4, 'carrot': 1}]) ,它等于:

  apple  carrot pear
0     1       1    a
1     a       3    2
2     2       1    3
3     3       1    b
4     4       1    4

在这种情况下,DictVectorizer 正是我所需要的。

    from sklearn.feature_extraction import DictVectorizer
    enc = DictVectorizer(sparse = False)
    enc.fit_transform(df.to_dict(orient='r'))

这给出:

array([[ 1.,  0.,  1.,  0.,  1.,  0.],
       [ 0.,  1.,  3.,  2.,  0.,  0.],
       [ 2.,  0.,  1.,  3.,  0.,  0.],
       [ 3.,  0.,  1.,  0.,  0.,  1.],
       [ 4.,  0.,  1.,  4.,  0.,  0.]])

我们可以看到列的特征名称:

    enc.feature_names_
    ['apple', 'apple=a', 'carrot', 'pear', 'pear=a', 'pear=b']

如果新的 CategoricalEncoder 可以选择做同样的事情,那就太好了。

我不认为我们打算处理那种混合情况

这是一种耻辱。 一个简单的子案例是一列是数字但有一些缺失值。 一个简单的解决方案是将 NaN 转换为空字符串,然后像上面的示例一样使用 DictVectorizer。 这有效地为值缺失时创建了一个新特征,否则保持数值不变。 我发现这是一种非常有用的技术。

新的 CategoricalEncoder 能做类似的事情吗?

我们考虑过允许用户将 NaN 视为一个单独的类别
或类似。 但这与处理任意数值不同
不同于字符串。

听起来不错。

你是对的,有两个用例。 让我解释一个特殊的例子,其中将数值与字符串不同对待对我有用。 可能有更好的解决方案。

假设您有一个整数数字特征,它需要一个大范围的值。 但是,您怀疑对于某些小值,精确值很重要。 对于较大的值,您怀疑情况并非如此。 一个简单的事情是将所有小值转换为字符串,如上所述运行 DictVectorizer,然后执行特征选择或直接使用您喜欢的分类器。

所以你把它用于非线性离散化? 下一个版本是
可能包括一个固定宽度的离散化器,但从日志中
变换或分位数变换它应该与您的行为非常相似
想要......但是在您的设置中,仅对数转换可能就足够了。

2018 年 2 月 25 日 18:10,lesshaste [email protected]写道:

听起来不错。

你是对的,有两个用例。 让我解释一个特定的例子
将数值视为不同于字符串的地方很有用
为了我。 可能有更好的解决方案。

假设您有一个整数数字特征,它需要一个大范围的
值。 但是,您怀疑对于某些小值,精确值
意义重大。 对于较大的值,您怀疑情况并非如此。 一个简单的
要做的是将所有小值转换为字符串,运行 DictVectorizer
如上所述,然后执行特征选择或仅使用您最喜欢的
直接分类。


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/scikit-learn/scikit-learn/issues/10521#issuecomment-368288727
或静音线程
https://github.com/notifications/unsubscribe-auth/AAEz60cmjwlDVKGyXc6oPyIC9oLbptSgks5tYQdvgaJpZM4RpUE8
.

@jnothman从某种意义上说是的,但有一点不同。 假设我怀疑 1...1024 中的某些值是有意义的。 那是 22 表示与 21 或 23 完全不同的特定内容。记录日志在这里无济于事。 但我想将所有超过 1024 的值保留为数字,因为我认为这些特定值意义不大。

听起来您对泛型变量了解太多
转变为您需要的那种东西。

2月25日2018年20:37,lesshaste [email protected]写道:

@jnothman https://github.com/jnothman从某种意义上说是的,除了
捻。 假设我怀疑 1...1024 中的某些值是有意义的。
即 22 表示与 21 或

  1. 记录日志在这里无济于事。 但我想把所有的价值都留下
    1024 作为数字,因为我认为这些特定值没有多大意义。


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/scikit-learn/scikit-learn/issues/10521#issuecomment-368295895
或静音线程
https://github.com/notifications/unsubscribe-auth/AAEz65bOdVB6k7rCAcgLBYz_NslxXWV0ks5tYSnggaJpZM4RpUE8
.

@jnothman更清楚一点,我不知道 22 很重要。 我只是怀疑有些值是,但我不知道有哪些或有多少。 我发现“转换为字符串”和 DictVectorizer 方法对于发现它们是非常有用的。

@lesshaste有关 NaN 作为单独类别的问题,请参阅https://github.com/scikit-learn/scikit-learn/issues/10465
如果您想进一步讨论特定的非线性离散化或混合数字/字符串编码,请随时开新 issue。 但是希望将这个重点放在原始问题上,即 CategoricalEncoder/OneHotEncoder 的不同类中的命名和组织。

我会试着在两周后的春假里看看这个,好吗? 不知道在那之前我是否有时间:-/

@amueller没关系。 在接下来的两周内,我没有时间处理被此阻止的 PR。 在那之后,我也应该有时间再做这件事。

@amueller你有时间看看这个吗?

@amueller你同意我继续在 PR 上工作,在 OrdinalEncoder 和 OneHotEncoder 中拆分 CategoricalEncoder(并弃用 OneHotEncoder 的当前参数)?

很抱歉缺席。 看起来不错,但你能给我两周的时间,这样我才能真正复习吗? 谢谢!

@amueller没问题,对我来说也是一样:-)
但是,我现在打算再看一遍。 所以,如果你能给这个看看,那将是受欢迎的。 我在 PR (https://github.com/scikit-learn/scikit-learn/pull/10523) 上有一些工作要做,所以不要详细审查(你可以看看它有一个想法然而,我们提出的建议)。
我认为在我投入大量时间之前我想看到的主要问题是,您是否同意将 CategoricalEncoder 拆分为多个类,在这种情况下,如果您同意重新使用 OneHotEncoder(这意味着弃用其当前的一些(奇怪的)功能)。 这些问题总结在https://github.com/scikit-learn/scikit-learn/issues/10521#issuecomment -363851328 和https://github.com/scikit-learn/scikit-learn/issues/10521#issuecomment -364802471。

(一旦我们就这部分达成一致,关于 PR 中的实际实施仍有很多要讨论的 :))

我会谨慎地说我回来了;)

恕我直言,最重要的是我们讨论的所有编码器的通用 API(即参数和行为模式)

PS https://github.com/scikit-learn-contrib/categorical-encoding

category_encoders包中,所有编码器都有一个cols参数,类似于旧 OneHotEncoder 中的categorical_features (尽管它不接受完全相同类型的值)。 参见例如http://contrib.scikit-learn.org/categorical-encoding/onehot.html
所以这与我们在https://github.com/scikit-learn/scikit-learn/pull/10523 中关于是否弃用categorical_features的当前讨论有关。

其余的我认为没有真正冲突的关键字(它们还有一些特定于数据框的其他关键字,我们目前不会添加到 sklearn 中)。 OneHotEncoder 和 OrdinalEncoder 的命名至少与category_encoders包一致。

此页面是否有帮助?
0 / 5 - 0 等级