SVM最初被用来解决线性分类问题,加入核方法之后能有效解决非线性问题。
分类学习基本思想:
基于训练集在样本空间中找到一个划分超平面,将不同类别的样本分开.
选择最优超平面的依据:
1.无法找到其他绘制方法使得到两条虚线之间的距离更大
2.最优超平面到与两种类型距其最近的点有相等的距离
支持向量(support.vector)就是离分隔超平面最近的那些点。
SVM硬间隔(Hard Margin)
严格地规定所有的数据都必须划分正确,即所有数据都在虚线两边
Hard Margin
软间隔(Soft Margin)
允许一些样本落在间隔内(两条虚线中间),防止出现过度拟合。
Soft Margin
这种情况下我们要尽可能正确地分类训练数据,间隔要尽可能大。
C值大,间隔小。C值小,间隔大。
可用交叉验证确定C值。
如果SVM模型过拟合,可以尝试通过减小超参数C去调整.
线性不可分问题
任何有限维度的非线性问题在更高维度的空间里总可以变化成线性可分问题。
SVM使用拉格朗日乘子法(Lagrange Multiplier)实现对超平面求解问题的升维。
Non-Linear
核函数
SVM其实并不需要真正的向量,可以用它们的数量积来进行分类。这意味着可以避免计算资源的耗费了。这就是核函数的技巧,它可以减少大量的计算资源的需求。通常,内核是线性的,所以可得到一个非线性的分类器:只需改变点积为我们想要的空间。
在不知道特征映射的形状时,我们并不知道什么样的核函数是合适的,于是“核函数选择”成为支持向量机的最大变数。
线性核(linear)
c=1时退化为线性核 高斯径向基核(Gaussian radial basis function) Sigmoid核
decision_function()函数可以返回输入的数据集与模型超平面之间的距离,用正负关系表示在超平面的哪一侧。该距离的绝对值越大则分类的可靠性越高。
非线性
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_circles
from mpl_toolkits.mplot3d import Axes3D
# generating data
X, Y = make_circles(n_samples = 500, noise = 0.05)
# visualizing data
plt.scatter(X[:, 0], X[:, 1], c = Y, marker = '.')
plt.show()
# adding a new dimension to X
X1 = X[:, 0].reshape((-1, 1))
X2 = X[:, 1].reshape((-1, 1))
X3 = (X1**2 + X2**2)
X = np.hstack((X, X3))
# visualizing data in higher dimension
fig = plt.figure()
axes = fig.add_subplot(111, projection = '3d')
axes.scatter(X1, X2, X1**2 + X2**2, c = Y, depthshade = True)
plt.show()
# consider a grid search with an SVM and different kernels
import multiprocessing
import warnings
warnings.filterwarnings('ignore')
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVC
from sklearn.model_selection import cross_val_score
param_grid = [ {'kernel': ['linear', 'rbf', 'poly', 'sigmoid'],
'C': [ 0.1, 0.2, 0.4, 0.5, 1.0, 1.5, 1.8, 2.0, 2.5, 3.0 ]
} ]
gs = GridSearchCV(estimator=SVC(), param_grid=param_grid,
scoring='accuracy', cv=10)
gs.fit(X, Y)
GridSearchCV(cv=10, error_score='raise',
estimator=SVC(C=1.0, kernel='rbf', max_iter=-1),
param_grid=[{'kernel': ['linear', 'rbf', 'poly', 'sigmoid'],
'C': [0.1, 0.2, 0.4, 0.5, 1.0, 1.5, 1.8, 2.0, 2.5, 3.0 ]}],
scoring='accuracy')
print(gs.best_estimator_)
print(gs.best_score_)
# create support vector classifier using a linear kernel
from sklearn import svm
svc = svm.SVC(kernel = 'linear')
svc.fit(X, Y)
w=svc.coef_
b=svc.intercept_
# plotting the separating hyperplane
x1 = X[:, 0].reshape((-1, 1))
x2 = X[:, 1].reshape((-1, 1))
x1, x2 = np.meshgrid(x1, x2)
x3 = -(w[0][0]*x1 + w[0][1]*x2 + b) / w[0][2]
fig = plt.figure()
axes2 = fig.add_subplot(111, projection = '3d')
axes2.scatter(X1, X2, X1**2 + X2**2, c = Y, depthshade = True)
axes1 = fig.gca(projection = '3d')
axes1.plot_surface(x1, x2, x3, alpha = 0.01)
plt.show()
在noise=0.05时,输出结果显示最好的核是rbf,且准确率达到了98%。
在noise=0.1时,最好的核是linear,准确率为85.6%
人脸识别
from sklearn.datasets import fetch_lfw_people
faces = fetch_lfw_people(min_faces_per_person=60)
print(faces.target_names)
print(faces.images.shape)
from sklearn.svm import SVC
from sklearn.decomposition import PCA
from sklearn.pipeline import make_pipeline
pca = PCA(n_components=150, whiten=True, random_state=19)
svc = SVC(kernel='rbf', class_weight='balanced')
model = make_pipeline(pca, svc)
from sklearn.model_selection import train_test_split
Xtrain, Xtest, ytrain, ytest = train_test_split(faces.data, faces.target,random_state=19)
#用网格搜索交叉检验来寻找最优参数组合
from sklearn.model_selection import GridSearchCV
param_grid =[{'kernel':['rbf','poly'],
'C': [1, 5, 10, 50], # C:控制边界线的硬度
'gamma': [0.0001, 0.0005, 0.001, 0.005]}] #gamma:控制径向基函数核的大小
grid = GridSearchCV(estimator=SVC(), param_grid=param_grid,
scoring='accuracy',cv=8)
grid.fit(faces.data,faces.target)
GridSearchCV(cv=8, error_score='raise',
estimator=SVC(C=1.0, kernel='rbf', max_iter=-1),
param_grid=[{'kernel': [ 'rbf', 'poly'],
'C': [0.1, 0.5, 1.0, 1.5],
'gamma':[0.0001, 0.0005, 0.001, 0.005]}],
scoring='accuracy')
print(grid.best_estimator_)
print(grid.best_score_)
model = grid.best_estimator_
yfit = model.predict(Xtest)
#from sklearn.metrics import classification_report
#print(classification_report(ytest, yfit, target_names=faces.target_names))
手写数字识别
from sklearn.datasets import load_digits
digits = load_digits()
跟上个例子一样可以用网格搜索的方法,只需改成digits.data, digits.target
网友评论