为什么我的 Spark SVM 总是预测相同的标签?

Why is my Spark SVM always predicting the same label?

我无法让 SVM 预测 0 和 1 在我期望的位置。似乎在我训练它并给它更多数据之后,它总是想预测 1 或 0,但它会预测全 1 或全 0,而不会预测两者的混合。我想知道你们中是否有人可以告诉我我做错了什么。

我搜索了 "svm always predicting same value" 和类似的问题,看起来这对于我们这些刚接触机器学习的人来说很常见。恐怕我不明白我遇到的答案。

所以我从这个开始,它或多或少起作用了:

from pyspark.mllib.regression import LabeledPoint
cooked_rdd = sc.parallelize([LabeledPoint(0, [0]), LabeledPoint(1, [1])])
from pyspark.mllib.classification import SVMWithSGD
model = SVMWithSGD.train(cooked_rdd)

我说"more or less"因为

model.predict([0])
Out[47]: 0

是我所期望的,并且...

model.predict([1])
Out[48]: 1

也是我所期望的,但是...

model.predict([0.000001])
Out[49]: 1

绝对不是我所期望的。我认为无论是什么原因造成的,都是我问题的根源。

在这里,我开始处理我的数据...

def cook_data():
  x = random()
  y = random()
  dice = 0.25 + (random() * 0.5)
  if x**2 + y**2 > dice:
    category = 0
  else:
    category = 1
  return LabeledPoint(category, [x, y])

cooked_data = []
for i in range(0,5000):
  cooked_data.append(cook_data())

...我得到了美丽的点云。当我绘制它们时,我得到一个带有一点混乱区域的分区,但是任何幼儿园的孩子都可以画一条线将它们分开。那么为什么当我尝试画一条线将它们分开时...

cooked_rdd = sc.parallelize(cooked_data)
training, testing = cooked_rdd.randomSplit([0.9, 0.1], seed = 1)
model = SVMWithSGD.train(training)
prediction_and_label = testing.map(lambda p : (model.predict(p.features), p.label))

...我只能把他们归为一组,而不是两个? (下面的列表显示了支持向量机预测的元组,以及答案应该是什么。)

prediction_and_label.collect()
Out[54]: 
[(0, 1.0),
 (0, 0.0),
 (0, 0.0),
 (0, 1.0),
 (0, 0.0),
 (0, 0.0),
 (0, 1.0),
 (0, 0.0),
 (0, 1.0),
 (0, 1.0),
...

等等。它只会猜测 0,当应该有一个非常明显的除法时它应该开始猜测 1。谁能告诉我我做错了什么?感谢您的帮助。

编辑:我认为这不是比例问题,正如其他一些有类似问题的帖子所建议的那样。我已经尝试将所有内容乘以 100,但我仍然遇到同样的问题。我也尝试尝试计算 "dice" 变量的方式,但我所能做的就是将 SVM 的猜测从全 0 更改为全 1。

SVM 通常是一个非常依赖调整的模型,如果参数选择不当,就会出现这种退化行为。我建议从更直接的分类模型类型开始,如逻辑回归或决策 trees/random 森林,并首先使其工作以确保您的周围代码正确。

设置完成后,如果您仍想更深入地了解 SVM,可以使用交叉验证网格搜索来为模型和数据集找到更好的参数。关于如何做到这一点的详细信息不仅仅是一个 Stack Overflow 的答案,但网上有很多关于它的好读物。

我明白了为什么它总是预测全 1 或全 0。我需要添加这一行:

model.setThreshold(0.5)

那就解决了。使用

后我想通了
model.clearThreshold()

clearThreshold,然后是预测测试数据,它告诉我计算机预测的是浮点数,而不仅仅是我最终要寻找的二进制 0 或 1。我可以看到 SVM 正在做出我认为违反直觉的舍入决定。通过使用 setThreshold,我现在可以获得更好的结果。