为什么 scikit-learn SVM 解决不了两个同心圆?

机器算法验证 机器学习 Python 支持向量机 scikit-学习 数据预处理
2022-03-02 03:11:31

考虑以下数据集(生成它的代码在帖子的底部): 在此处输入图像描述

运行以下代码:

from sklearn.svm import SVC
model_2 = SVC(kernel='rbf', degree=2, gamma='auto', C=100)
model_2.fit(X_train, y_train)
print('accuracy (train): %5.2f'%(metric(y_train, model_2.predict(X_train))))
print('accuracy (test): %5.2f'%(metric(y_test, model_2.predict(X_test))))
print('Number of support vectors:', sum(model_2.n_support_))

我得到以下输出:

accuracy (train):  0.64
accuracy (test):  0.26
Number of support vectors: 55

我还尝试了不同程度的多项式内核,并得到了或多或少相同的结果。

那么为什么它做得这么差。我刚刚了解了 SVM,我认为二阶多项式核可以将这些点投影到抛物面上,结果将是线性可分的。我在哪里错了?

参考:这篇文章中的代码片段的起始代码来自这个课程

生成数据的代码:

np.random.seed(0)
data, labels = sklearn.datasets.make_circles()
idx = np.arange(len(labels))
np.random.shuffle(idx)
# train on a random 2/3 and test on the remaining 1/3
idx_train = idx[:2*len(idx)//3]
idx_test = idx[2*len(idx)//3:]
X_train = data[idx_train]
X_test = data[idx_test]

y_train = 2 * labels[idx_train] - 1  # binary -> spin
y_test = 2 * labels[idx_test] - 1

scaler = sklearn.preprocessing.StandardScaler()
normalizer = sklearn.preprocessing.Normalizer()

X_train = scaler.fit_transform(X_train)
X_train = normalizer.fit_transform(X_train)

X_test = scaler.fit_transform(X_test)
X_test = normalizer.fit_transform(X_test)
plt.figure(figsize=(6, 6))
plt.subplot(111)
plt.scatter(data[labels == 0, 0], data[labels == 0, 1], color='navy')
plt.scatter(data[labels == 1, 0], data[labels == 1, 1], color='c')
```
3个回答

让我们从警告开始:

  1. 所有预处理都应使用训练集的拟合值完成:

    X_test = scaler.transform(X_test)
    X_test = normalizer.transform(X_test)
    
  2. degree是多项式内核的超参数,如果内核不是 则被忽略poly

    model_2 = SVC(kernel='poly', degree=2, gamma='auto', C=100)
    

    或者

    model_2 = SVC(kernel='rbf', gamma='auto', C=100)
    
  3. 在调试时,在经过预处理后打印最终的数据集,看看您是否已经破坏了数据集:

在此处输入图像描述

不要盲目地进行预处理。删除标准化步骤,因为它只会破坏数据集。您将获得 100% 的准确率。

@gunes 有一个很好的答案:degree 是针对 poly,而 rbf 是由 gamma 和 C 控制的。一般来说,看到默认参数不能正常工作也就不足为奇了。

参见RBF SVM 参数


如果您更改代码

model_2 = SVC(kernel='rbf', gamma=1000, C=100)

您将看到 100% 的培训,但 56% 的测试。

原因是正如@gunes 提到的预处理改变了数据。这也告诉我们 RBF 内核非常强大,可以很好地过拟合训练数据。

答案很简单,也很简短。因为你试图让支持向量机创建一些不可能的东西,所以没有支持向量会限制在这两个圆上。