字符串作为决策树/随机森林中的特征


63

我在决策树/随机森林的应用程序上遇到了一些问题。我正在尝试解决一个以数字和字符串(例如国家/地区名称)为特征的问题。现在的库scikit-learn仅将数字作为参数,但是我想注入字符串,因为它们具有大量的知识。

如何处理这种情况?

我可以通过某种机制将字符串转换为数字,例如Python中的哈希。但是我想知道有关如何在决策树问题中处理字符串的最佳实践。


不能将字符串转换为float:在sckitlearn的情况下,我已经看到,我们需要编码分类变量,否则拟合方法将抛出一个错误说ValueError异常

Answers:


55

在大多数完善的机器学习系统中,分类变量是自然处理的。例如,在R中,您将使用因子,在WEKA中,您将使用名义变量。scikit-learn中不是这种情况。在scikit-learn中实现的决策树仅使用数字功能,并且这些功能始终被解释为连续的数字变量

因此,应该避免用哈希码简单地替换字符串,因为将其视为连续的数字功能,您将使用的任何编码都将导致数据中根本不存在的顺序。

一个例子是用[1,2,3]编码['red','green','blue'],会产生诸如'red'低于'blue'的怪异事物,如果您平均使用'red'一个“蓝色”,您将得到一个“绿色”。当您用[1,2,3]编码['low','medium','high']时,可能会出现另一个更微妙的示例。在后一种情况下,它可能恰好具有合理的排序,但是,当“中”不在“低”和“高”中间时,可能会发生一些细微的不一致。

最后,问题的答案在于将分类特征编码为多个二进制特征。例如,您可以用3列编码['red','green','blue'],每个类别一个,类别匹配时为1,否则为0。这称为“ 一次热编码”,“二进制编码”,“千分之一编码”或其他。您可以在此处查看有关分类特征编码特征提取(散列和字典)的文档。显然,一键编码会扩展您的空间要求,有时还会损害性能。


2
不能正确处理分类变量的是scikit实现。像这个答案所示的那样重新编码可能是您可以做的最好的事情。更严重的用户可能会寻找替代软件包。
SmallChess

3
可以使用sklearn.preprocessing.LabelBinarizer对分类变量进行一次热编码。
GuSuku

@rapaio我认为二进制编码不是一种热编码。二进制编码是指表示3个列的8个类别,或表示4个列的9至16个类别之间的依此类推。我错了吗?
Alok Nayak

patsy python软件包将处理分类变量的一键编码。patsy.readthedocs.io/en/latest/quickstart.html
zhespelt

5
不要使用LabelBinarizer,请使用sklearn.preprocessing.OneHotEncoder。如果您正在使用pandas导入和预处理数据,则也可以直接使用pandas.get_dummies进行此操作。令人惊讶的是,scikit-learn不支持分类变量。
里卡多·克鲁兹


7

通常,您应该对scikit-learn模型(包括随机森林)进行一键编码分类变量。随机森林通常无需使用一键编码就可以正常工作,但如果执行一键编码,通常效果会更好。在这种情况下,一键编码和“虚拟”变量含义相同。Scikit-learn具有sklearn.preprocessing.OneHotEncoder,Pandas具有pandas.get_dummies来完成此任务。

但是,还有其他选择。KDnuggets上的“超越一站式”文章很好地解释了为什么您需要编码分类变量和一键式编码的替代方法。

有一些随机森林的替代实现,它们不需要像R或H2O这样的一键编码。R中的实现在计算上昂贵的,并且如果您的功能具有很多类别则将无法使用。H2O将适用于大量类别。Continuum已在Anaconda Python中提供H2O。

目前正在努力使scikit-learn直接处理分类功能

本文介绍了H2O中使用的算法。它引用了学术论文“流并行决策树算法”和该论文的较长版本


5

2018更新!

