我尝试使用 flink-ml svm 实现进行一些二进制分类。
当我评估分类时,我在训练数据集上得到了大约 85% 的错误率。我绘制了 3D 数据,看起来你可以用超平面很好地分离数据。
当我试图从 svm 中获取权重向量时,我只看到了在不拦截超平面的情况下获取权重向量的选项。所以只是一个通过(0,0,0)的超平面。
我不知道错误可能在哪里,并感谢每一条线索。
val env = ExecutionEnvironment.getExecutionEnvironment
val input: DataSet[(Int, Int, Boolean, Double, Double, Double)] = env.readCsvFile(filepathTraining, ignoreFirstLine = true, fieldDelimiter = ";")
val inputLV = input.map(
t => { LabeledVector({if(t._3) 1.0 else -1.0}, DenseVector(Array(t._4, t._5, t._6)))}
)
val trainTestDataSet = Splitter.trainTestSplit(inputLV, 0.8, precise = true, seed = 100)
val trainLV = trainTestDataSet.training
val testLV = trainTestDataSet.testing
val svm = SVM()
svm.fit(trainLV)
val testVD = testLV.map(lv => (lv.vector, lv.label))
val evalSet = svm.evaluate(testVD)
// groups the data in false negatives, false positives, true negatives, true positives
evalSet.map(t => (t._1, t._2, 1)).groupBy(0,1).reduce((x1,x2) => (x1._1, x1._2, x1._3 + x2._3)).print()
绘制的数据如下所示:
最佳答案
SVM 分类器不会为您提供到原点的距离(也就是偏差或阈值),因为这是预测器的参数。阈值的不同值将导致不同的精度和召回指标,并且最佳是特定于用例的。通常我们使用 ROC (Receiver Operating Characteristic) curve找到它。SVM
上的相关属性是(来自 Flink docs ):
true
输出到分离平面的距离而不是二元分类。 ROC曲线
如何找到最佳阈值本身就是一门艺术。在不了解更多问题的情况下,您始终可以做的是为阈值的不同值绘制 ROC 曲线(真阳性率对假阳性率),并寻找与随机猜测距离最大的点(斜率为 0.5 的直线)。但最终阈值的选择还取决于您域中误报的成本与误报的成本。以下是来自维基百科的三个不同分类器的 ROC 曲线示例:
要选择初始阈值,您可以对训练数据(或其样本)进行平均:
// weights is a DataSet of size 1
val weights = svm.weightsOption.get.collect().head
val initialThreshold = trainLV.map { lv =>
(lv.label - (weights dot lv.vector), 1l)
}.reduce { (avg1, avg2) =>
(avg1._1 + avg2._1, avg1._2 + avg2._2)
}.collect() match { case Seq((sum, len)) =>
sum / len
}
然后循环改变它,在测试数据上测量 TPR 和 FPR。
其他超参数
请注意
SVM
教练也有Parameters (这些被称为超参数)需要调整以获得最佳预测性能。有很多技术可以做到这一点,这篇文章会变得太长而无法列出它们。我只是想引起你的注意。如果您觉得懒惰,请访问维基百科上的链接:Hyperparameter optimization .其他维度?
如果您现在不想处理阈值,则有(有点)黑客攻击。您可以将偏差塞入特征向量的另一个维度,如下所示:
val bias = 10 // choose a large value
val inputLV = input.map { t =>
LabeledVector(
if (t._3) 1.0 else -1.0,
DenseVector(Array(t._4, t._5, t._6, bias)))
}
这是一个 nice discussion关于你为什么不应该 做这个。基本上问题在于偏差会参与正则化。但在机器学习中,没有绝对的真理。
关于scala - Flink SVM 90% 错误分类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47597609/