如何使用以LibSVM格式训练的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")// 将数据分为训练集(60%)和测试集(40%)。val splits = data.randomSplit(Array(0.6, 0.4), seed = 11L)val training = splits(0).cache()val test = splits(1)// 运行训练算法构建模型val model = new LogisticRegressionWithLBFGS()  .setNumClasses(10)  .run(training)

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

附注:看起来Spark的ML管道是更好的方法,但我不想放弃我已经完成的所有工作,如果可以的话,我不想尝试这种策略。


回答:

当你已经完成模型训练并且只想使用它进行预测时,你不需要将数据转换为LabeledPoint格式。你只需要一个向量(可以是密集的或稀疏的,详见这里)来进行预测。

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, ...)))

由于LibSVM文件指定了索引和值,因此示例中使用了SparseVector

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

按照这个方法,你可以轻松地自己创建向量来进行预测。

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注