您可以为分类变量创建一个嵌入(密集向量)空间。你们中的许多人都熟悉word2vec和fastext,它们将单词嵌入到有意义的密集向量空间中。同样的想法-您的分类变量将映射到具有某些含义的向量。

郭/伯克汉的论文中

与单热编码相比,实体嵌入不仅减少了内存使用并加快了神经网络的速度,而且更重要的是,通过在嵌入空间中映射彼此接近的相似值,它揭示了分类变量的内在属性。我们在最近的Kaggle竞赛中成功应用了该软件,并以相对简单的功能将其排名第三。

作者发现,以这种方式表示分类变量可提高所有测试的机器学习算法(包括随机森林)的有效性。

最好的例子可能是Pinterest在该技术中对相关Pin进行分组的应用

在此处输入图片说明

fastai的人们已经实现了分类嵌入,并使用配套的演示笔记本创建了一个非常不错的博客文章

附加细节和说明

神经网络用于创建嵌入,即为每个分类值分配一个向量。一旦有了向量,就可以在任何接受数值的模型中使用它们。向量的每个分量成为输入变量。例如,如果您使用3-D向量来嵌入颜色分类列表,则可能会得到类似:red =(0,1.5,-2.3),blue =(1,1,0)等。您将使用三个输入随机变量中与这三个组成部分相对应的变量。对于红色物体,c1 = 0,c2 = 1.5和c3 = -2.3。对于蓝色物体,c1 = 1,c2 = 1和c3 = 0。

实际上,您不需要使用神经网络来创建嵌入(尽管我不建议您避开该技术)。在可能的情况下,您可以手动或其他方式自由创建自己的嵌入。一些例子:

  1. 将颜色映射到RGB向量。
  2. 将位置映射到经/纬向量。
  3. 在美国的政治模型中,将城市映射到代表左/右对齐,税负等的某些矢量分量。

好的,很酷,但是除非我错过了一些事情,否则这将使网开始完成。我们如何创建嵌入然后将其传递到Forrest中?我想您必须训练一个具有所有功能的整个网络,然后采用前几层并将其用作Forrest的输入功能。目前尚不清楚该怎么做。
基思

Keith使用神经网络创建嵌入,即为每个分类值分配一个向量。一旦有了向量,就可以在任何接受数值的模型中使用它们。向量的每个分量成为输入变量。例如,如果使用3-D向量嵌入颜色的分类列表,则可能会得到诸如:red = (0, 1.5, -2.3),blue = (1, 1, 0)等的信息。您将在随机森林中使用与三个分量相对应的三个输入变量。对于红色物体,c1 = 0,c2 = 1.5,c3 = -2.3。用于蓝色的东西,C1 = 1,C2 = 1,和c3 = 0
皮特

因为它非常简单,所以我完全理解了这个概念。我的意思是在实施过程中将如何进行?您链接的fast.ai演示笔记本的末尾有一个RandomForestRegressor,但是我真的看不到它在嵌入中是如何添加的。
基思

我认为这可能是Keras
Keith

3

您可以在这种情况下使用伪变量。使用熊猫,panda.get_dummies您可以为要放入决策树或随机森林的字符串创建虚拟变量。

例:

import pandas as pd
d = {'one' : pd.Series([1., 2., 3.,4.], index=['a', 'b', 'c','d']),'two' :pd.Series(['Paul', 'John', 'Micheal','George'], index=['a', 'b', 'c', 'd'])}
df = pd.DataFrame(d)

df_with_dummies= pd.get_dummies(df,columns=["two"],drop_first=False)
df_with_dummies

2

将它们转换为数字,例如,为每个唯一的国家/地区设置一个唯一的数字(例如1,2,3和...)

你也不要需要使用一热编码(又名虚拟变量)与随机森林工作时,因为树木并不像其他算法的工作(如线性/逻辑回归),他们不远处的工作(他们寻找适合您功能的最佳分割),因此无需一键编码


1
它实际上取决于训练树的特定算法。特别是,scikit不支持分类变量。
一人为
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.