scala - Flink SVM 90% 错误分类

标签 scala svm apache-flink flinkml

我尝试使用 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()

绘制的数据如下所示:

Plot of the Data

最佳答案

SVM 分类器不会为您提供到原点的距离(也就是偏差或阈值),因为这是预测器的参数。阈值的不同值将导致不同的精度和召回指标,并且最佳是特定于用例的。通常我们使用 ROC (Receiver Operating Characteristic) curve找到它。
SVM上的相关属性是(来自 Flink docs ):

  • ThresholdValue - 设置测试/预测的阈值。下面的输出被归类为负,而上面的输出被归类为正。默认为 0。
  • OutputDecisionFunction - 将其设置为 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/

    相关文章:

    在 R 中运行 tune.svm 并花费很长时间

    apache-flink - Flink Stateful Functions 与现有 Flink 应用程序

    scala - 在 flink 中高效计算属性数量

    scala - Twitter 说 Scala 不能发出原始的未修饰的 volatile 字段。真的?

    scala - 是否有 Scala 命令行调试器?

    具有参数类型的 Scalacheck/Scalatest

    time-series - 使用支持向量机进行时间序列预测

    java - 寻找适用于 scala、java 或 python 的通用 Oauth 库

    python - 为多标签 SVM 分配权重以平衡类

    apache-flink - Flink 窗口状态大小和状态管理