Scala 使用保存的Spark模型评估新数据

Scala 使用保存的Spark模型评估新数据,scala,apache-spark,apache-spark-mllib,Scala,Apache Spark,Apache Spark Mllib,我已经成功地构建了一个将我的数据转换成LibSVM文件的模型,并在Spark的MLlib包中在此基础上训练了一个决策树模型。我在中使用了Scala代码,只更改了文件名: import org.apache.spark.mllib.tree.DecisionTree import org.apache.spark.mllib.tree.model.DecisionTreeModel import org.apache.spark.mllib.util.MLUtils // Load and pa

我已经成功地构建了一个将我的数据转换成LibSVM文件的模型,并在Spark的MLlib包中在此基础上训练了一个决策树模型。我在中使用了Scala代码,只更改了文件名:

import org.apache.spark.mllib.tree.DecisionTree
import org.apache.spark.mllib.tree.model.DecisionTreeModel
import org.apache.spark.mllib.util.MLUtils

// Load and parse the data file.
val data = MLUtils.loadLibSVMFile(sc, "data/mllib/sample_libsvm_data.txt")
// Split the data into training and test sets (30% held out for testing)
val splits = data.randomSplit(Array(0.7, 0.3))
val (trainingData, testData) = (splits(0), splits(1))

// Train a DecisionTree model.
//  Empty categoricalFeaturesInfo indicates all features are continuous.
val categoricalFeaturesInfo = Map[Int, Int]()
val impurity = "variance"
val maxDepth = 5
val maxBins = 32

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

// Evaluate model on test instances and compute test error
val labelsAndPredictions = testData.map { point =>
  val prediction = model.predict(point.features)
  (point.label, prediction)
}
val testMSE = labelsAndPredictions.map{ case (v, p) => math.pow(v - p, 2) }.mean()
println("Test Mean Squared Error = " + testMSE)
println("Learned regression tree model:\n" + model.toDebugString)

// Save and load model
model.save(sc, "target/tmp/myDecisionTreeRegressionModel")
val sameModel = DecisionTreeModel.load(sc, "target/tmp/myDecisionTreeRegressionModel")
代码正确显示模型的MSE和学习的树模型。然而,我一直在琢磨如何使用
sameModel
来评估新数据。比如,如果我用来训练模型的LibSVM文件如下所示:

0 1:1.0 2:0.0 3:0.0 4:0.0 5:0.0 6:0.0 7:0.0 8:0.0 9:0.0 10:0.0 11:0.0 12:0 13:0 14:0 15:9 16:19
0 1:1.0 2:0.0 3:0.0 4:0.0 5:0.0 6:0.0 7:0.0 8:0.0 9:0.0 10:0.0 11:0.0 12:1 13:0 14:0 15:9 16:12
0 1:1.0 2:0.0 3:0.0 4:0.0 5:0.0 6:0.0 7:0.0 8:0.0 9:0.0 10:0.0 11:0.0 12:0 13:0 14:0 15:6 16:7
我如何向训练有素的模型提供这样的信息,并让它预测标签

1:1.0 2:0.0 3:0.0 4:0.0 5:0.0 6:0.0 7:0.0 8:0.0 9:0.0 10:0.0 11:0.0 12:0 13:0 14:0 15:9 16:19
1:1.0 2:0.0 3:0.0 4:0.0 5:0.0 6:0.0 7:0.0 8:0.0 9:0.0 10:0.0 11:0.0 12:1 13:0 14:0 15:9 16:12
1:1.0 2:0.0 3:0.0 4:0.0 5:0.0 6:0.0 7:0.0 8:0.0 9:0.0 10:0.0 11:0.0 12:0 13:0 14:0 15:6 16:7
编辑(2017年8月31日下午3:56,东部)

根据以下建议,我正在尝试predict函数,但代码似乎不太正确:

val new_data = MLUtils.loadLibSVMFile(sc, "hdfs://.../new_data/*")

