sklearn随机森林能否直接处理分类特征?

81

假设我有一个分类特征,颜色,可以取值为

['红色', '蓝色', '绿色', '橙色'],

我想用它来预测随机森林中的某些内容。如果我对其进行“one-hot编码”(即将其更改为四个虚拟变量),该如何告诉sklearn这四个虚拟变量实际上是一个变量?具体而言,在随机选择不同节点要使用的特征时,它应该将红、蓝、绿和橙色的虚拟变量一起包含,或者不包含它们中的任何一个。

我听说没有方法可以做到这一点,但我想必须有一种处理分类变量的方法,而不是以数字或类似方法对其进行任意编码。


自2014年以来,这是sklearn上一个有用且长期存在的增强请求。其中一个考虑因素是他们是否应该优先实现新的pandas Categorical,还是通用的numpy。 - smci
6个回答

65

没有,目前除了使用虚拟编码(one-hot encoding)之外,在scikit-learn中还没有支持分类变量的功能。有人正在working on this,可能会将补丁合并到主线上,但现在还没有支持。


4
如果这最终得到实现,那么我会给予十个赞。就我个人而言,我会把pandas分类优先于纯numpy,但核心维护者想要不同的方式。 - smci
4
在sklearn中处理分类特征的一种方法是使用独热编码。独热编码将每个可能的分类值转换为一个二进制向量,其中只有一个位是1,其他位都是0。这个位对应于该分类值在可能的分类值集合中的位置。可以使用sklearn.preprocessing.OneHotEncoder类来执行独热编码操作。 - Zhiyong
2
“one-hot encoding”对于“随机森林”来说不能正确处理分类数据,通过为每个类别创建任意数字,您将获得比“one-hot encoding”更好的模型,但这也不是正确的方法。您可以轻松地使用“R” randomForest软件包来查看,它会给出完全不同的结果,“随机”方差不仅如此,您可以重复使用“scikit-learn”的精度,使用“one-hot encoding”的准确度甚至不接近“R”的randomForest软件包。 - caiohamamura
现在还有人在处理这个请求吗?还是这个请求已经完成了?我知道对于lightgbm包,如果将分类数据传递为pandas.astype('category'),它可以处理。我认为如果lgbm有处理分类的逻辑,那么随机森林可能也应该有。 - Thomas Leyshon

32

大多数实现随机森林(以及许多其他机器学习算法)的程序都接受分类输入,但它们要么只是自动为您编码分类特征,要么使用一种在大量类别时变得计算上难以处理的方法。

H2O是一个值得注意的例外。H2O具有非常高效的方法,可以直接处理分类数据,这通常使其比需要进行独热编码的基于树的方法更具优势。

Will McGinnis的这篇文章对独热编码和替代方法进行了非常好的讨论。

这篇文章由Nick Dingwall和Chris Potts撰写,对分类变量和基于树的学习器进行了非常好的讨论。


7
最近另一个值得注意的例外是LightGBM,其在objective='rf'下具有针对分类特征的最优分割。 - zkurtz
1
你应该将这个作为一个独立的答案添加! - denson

15

你需要将分类变量转换为一系列虚拟变量。这是sklearn的工作方式。

如果你正在使用pandas,可以使用pd.get_dummies,它非常有效。


12
如果训练和推断中都有相同的独特数值,那么它会表现得非常好,因此它不够可靠。 - marbel
6
不仅令人烦恼,而且会导致次优结果。当使用虚拟变量时,随机森林表现更差。请参考此文章中的以下引述:假设我们的分类变量有100个水平,每个水平出现的频率大约相同。通过在其One-Hot编码的虚拟变量之一上进行分割,算法可以期望的最佳结果是将不纯度降低约1%,因为每个虚拟变量在大约1%的样本中都是“热点”。 - James Mchugh

2

不是这样的。 分类特征有两种类型:

  1. 有序:使用OrdinalEncoder
  2. 无序:使用LabelEncoder或OnehotEncoder

注意:LabelEncoder和OnehotEncoder之间的区别:

  1. LabelEncoder:仅适用于单个列 => 通常用于编码标签列(即目标列)
  2. OnehotEncoder:适用于多个列 => 可以同时处理更多特征

0
也许你可以使用 1~4 来替代这四种颜色,即在该列中使用数字而非颜色名称。然后,带有数字的列可以在模型中使用。

4
答案不正确。用1-4数字代替颜色会误导基于树的模型。如果我们可以简单地按您建议的那样做,我们就永远不需要独热编码了。 - Marvania Mehul

-3

您可以使用以下方法直接将分类变量提供给随机森林:

  1. 首先使用sklearn标签编码器将特征的类别转换为数字
  2. 其次将标签编码的特征类型转换为字符串(对象)
le=LabelEncoder()
df[col]=le.fit_transform(df[col]).astype('str')

以上代码将解决您的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接