R的randomForest不能处理超过32个级别。解决方法是什么?


22

R的randomForest包不能处理超过32个级别的因子。当给它超过32个级别时,它将发出错误消息:

无法处理超过32个类别的类别预测变量。

但是我拥有的数据有几个因素。其中一些具有1000+的级别,而某些具有100+。它甚至具有52个美国的“州”。

所以,这是我的问题。

  1. 为什么会有这样的限制?即使对于简单的情况,randomForest也拒绝运行。

    > d <- data.frame(x=factor(1:50), y=1:50)
    > randomForest(y ~ x, data=d)
      Error in randomForest.default(m, y, ...) : 
      Can not handle categorical predictors with more than 32 categories.
    

    如果仅仅是由于内存限制,scikit如何学习使用32个以上级别运行的randomForeestRegressor?

  2. 解决此问题的最佳方法是什么?假设我有X1,X2,...,X50自变量,Y是因变量。并假设X1,X2和X3具有32个以上的级别。我该怎么办?

    我正在考虑为X1,X2和X3中的每一个运行聚类算法,其中距离定义为Y的差值。我将运行三个聚类,因为存在三个有问题的变量。并且希望在每个群集中都可以找到相似的级别。我将合并它们。

    听起来如何?


使用软件包名称和错误消息在网上搜索会提供一些答案。
罗兰

5
@Roland实际上,它把我引到了这里……
同构性

1
您可能会尝试使用数据科学本身,因为有几个统计头脑的人都具有对多维度数据进行编程的经验。
aeroNotAuto15年

2
更新:从4.6-9版本开始,randomForest可以处理多达53个级别的分类预测变量。新闻
2016年

R的随机森林如何确定级别数?我想级别是指类别。
ajp

Answers:


25

这实际上是一个相当合理的约束,因为在具有水平的因子上进行拆分实际上是从可能组合之一中进行选择。因此,即使使用例如25),组合的空间也是如此之大,以至于这种推断意义不大。ñ2ñ-2ñ

大多数其他实现都只是将factor视为序数(即1到整数),这是解决此问题的一种选择。实际上,RF通常足够明智,可以将其分成几组,分成任意组。ñ

另一个选择是更改表示形式-也许您的结果并不直接取决于国家实体,例如,面积,人口,人均松树数量或您可以插入信息系统的其他属性。

也可能是每个状态都是一个孤立且不相关的实体,以至于它需要一个单独的模型。

基于决策进行聚类可能不是一个好主意,因为这样会将信息从决策中走私到属性中,而这通常会导致过度拟合。


4
它可以轻松移动,尽管有点乏味。例如,如果您的水平介于33和1024之间,则创建两个因子,每个因子均<= 32。
KalEl

15

主要原因是randomForest是如何实现的。R的实现在很多方面都遵循了最初的Breiman规范。这里要注意的重要一点是,对于因子/类别变量,拆分条件是二进制的,左侧带有一些标签值,右侧是其余标签值。

这意味着它将搜索两组标签值的所有组合。如果用表示左边的组,用表示右边的组,并且为每个标签枚举一个数字,则将获得范围为组合的数字,从计算的角度来看,这是禁止的。01个[0;2中号-1个]

为什么Weka和Python的实现有效?

默认情况下,weka实现不使用CART树。它使用不存在此计算问题的C45树,因为对于分类输入,它分为多个节点,每个级别值一个。

python随机森林实现不能使用分类/因子变量。您必须将这些变量编码为虚拟或数字变量。

另一个实现可能允许多个级别(此处包括weka),因为即使它们使用CART,也不一定实现双重。这意味着仅通过将一个标签与所有其他值进行分组,就可以找到因子变量的最佳拆分。由于只需要检查分割点,因此所需的计算量要少得多。中号


2
非常感谢!是否从您的回答中得出结论,R的用于处理分类值的实现优于Python的实现(我记得Max Kuhn提到将RF的分类变量分组可提供比将其虚拟化更好的结果),或者至少在R与Python我很有可能获得不同的结果(准确性等...)?根据您的经验,在建模时,尝试将var分组(在R中)并将其虚拟化然后比较两种方法是否有意义?
谢尔盖·布什曼诺夫

2
虚拟编码有效,但只能产生一个类别而不是全部类别。编码后,一次测试一次变量。因此,不可能实现双重化。如果此功能可以提供帮助,我认为实际上没有太大区别。但是,在以可变的重要性进行工作时,还有其他事情可能需要注意:某些实现偏向于具有多个级别的分类。有关详细信息,请参见Carolin Strobl论文:statistik.uni-dortmund.de/useR-2008/slides/Strobl+Zeileis.pdf。在R中,有些实现没有这种偏见。
rapaio

2

您可以尝试以另一种方式表示该列。您可以表示与稀疏数据框相同的数据。

最小可行代码;

example <- as.data.frame(c("A", "A", "B", "F", "C", "G", "C", "D", "E", "F"))
names(example) <- "strcol"

for(level in unique(example$strcol)){
      example[paste("dummy", level, sep = "_")] <- ifelse(example$strcol == level,     1, 0)
}

请注意,原始列中的每个值现在如何变成一个单独的虚拟列。

更广泛的示例代码;

set.seed(0)
combs1 = sample.int(33, size= 10000, replace=TRUE)
combs2 = sample.int(33, size= 10000, replace=TRUE)
combs3 = combs1 * combs2 + rnorm(10000,mean=0,100)
df_hard = data.frame(y=combs3, first=factor(combs1), second=factor(combs2))

for(level in unique(df_hard$first)){
    df_hard[paste("first", level, sep = "_")] <- ifelse(df_hard$first == level, 1, 0)
}

for(level in unique(df_hard$second)){
    df_hard[paste("second", level, sep = "_")] <- ifelse(df_hard$second == level, 1, 0)
}

example$first <- NULL
example$second <- NULL

rf_mod = randomForest( y ~ ., data=example )

即使这段代码表明您确实不再会收到该错误,您仍会注意到randomForest算法现在需要很长时间才能完成。这是由于CPU的限制,您现在也可以通过采样映射减少此任务。

有关更多信息,请查看此博客文章:

https://blog.cloudera.com/blog/2013/02/how-to-resample-from-a-large-data-set-in-parallel-with-r-on-hadoop/


第二个代码块看起来令人困惑,尽管您在整个正文中使用df_hard,但在最后几行中,将“ first”和“ second”设置为NULL,还使用“ example”作为randomForest的数据,这对于我,因为example与df_hard之间没有联系。
Özgür的

Vincent,如果我的订单级别超过100,您是否会觉得我会遇到这么大的麻烦,您是否建议将每一列作为输入添加到随机变量?
Hardik Gupta

另一种选择是在h2o中使用randomforest实现。这为大型数据集提供了更好的支持。我不明白“将每列添加为随机输入”位。
文森特·沃默丹

0

您可以改用extraTrees包。极随机森林算法不会尝试任何断点/分割,而只会尝试分割的有限随机子集。


1
extraTrees有局限性,从某种意义上说,您的输入必须是数字数据矩阵,对吗?
Hardik Gupta

0

另一个选择:根据级别的数量和数据中观测值的数量,您可以合并一些级别。如果您只有几个观察值而具有多个级别,则超出限制范围可能会减小方差。哈德利forcats:fct_lump做到了。

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.