Scala - MaxBins错误 - 决策树 - 分类变量

时间:2017-11-20 13:25:03

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

我的错误类似于这两篇帖子,尝试过这些可能性,但仍然看到以下错误: 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
})

1 个答案:

答案 0 :(得分: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变量中,其分类特征的名称数组存储在categoricalFeatures变量列表列表-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尚未为handleInvalid="keep"实例实现StringIndexer方法,因此在运行此阶段后,您需要替换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时更改了outputCol的某些值,则应从indexers中删除该原始列(其名称为inputCol的值)。

最后,使用标记点声明df_r:(*)

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中的列号0。如果没有,可以说它是列df_r,将其更改:

i

以这种方式创建trainingData = df_r.rdd.map(lambda row: LabeledPoint(row[i], Vectors.dense(row[:i]+row[i+1:]))) 对我有用。

还有一种从trainingData元数据中获取categoricalFeaturesInfo的简便方法:假设df_r是用k转换的分类列的索引,

StringIndexer

存储原始值,您只需要对所有原始值进行计数就可以知道该列号中有多少个不同的值,而且您可以从那里恢复原始值,而不必使用df_r.schema.fields[k].metadata['ml_attr']['vals']

致谢。

(*)只需少量更改,您就可以在Scala中进行相同的操作。

相关问题