【问题标题】:Scala - MaxBins error - Decision Tree - Categorical variablesScala - MaxBins 错误 - 决策树 - 分类变量
【发布时间】:2018-05-03 17:42:05
【问题描述】:

我的错误类似于这 2 个帖子,尝试了这些可能性,但仍然看到以下错误: : CLOUDERA && STACK OVERFLOW

   var categoricalFeaturesInfo = Map[Int, Int]()
       categoricalFeaturesInfo += (0 -> 31)
       categoricalFeaturesInfo += (1 -> 7)

java.lang.IllegalArgumentException:要求失败:DecisionTree 要求 maxBins (= 3) 至少与值的数量一样大 在每个分类特征中,但分类特征 0 有 31 个值。 考虑删除这个和其他具有大的分类特征 值的数量,或添加更多的训练示例。

   val numClasses = 2
   val impurity = "gini"
   val maxDepth = 9
   val maxBins = 32

val model = DecisionTree.trainClassifier(trainingData, numClasses, categoricalFeaturesInfo,impurity, maxDepth, maxBins)

问题:最大的分类变量是 31 ,我试过 maxBins = 32 (根据这些帖子中的答案)。我错过了什么吗?

就像试验 n 错误一样,我尝试了所有值集,例如 2 、 3 10 、 15 、 50 、 10000 ,看到同样的错误。 !

使用的地图功能:

val mlprep = flightsRDD.map(flight => {
  val monthday = flight.dofM.toInt - 1 // category
  val weekday = flight.dofW.toInt - 1 // category
})

【问题讨论】:

标签: scala apache-spark machine-learning decision-tree


【解决方案1】:

我在使用 PySpark 时遇到了同样的错误。可能有很多原因:

1) 为确保maxBins 准确无误,请使其等于每个分类列的不同分类值数量的最大值。

maxBins = max(categoricalFeaturesInfo.values() )

2) 错误信息说

...但是分类特征 0 有 31 个值...

trainingData 的第 0 列(第一个,不是第一个特征)实际上是训练集的标签吗?他们一定! DecisionTree.trainClassifier 默认情况下将第一列视为标签。确保标签列是trainingData 的第一个列,而不是特征之一。

3) 你是怎么得到trainingData 的? DecisionTree.trainClassifier 为我工作,表解析为 LabeledPoint,就像 RandomForest.trainClassifier,参见 http://jarrettmeyer.com/2017/05/04/random-forests-with-pyspark。 (*)

4) 此外,在将数据集转换为 LabeledPoint RDD 之前,首先转换原始数据框以对分类列进行索引。

对我有用的是首先使用Pipeline 转换源数据框,每个阶段由StringIndexer 转换组成,用于附加另一列,其值为索引分类列,然后将它们转换为LabeledPoint .

总之,它在 PySpark 中的工作方式如下:

假设原始数据帧存储在df变量中,其分类特征的名称数组存储在categoricalFeaturesvariable-list-array-whateverYouCallIt中。

导入PipelineStringIndexer (*):

from pyspark.ml import Pipeline
pyspark.ml.feature import StringIndexer

要建立流水线阶段,请创建一个 StringIndexer 数组,每个数组索引一个分类列 (*)。见https://spark.apache.org/docs/2.2.0/ml-features.html#stringindexer

indexers = [ StringIndexer(inputCol=column, outputCol=column) for column in categoricalFeatures ]

这里要小心,因为 Spark 版本 1.6 没有为 StringIndexer 实例实现 handleInvalid="keep" 方法,因此您需要在运行此阶段后替换 NULL 值。见https://weishungchung.com/2017/08/14/stringindexer-transform-fails-when-column-contains-nulls/

设置管道:(*)

pipeline = Pipeline( stages=indexers )

现在运行转换:

df_r= pipeline.fit(df).transform(df)

如果这里有问题,请尝试将 outputCol 的值更改为 indexers 中的不同值。如果NULL 值存在于df 中,则会引发NullPointerException

现在categoricalFeatures 列表中的所有(分类)列都在df_r 中编制索引。如果在初始化indexers 时更改了outputCol 的某些值,则应从df_r 中删除该原始列(其名称为inputCol 值)。

最后,使用标记点声明您的trainingData:(*)

from pyspark.mllib.linalg import Vectors
from pyspark.mllib.regression import LabeledPoint

trainingData = df_r.rdd.map(lambda row: LabeledPoint(row[0], Vectors.dense(row[1:])))

这里df_r 的所有列都必须是数字的(因此分类列已经转换为索引列),标签列是df_r 中的列号 0。如果不是,假设它是列i,更改它:

trainingData = df_r.rdd.map(lambda row: LabeledPoint(row[i], Vectors.dense(row[:i]+row[i+1:])))

以这种方式创建trainingData 对我有用。

还有一种快速简便的方法可以从df_r 元数据中获取categoricalFeaturesInfo:让k 成为用StringIndexer 转换的分类列的索引,

df_r.schema.fields[k].metadata['ml_attr']['vals']

存储原始值,您只需将它们全部计数即可知道该列号中有多少不同的值,并且您可以从那里恢复原始值,而不是使用IndexToString

问候。

(*) 只需少量更改,您就可以在 Scala 中做同样的事情。

【讨论】:

    猜你喜欢
    • 2017-01-27
    • 2016-09-11
    • 2021-10-14
    • 2016-12-08
    • 2014-08-23
    • 2019-10-08
    • 2017-05-03
    • 2018-08-14
    • 2020-05-19
    相关资源
    最近更新 更多