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

How to Predict with a Spark MLlib model trained in LibSVM format

我使用 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 管道是执行此操作的更好方法,但我不想放弃到目前为止所做的所有工作并尝试该策略(如果我可以帮助它) .

当您完成模型训练并只想使用它进行预测时,您不需要 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, ...)))

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

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

接下来,您可以轻松地自己创建向量来进行预测。