如何使用以LibSVM格式训练的Spark MLlib模型进行预测

时间:2017-10-04 00:11:22

标签: scala apache-spark machine-learning apache-spark-mllib

我使用LibSVM格式的训练数据文件训练了我的模型,如http://spark.apache.org/docs/2.2.0/mllib-linear-methods.html所述。具体来说,我使用了这部分

val data = MLUtils.loadLibSVMFile(sc, "data/mllib/sample_libsvm_data.txt")

// Split data into training (60%) and test (40%).
val splits = data.randomSplit(Array(0.6, 0.4), seed = 11L)
val training = splits(0).cache()
val test = splits(1)

// Run training algorithm to build the model
val model = new LogisticRegressionWithLBFGS()
  .setNumClasses(10)
  .run(training)

但我的问题是你如何为在预测时间以这种方式训练的模型准备你的特征?我想出的解决方案是以libsvm格式保存一个中间文件(带有虚拟标签,因为我只想预测)并使用MLUtils.loadLibSVMFile加载它然后将结果应用于训练模型进行预测。但是,这种策略效率很低,在我的系统中,这需要非常昂贵的collect()调用。有没有任何方法可以将我的数据放入正确的LabeledPoint格式而不先将其放入LibSVM格式(需要和中间文件)?我希望我不必深入研究MLUtils.loadLibSVMFile的内部,以弄清楚libSVM格式的行是如何转换为LabeledPoint对象的。

PS:看起来Spark的ML管道是一种更好的方法,但是我不想废弃我迄今为止所做的所有工作,如果我能帮助它就尝试这种策略。

1 个答案:

答案 0 :(得分:1)

当您完成模型训练并且只想使用它进行预测时,您不需要使用LabeledPoint格式的数据。您唯一需要的是一个矢量(密集或稀疏,请参阅here以获取更多信息)来进行预测。

val prediction = model.predict(features)

当然,也可以转换为LabeledPoint,尽管没有必要。一个小例子:

val rdd = sc.parallelize(Array(
    (1, List(1.0,4.0,8.0)),
    (2, List(3.0,3.0,8.0)),
    (3, List(5.0,5.0,9.0))))

val rdd2 = rdd.map{ case(k, vs) => 
  LabeledPoint(k.toDouble, Vectors.dense(vs.toArray))
}

可以在LibSVM格式和Spark矢量之间进行转换。在LibSVM文件中,每一行都具有以下格式:

<label> <index1>:<value1> <index2>:<value2> ... <indexN>:<valueN>

索引,其中是特征向量中的索引(训练和预测的顺序相同)。 MLUtils.loadLibSVMFile()会在此之后创建LabeledPoint,即每个LabeledPoint将如下所示:

LabeledPoint(label, Vectors.sparse(N, Array(index1-1, index2-1, ...), Array(value1, value2, ...)))

示例中使用了SparseVector,因为LibSVM文件同时指定了索引和值。

在LibSVM中,索引从1开始,而更常见的约定(包括创建SparseVector)是从0开始,因此,从LibSVM格式转换时从索引中减去1是必要的。

在此之后,您可以自己轻松创建矢量以进行预测。