至于SVM的数学理解,强烈推荐如下三篇知乎博文,我是自学视频学习的,但是如下三篇博文讲的是真的好啊,完全跟我在视频里学习到的是一样的,我很激动啊。
https://zhuanlan.zhihu.com/p/28660098
https://zhuanlan.zhihu.com/p/28954032
https://zhuanlan.zhihu.com/p/77750026
这三篇写的真的是用心极力推荐啊。我就不自己重复工作了,为了搞懂这点,或者说初步搞懂这点,我花了两天的时间,因为自己的数学能力有点薄弱。
我们这一篇主要讲解各个核函数和一些参数的调试过程。
我们拿乳腺癌数据进行学习
第一步,先加载数据。且简单查看一下。
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
import matplotlib.pyplot as plt
import numpy as np
from time import time
import datetime
# 第一步骤:加载数据
breast_cancer = load_breast_cancer()
x = breast_cancer.data
y = breast_cancer.target
print(x.shape)
print(y.shape)
print(breast_cancer.feature_names)
print(breast_cancer.target_names)
# 随便挑选两个特征来可视化一下数据
plt.scatter(x[:, 0], x[:, 1], c=y, cmap='rainbow')
plt.show()
plt.scatter(x[:, 2], x[:, 3], c=y, cmap='rainbow')
plt.show()
第二步:我们尝试使用不同的核函数来拟合
# 第二步骤:查看不同的核函数下的表现哈
Xtrain, Xtest, Ytrain, Ytest = train_test_split(x, y, test_size=0.7, random_state=2)
kernels = ['linear', 'poly', 'rbf', 'sigmoid']
for kernel in kernels:
time0 = time()
clf = SVC(kernel=kernel,
degree=1, # 多项式的d参数
gamma='auto',
cache_size=5000).fit(Xtrain, Ytrain) # 可以使用的内存缓存,单位是M
print('The accuracy under %s kernel is %f' % (kernel, clf.score(Xtest, Ytest)))
print(datetime.datetime.fromtimestamp(time() - time0).strftime('%M:%S:%f'))
输出如下:
The accuracy under linear kernel is 0.939850
00:00:116686
The accuracy under poly kernel is 0.942356
00:00:008981
The accuracy under rbf kernel is 0.614035
00:00:013000
The accuracy under sigmoid kernel is 0.614035
00:00:002995
说明在poly核函数下,拟合乳腺癌数据是又快又好啊,rbf和sigmoid核函数的虽然也挺快,但是效果却及其差。
在我们印象中啊,rbf可以很强大吧,几乎可以做到很多数据集的吧,但是这里的效果确实很不好。
我们来分析下数据。
# 查看数据的分布
import pandas as pd
data = pd.DataFrame(x)
print(data.describe([0.01, 0.05, 0.1, 0.25, 0.5, 0.75, 0.90, 0.99]).T)
从结果来看呢,数据存在量纲不统一的问题,很多数据偏差有点大。
我们先来重新进行数据的标准化
from sklearn.preprocessing import StandardScaler
x = StandardScaler().fit_transform(x)
data = pd.DataFrame(x)
print(data.describe([0.01, 0.05, 0.1, 0.25, 0.5, 0.75, 0.90, 0.99]).T)
此时,每一特征的均值接近于0,方差接近于1,都是标准正太分布了。
我们这时候再来一次。
# 第二步骤:查看不同的核函数下的表现哈
Xtrain, Xtest, Ytrain, Ytest = train_test_split(x, y, test_size=0.7, random_state=2)
kernels = ['linear', 'poly', 'rbf', 'sigmoid']
for kernel in kernels:
time0 = time()
clf = SVC(kernel=kernel,
degree=1, # 多项式的d参数
gamma='auto',
cache_size=5000).fit(Xtrain, Ytrain) # 可以使用的内存缓存,单位是M
print('The accuracy under %s kernel is %f' % (kernel, clf.score(Xtest, Ytest)))
print(datetime.datetime.fromtimestamp(time() - time0).strftime('%M:%S:%f'))
输出如下:
The accuracy under linear kernel is 0.952381
00:00:002958
The accuracy under poly kernel is 0.969925
00:00:000998
The accuracy under rbf kernel is 0.969925
00:00:002992
The accuracy under sigmoid kernel is 0.957393
00:00:002035
诶?这下就好多了吧。几个核函数都提高了,Rbf的表现是最好的啊,而且速度也都是提升了。可以得出,数据的标准化是多么重要啊。
所以我们得出一个经验,在执行svm之前啊,先进行数据的无量纲化和标准化。
在执行svm之前啊,先进行数据的无量纲化和标准化。
在执行svm之前啊,先进行数据的无量纲化和标准化。
至于还有一些参数,比如说是gamma,我们来试着使用学习曲线来看看。
在上面代码运行的基础上,数据经过了那个标准化:
scores = []
gammas = np.linspace(0.001, 1, 100)
for i in gammas:
clf = SVC(kernel='rbf',
# degree=1, # 多项式的d参数
gamma=i,
cache_size=5000).fit(Xtrain, Ytrain) # 可以使用的内存缓存,单位是M
scores.append(clf.score(Xtest, Ytest))
print(max(scores), gammas[scores.index(max(scores))])
plt.plot(gammas, scores)
plt.show()
如果我们使用多项式核函数,那么就会涉及3个参数,gamma,degree和coef,我们一般取degree是1,我们试着找出其他两个参数来看看。
我们使用网格搜索,数据同样需要提前标准化啊:
from sklearn.model_selection import StratifiedShuffleSplit, GridSearchCV
time0 = time()
gamma_range = np.linspace(0.001, 0.1, 10)
coef0_range = np.linspace(0, 5, 10)
param_grid = {'gamma': gamma_range, 'coef0': coef0_range}
cv = StratifiedShuffleSplit(n_splits=10, test_size=0.3, random_state=34)
svc = SVC(kernel='poly', degree=1, cache_size=2000)
grid = GridSearchCV(estimator=svc, param_grid=param_grid, cv=cv)
grid.fit(x, y)
print('best parameters are %s and the score is %0.5f' % (grid.best_params_, grid.best_score_))
print(datetime.datetime.fromtimestamp(time() - time0).strftime('%M:%S:%f'))
在软间隔的问题上有一个参数C(自行学习),软间隔其实就是在噪声的影响下,允许一小点的训练误差,来达到更好的泛化效果,这个参数如何作用呢?
scores = []
kernels = ['linear', 'rbf']
C_range = np.linspace(0.001, 1, 100)
for k in kernels:
score = []
for c in C_range:
clf = SVC(kernel=k,
# degree=1, # 多项式的d参数
gamma='auto',
C=c,
cache_size=5000).fit(Xtrain, Ytrain) # 可以使用的内存缓存,单位是M
score.append(clf.score(Xtest, Ytest))
scores.append(score)
for i in range(len(kernels)):
plt.plot(C_range, scores[i], label=kernels[i])
plt.legend() # 显示图例
plt.show()