支持向量机(Support Vector Machine, SVM)是一类按监督学习(supervised learning)方式对数据进行二元分类的广义线性分类器(generalized linear classifier),其决策边界是对学习样本求解的最大边距超平面(maximum-margin hyperplane)
在二维空间上,两类点被一条直线完全分开叫做线性可分。从二维扩展到多维空间中时,将两类N维空间完全分开的N-1维面就成了一个超平面。
这些靠近超平面最近的一些点,就称为支持向量
对于非线性问题,运用核函数将数据映射到高维空间后应用线性SVM可获得解决。
SVM在scikit- learn 中的实现类是 SVC 类,我们通过一个简单的例子来演示一下:
import matplotlib.pyplot as plt import numpy as np from sklearn import svm def loadDataSet(fileName): """ Args: fileName 文件名 Returns: dataMat 数据矩阵 labelMat 类标签 """ dataMat = [] labelMat = [] fr = open(fileName) for line in fr.readlines(): lineArr = line.strip().split(',') dataMat.append([float(lineArr[0]), float(lineArr[1])]) labelMat.append(float(lineArr[2])) return dataMat, labelMat X, Y = loadDataSet('./data/datalog2.txt') X = np.mat(X) print("X=", X[:5]) print("Y=", Y[:5]) clf = svm.SVC(C=8,kernel='linear',gamma=10,probability=True) #SVC(C=5, cache_size=200, class_weight=None, coef0=0.0, #, decision_function_shape='ovr', degree=3, gamma=10, kernel='linear', #, max_iter=-1, probability=False, random_state=None, shrinking=True, #, tol=0.001, verbose=False) clf.fit(X, Y) # 获取分割超平面 w = clf.coef_[0] # 斜率 a = -w[0] / w[1] # 从-2到10,顺序间隔采样50个样本,默认是num=50 xx = np.linspace(-2, 10) # , num=50) # 二维的直线方程 yy = a * xx - (clf.intercept_[0]) / w[1] print("yy=", yy) print("support_vectors_=", clf.support_vectors_) 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]) plt.plot(xx, yy, 'k-') plt.plot(xx, yy_down, 'k--') plt.plot(xx, yy_up, 'k--') plt.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1], s=80, facecolors='none') plt.scatter(X[:, 0].flat, X[:, 1].flat, c=Y, cmap=plt.cm.Paired) plt.axis('tight') plt.show()
运行后得到下图
我们再用scikit-learn中自带的手写数字数据集进行实验
import matplotlib.pyplot as plt import numpy as np import scipy,cv2,imageio from sklearn import svm from sklearn.datasets import load_digits from sklearn.model_selection import train_test_split from fractions import Fraction from skimage.transform import resize #读取sklearn.datasets自带的手写数字数据集 datas = load_digits() #print(datas.data[1]) #前63个值为特征,赋值给x,最后一个值是分类,赋值给y x = datas.data[:, :-1] y = datas.target x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=666) #调用svm.SVC方法进行训练 clf = svm.SVC(C=8,kernel='linear',gamma=10,probability=True) #SVC(C=5, cache_size=200, class_weight=None, coef0=0.0, #, decision_function_shape='ovr', degree=3, gamma=10, kernel='linear', #, max_iter=-1, probability=False, random_state=None, shrinking=True, #, tol=0.001, verbose=False) clf.fit(x, y) #print(clf.predict(x[0:15]))#必须以区间取值的方式,4:5 其实就是取 4 这个值 #训练集准确率 print("Train :", clf.score(x_train, y_train)) #测试集准确率 print("Test :", clf.score(x_test, y_test)) #以下为实现用训练好的模型识别自己手写的图片 #图片处理函数,主要是把图片压缩为8*8的格式(和数据集一致),包括变灰度、黑白反转 def image2Digit(image): # 调整为8*8大小 #im_resized = scipy.misc.imresize(image, (8,8))#scipy.misc.imresize这个函数现在不能用了 #print(image.shape) im_resized=cv2.resize(image,(8, 8)) #print('im_resized:') #print(im_resized.shape) im_resized2=im_resized.astype(np.float32) #这里是个坑,CV2默认数据格式是float64的,np默认格式是float32的,这里要把数据格式转一下,否则后面会报错 #print('im_resized2:') #print(im_resized2) # RGB(三维)转为灰度图(一维) im_gray = cv2.cvtColor(im_resized2, cv2.COLOR_BGR2GRAY) #print('im_gray') #print(im_gray.shape) # 调整为0-16之间(digits训练数据的特征规格)像素值——16/255 im_hex = Fraction(16,255) * im_gray #print('im_hex') #print(im_hex) # 将图片数据反相(digits训练数据的特征规格——黑底白字) im_reverse = 16 - im_hex return im_reverse.astype(np.int) #图片文件路径 fp='data/numbers/test1.png' # 读取单张自定义手写数字的图片 #image = scipy.misc.imread(fp) #新版本scipy不支持imread,可以用imageio.imread代替 image = imageio.imread(fp) # 调用上面的函数,将图片转为digits训练数据的规格——即数据的表征方式要统一 im_reverse = image2Digit(image) # 显示图片转换后的像素值 print(im_reverse) # 8*8转为1*64(预测方法的参数要求) reshaped = im_reverse.reshape(1,64) # 预测 result = clf.predict(reshaped[:, :-1]) print('识别到的数字为:{}'.format(result[0]))
打印结果如下:
PS C:\coding\machinelearning>SVM-手写数字数据集实验.py Train : 1.0 Test : 1.0 [[ 0 0 0 0 0 0 0 0] [ 0 0 16 16 16 16 15 0] [ 0 0 16 16 9 9 16 0] [ 0 0 0 0 0 16 16 0] [ 0 0 0 1 14 16 0 0] [ 0 0 16 16 16 8 0 0] [ 0 0 1 15 16 16 16 16] [ 0 0 0 0 0 0 0 2]] 识别到的数字为:2 PS C:\coding\machinelearning>
从图形也能看出来,这是个数字2