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

Nat*_*iel 1 python svm apache-spark pyspark apache-spark-mllib

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

我搜索过“svm 总是预测相同的值”和类似的问题,对于我们这些机器学习新手来说,这看起来很常见。恐怕我不明白我遇到的答案。

所以我从这个开始,它或多或少是有效的:

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)
Run Code Online (Sandbox Code Playgroud)

我说“或多或少”是因为

model.predict([0])
Out[47]: 0
Run Code Online (Sandbox Code Playgroud)

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

model.predict([1])
Out[48]: 1
Run Code Online (Sandbox Code Playgroud)

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

model.predict([0.000001])
Out[49]: 1
Run Code Online (Sandbox Code Playgroud)

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

在这里,我首先处理我的数据......

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())
Run Code Online (Sandbox Code Playgroud)

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

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))
Run Code Online (Sandbox Code Playgroud)

……只能归为一组,不能归为两组?(下面的列表显示了 SVM 预测的元组,以及答案应该是什么。)

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),
...
Run Code Online (Sandbox Code Playgroud)

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

编辑:我不认为这是规模问题,正如其他一些有类似问题的帖子所建议的那样。我试过把所有东西都乘以 100,但我仍然遇到同样的问题。我也尝试玩弄我如何计算“骰子”变量,但我所能做的就是将 SVM 的猜测从全 0 更改为全 1。

Nat*_*iel 5

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

model.setThreshold(0.5)
Run Code Online (Sandbox Code Playgroud)

那修复它。使用后我想通了

model.clearThreshold()
Run Code Online (Sandbox Code Playgroud)

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