我的错误类似于这两篇帖子,尝试过这些可能性,但仍然看到以下错误: 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
})
答案 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中。
导入Pipeline
和StringIndexer
(*):
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中进行相同的操作。