一、什么是svm
支持向量机(Support Vector Machine, SVM)是一类按监督学习(supervised learning)方式对数据进行二元分类的广义线性分类器(generalized linear classifier),其决策边界是对学习样本求解最大边距超平面(maximum-margin hyperplane) 。
1、支持向量与超平面
在了解svm算法之前,我们首先需要了解一下线性分类器这个概念。比如给定一系列的数据样本,每个样本都有对应的一个标签。为了使得描述更加直观,我们采用二维平面进行解释,高维空间原理也是一样。 举个例子,假设在一个二维线性可分的数据集中,如下图所示,我们要找到一条线(称为超平面)把两组数据分开,这条直线可以是图中的直线H1,也可以是直线H2,或者H3,但哪条直线才最好呢,也就是说哪条直线能够达到最好的分类效果呢?那就是一个能使两类之间的空间大小最大的一个超平面,即图二中的gap在两个分类之间所占空间最大。
- 这个超平面在二维平面上看到的就是一条直线,在三维空间中就是一个平面,高纬度下以此类推,因此,我们把这个划分数据的决策边界统称为超平面。
- 离这个超平面最近的点就叫做支持向量,
- 点到超平面的距离叫间隔。支持向量机就是要使超平面和支持向量之间的间隔尽可能的大,这样超平面才可以将两类样本准确的分开,而保证间隔尽可能的大就是保证我们的分类器误差尽可能的小,尽可能的健壮。
2、松弛变量
实际分类当中很多样本数据都不能够用一个超平面把数据完全分开。如果数据集中存在噪点的话,那么在求超平的时候就会出现很大问题。从图中课看出灰点和白点并不完全分布于直线两端,如果按正常逻辑去计算超平面,可能得到的间隙会很小甚至无法求出,这时候分类模型就起不到应有的作用,甚至会对新样本进行错误分类。因此我们需要引入一个松弛变量,来允许一些数据样本可以处于超平面错误的一侧。
3、核函数
以上讨论的都是在线性可分情况进行讨论的,但是实际问题中给出的数据并不是都是线性可分的,比如有些数据可能是如图样子。
而对于非线性的情况,SVM 的处理方法是选择一个核函数 κernel,通过将数据映射到高维空间,来解决在原始空间中线性不可分的问题。
在线性不可分的情况下,支持向量机首先在低维空间中完成计算,然后通过核函数将输入空间映射到高维特征空间,最终在高维特征空间中构造出最优分离超平面,从而把平面上本身不好分的非线性数据分开。
代码
1、sklearn简单例子
from sklearn import svm
X = [[2, 0], [1, 1], [2, 3]]
y = [0, 0, 1]
clf = svm.SVC(kernel='linear')
clf.fit(X, y)
print(clf)
# 打印支持向量
print(clf.support_vectors_)
# g打印支持向量在数组中的坐标
print(clf.support_ )
# 打印每一类里面有多少个是支持向量
print(clf.n_support_)
结果:
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma='auto', kernel='linear',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
[[1. 1.]
[2. 3.]]
[1 2]
[1 1]
2、利用pylab画出图像
import numpy as np
import pylab as pl
from sklearn import svm
# 生成40个随机的离散点
np.random.seed(0)
X = np.r_[np.random.randn(20, 2) - [2, 2], np.random.randn(20, 2) + [2, 2]]
Y = [0] * 20 + [1] * 20
# 创建分类器模型
clf = svm.SVC(kernel='linear')
clf.fit(X, Y)
# 获取超平面
w = clf.coef_[0]
a = -w[0] / w[1]
xx = np.linspace(-5, 5)
yy = a * xx - (clf.intercept_[0]) / w[1]
# 支持向量
b = clf.support_vectors_[0]
yy_down = a * xx + (b[1] - a * b[0])
b = clf.support_vectors_[-1]
yy_up = a * xx + (b[1] - a * b[0])
print("w: ", w)
print("a: ", a)
# print " xx: ", xx
# print " yy: ", yy
print("support_vectors_: ", clf.support_vectors_)
print("clf.coef_: ", clf.coef_)
# 在图像中画出所有点,以及超平面
pl.plot(xx, yy, 'k-')
pl.plot(xx, yy_down, 'k--')
pl.plot(xx, yy_up, 'k--')
pl.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1],
s=80, facecolors='none')
pl.scatter(X[:, 0], X[:, 1], c=Y, cmap=pl.cm.Paired)
pl.axis('tight')
pl.show()
效果如下
这里的数据仅供参考,生成的随机点不一样,计算出来的超平面以及支持向量也不一样
w: [0.90230696 0.64821811]
a: -1.391980476255765
support_vectors_: [[-1.02126202 0.2408932 ]
[-0.46722079 -0.53064123]
[ 0.95144703 0.57998206]]
clf.coef_: [[0.90230696 0.64821811]]
3、利用svm进行人脸识别
from __future__ import print_function
from time import time
import logging
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.datasets import fetch_lfw_people
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from sklearn.decomposition import PCA
from sklearn.svm import SVC
# 打印进程信息
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(message)s')
###############################################################################
# 下载lfw数据集
lfw_people = fetch_lfw_people(data_home='.\\', min_faces_per_person=70, resize=0.4)
# 获取图像的样本数,高,宽
n_samples, h, w = lfw_people.images.shape
X = lfw_people.data # 获取特征数据
n_features = X.shape[1] # 特征数
y = lfw_people.target # 标签值
target_names = lfw_people.target_names
n_classes = target_names.shape[0]
# 打印相关数据信息
print("Total dataset size:")
print("n_samples: %d" % n_samples)
print("n_features: %d" % n_features)
print("n_classes: %d" % n_classes)
###############################################################################
# 分离测试机和训练集
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25)
###############################################################################
# Compute a PCA (eigenfaces) on the face dataset (treated as unlabeled
# dataset): unsupervised feature extraction / dimensionality reduction
n_components = 150
print("Extracting the top %d eigenfaces from %d faces"
% (n_components, X_train.shape[0]))
t0 = time()
pca = PCA(svd_solver='randomized', n_components=n_components, whiten=True).fit(X_train)
print("done in %0.3fs" % (time() - t0))
eigenfaces = pca.components_.reshape((n_components, h, w))
print("Projecting the input data on the eigenfaces orthonormal basis")
t0 = time()
X_train_pca = pca.transform(X_train)
X_test_pca = pca.transform(X_test)
print("done in %0.3fs" % (time() - t0))
###############################################################################
# 训练svm分类器模型
print("Fitting the classifier to the training set")
t0 = time()
# 计算最适合的参数
param_grid = {'C': [1e3, 5e3, 1e4, 5e4, 1e5],
'gamma': [0.0001, 0.0005, 0.001, 0.005, 0.01, 0.1], }
clf = GridSearchCV(SVC(kernel='rbf'), param_grid)
clf = clf.fit(X_train_pca, y_train)
print("done in %0.3fs" % (time() - t0))
print("Best estimator found by grid search:")
print(clf.best_estimator_)
###############################################################################
# Quantitative evaluation of the model quality on the test set
print("Predicting people's names on the test set")
t0 = time()
y_pred = clf.predict(X_test_pca)
print("done in %0.3fs" % (time() - t0))
print(classification_report(y_test, y_pred, target_names=target_names))
print(confusion_matrix(y_test, y_pred, labels=range(n_classes)))
###############################################################################
# Qualitative evaluation of the predictions using matplotlib
def plot_gallery(images, titles, h, w, n_row=3, n_col=4):
"""Helper function to plot a gallery of portraits"""
plt.figure(figsize=(1.8 * n_col, 2.4 * n_row))
plt.subplots_adjust(bottom=0, left=.01, right=.99, top=.90, hspace=.35)
for i in range(n_row * n_col):
plt.subplot(n_row, n_col, i + 1)
plt.imshow(images[i].reshape((h, w)), cmap=plt.cm.gray)
plt.title(titles[i], size=12)
plt.xticks(())
plt.yticks(())
# plot the result of the prediction on a portion of the test set
def title(y_pred, y_test, target_names, i):
pred_name = target_names[y_pred[i]].rsplit(' ', 1)[-1]
true_name = target_names[y_test[i]].rsplit(' ', 1)[-1]
return 'predicted: %s\ntrue: %s' % (pred_name, true_name)
prediction_titles = [title(y_pred, y_test, target_names, i)
for i in range(y_pred.shape[0])]
plot_gallery(X_test, prediction_titles, h, w)
# plot the gallery of the most significative eigenfaces
eigenface_titles = ["eigenface %d" % i for i in range(eigenfaces.shape[0])]
plot_gallery(eigenfaces, eigenface_titles, h, w)
plt.show()
结果:
Total dataset size:
n_samples: 1288
n_features: 1850
n_classes: 7
Extracting the top 150 eigenfaces from 966 faces
done in 0.131s
Projecting the input data on the eigenfaces orthonormal basis
done in 0.012s
Fitting the classifier to the training set
done in 22.472s
Best estimator found by grid search:
SVC(C=1000.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma=0.005, kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
Predicting people's names on the test set
done in 0.052s
看最后一行,准确率都达到了80%以上
precision recall f1-score support
Ariel Sharon 1.00 0.68 0.81 22
Colin Powell 0.84 0.95 0.89 59
Donald Rumsfeld 0.96 0.81 0.88 31
George W Bush 0.84 0.97 0.90 132
Gerhard Schroeder 0.79 0.71 0.75 21
Hugo Chavez 1.00 0.72 0.84 18
Tony Blair 1.00 0.74 0.85 39
avg / total 0.89 0.87 0.87 322
行表示真实身份,列表示预测身份,我们可以观察对角线上的数据大小来推断其准确性。
[[ 15 4 0 3 0 0 0]
[ 0 56 0 3 0 0 0]
[ 0 2 25 3 1 0 0]
[ 0 4 0 128 0 0 0]
[ 0 0 1 5 15 0 0]
[ 0 1 0 4 0 13 0]
[ 0 0 0 7 3 0 29]]