Scala 使用保存的Spark模型评估新数据
我已经成功地构建了一个将我的数据转换成LibSVM文件的模型,并在Spark的MLlib包中在此基础上训练了一个决策树模型。我在中使用了Scala代码,只更改了文件名: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
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
您可以通过
管道
从磁盘加载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
所有地方)您好。您是否找到了上述预测标签问题的解决方案?