val labelsAndPredictions = new_data.map { point =>
  val prediction = sameModel.predict(point.features)
  (point.label, prediction)
}

labelsAndPredictions.take(10)

如果我用一个包含“1”值的LibSVM文件作为标签来运行它(我用文件中的十个新行进行测试),那么它们在
labelsandprodictions.take(10)
命令中都返回为“1.0”。如果我给它一个“0”值,那么它们都返回为“0.0”,因此似乎没有正确预测任何内容。

加载方法应该返回一个模型。然后使用RDD[Vector]或单个向量调用
predict

  • 加载原始数据(如上所述,是一个类似的LibSVM文件)
  • 提供有关分类功能的信息
  • 对于上述数据中的每个点,通过调用savedModel.predict(point.features)进行预测

  • 您可以通过
    管道
    从磁盘加载ML模型:

    import org.apache.spark.ml._
    val pipeline = Pipeline.read.load("sample-pipeline")
    
    scala> val stageCount = pipeline.getStages.size
    stageCount: Int = 0
    
    val pipelineModel = PipelineModel.read.load("sample-model")
    
    scala> pipelineModel.stages
    
    获取
    管道后
    用户可以对数据集进行评估:

    val model = pipeline.fit(dataset)
    val predictions = model.transform(dataset)
    
    您必须使用适当的
    评估器
    ,例如
    回归评估器
    。 Evaluator处理具有预测的数据集:

    import org.apache.spark.ml.evaluation.RegressionEvaluator
    val regEval = new RegressionEvaluator
    println(regEval.explainParams)
    regEval.evaluate(predictions)
    
    UPD如果您处理过
    hdfs
    您可以轻松加载/保存模型:

    将模型保存到HDFS的一种方法如下:

    // persist model to HDFS
    sc.parallelize(Seq(model), 1).saveAsObjectFile("hdfs:///user/root/sample-model")
    
    然后可以将保存的模型加载为:

    val linRegModel = sc.objectFile[LinearRegressionModel]("hdfs:///user/root/sample-model").first()
    linRegModel.predict(Vectors.dense(11.0, 2.0, 2.0, 1.0, 2200.0))
    
    或与上面的示例类似,但改为本地文件
    hdfs

    PipelineModel.read.load("hdfs:///user/root/sample-model")
    

    将带有hdfs的文件发送到集群中所有节点都可以看到的目录。在您的代码中加载它并预测。

    如果我只是从LibSVM文件中删除标签(“1:1.0 2:0.0…”),Spark不喜欢这样。它无法执行那一行新代码,为输入字符串调用
    java.lang.NumberFormat异常:“1:1.0”
    错误。你在那个地方放了什么?我不理解你在上述“评论”中面临的问题。根据您上面的编辑,有一个后续问题:您确定,您正在查看返回的预测吗?(您的代码似乎是对的)您可以在昨天编辑的代码中看到
    take()
    的来源。标签值显示,似乎与输入中的任何标签值都匹配
    ”hdfs://.../new_data/*“
    文件。这看起来很有希望。谢谢分享!有一个问题,我在HDFS上现有的文件都不适合替换代码第二行中的“示例管道”部分。你装的是什么?对不起,我现在才回到这个话题。在我的原始代码中使用
    model.save()
    命令中的文件名,您建议的所有三种方法在运行REPL时都会导致错误。使用
    PipelineModel.read.load()
    会出现错误:
    org.json42.package$MappingException:未找到可转换为java.lang.String的值。
    objectFile[]()
    方法导致错误:
    java.io.FileNotFoundException:文件不存在
    。我可以用
    DecisionTreeModel.load()
    加载保存的模型,但加载后似乎无法使用它。@EB您可以无缝地将其迁移到Python,只需替换导入并考虑Python中的动态键入(只需删除
    val
    所有地方)您好。您是否找到了上述预测标签问题的解决方案?