如何在Spark Pipeline中使用随机森林算法?

4
我希望使用Spark进行模型调优,采用网格搜索和交叉验证。在Spark中,必须将基础模型放在管道中,管道的官方演示使用LogisticRegression作为基础模型,可以作为一个新对象。然而,客户端代码无法创建RandomForest模型,因此似乎无法在管道API中使用RandomForest。我不想重新发明轮子,所以有人能给出一些建议吗? 谢谢
1个回答

5

然而,RandomForest模型不能被客户端代码新建,所以似乎无法在管道API中使用RandomForest。

这是真的,但是你只是尝试使用了错误的类。你应该使用ml.classification.RandomForestClassifier而不是mllib.tree.RandomForest。这里有一个基于MLlib文档的例子。

import org.apache.spark.ml.classification.RandomForestClassifier
import org.apache.spark.ml.Pipeline
import org.apache.spark.ml.feature.StringIndexer
import org.apache.spark.mllib.linalg.Vector
import org.apache.spark.mllib.util.MLUtils
import sqlContext.implicits._ 

case class Record(category: String, features: Vector)

val data = MLUtils.loadLibSVMFile(sc, "data/mllib/sample_libsvm_data.txt")
val splits = data.randomSplit(Array(0.7, 0.3))
val (trainData, testData) = (splits(0), splits(1))

val trainDF = trainData.map(lp => Record(lp.label.toString, lp.features)).toDF
val testDF = testData.map(lp => Record(lp.label.toString, lp.features)).toDF

val indexer = new StringIndexer()
  .setInputCol("category")
  .setOutputCol("label")

val rf  = new RandomForestClassifier()
    .setNumTrees(3)
    .setFeatureSubsetStrategy("auto")
    .setImpurity("gini")
    .setMaxDepth(4)
    .setMaxBins(32)

val pipeline = new Pipeline()
    .setStages(Array(indexer, rf))

val model = pipeline.fit(trainDF)

model.transform(testDF)

这里有一件事情我无法理解。据我所知,应该可以直接使用从LabeledPoints中提取的标签,但由于某种原因它不起作用,pipeline.fit会引发IllegalArgumentExcetion

RandomForestClassifier给出了带有无效标签列标签的输入,未指定类别数。

因此,使用StringIndexer进行丑陋的技巧。应用后,我们得到所需的属性({"vals":["1.0","0.0"],"type":"nominal","name":"label"}),但是ml中的某些类似乎可以正常工作而无需使用它。

RandomForestClassifier是spark v1.4中的新功能,但我的环境现在是1.3,我必须等到本月底我的spark集群更新到1.4才行 :-( - bourneli
使用随机森林算法,我得到了输出结果,但是我不知道如何读取它:(1.0 -> prediction=0.0, prob=[0.90,0.08] (0.0 -> prediction=1.0, prob=[0.01,0.88]。看起来这里的prediction只是最高概率值的索引。这意味着我必须查看我的类别才能确定实际的类别。问题在于,如果没有“丑陋的hack”,就无法知道这些类别。这是它应该工作的方式,还是我错过了什么? - evgenii
预计机器学习使用基于0的标签(0.0、1.0、2.0),并且预测和概率也反映了这一点。 - zero323
0-based是清楚的。问题在于不同。我有10个类 - 从0.0、1.0、2.0到9.0。随机森林给出了一些预测,如下所示:(4.0 -> prediction=7.0, 9.0 -> prediction=3.0, 2.0 -> prediction=4.0, 8.0 -> prediction=8.0。根据文档,predicted是“预测标签”,看起来并不像那样。但是!只要有像我从StringIndexer得到的类映射({"ml_attr":{"vals":["1.0","7.0","3.0","9.0","2.0","6.0","0.0","4.0","8.0","5.0"],"type":"nominal","name":"indexedLabel"}}),并将“prediction”作为索引应用于该映射,我就能得到正确的预测! - evgenii
1
是的,没错。恐怕预测标签指的是StringIndexer的输出而不是某个原始字符串,这是正确/预期的行为。在1.6.0版本中,有一个IndexToString转换器可以用于反向映射。 - zero323

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