机器学习实战----SKLearn实现SVM之minst分类

一、简介

win10, python 3.6, notebook

参考:

【机器学习实战】支持向量机----分类库和简单训练mnist

https://blog.csdn.net/u013597931/article/details/80076058

SVM学习笔记(二)----手写数字识别

https://blog.csdn.net/chunxiao2008/article/details/50448154

二、SVM模块详解

基本理论-------算法库------属性-------方法

基本理论:

  • 基本思想是利用最大间隔进行分类
  • 处理非线性问题是通过核函数将特征向量映射到高维空间,从而变成线性可分的,但是运算却是在低维空间运行的
  • 考虑到数据中可能存在噪音,还引入了松弛变量。

sklearn.svm模块中提供了这些库: 

è¿éåå¾çæè¿°

 大概分成这几类(除了svm_l1_min_c返回的是惩罚参数C的最低界) 

è¿éåå¾çæè¿°

分类库主要参数:

è¿éåå¾çæè¿°

其他参数介绍可以看官方库: 
http://scikit-learn.org/stable/modules/classes.html#module-sklearn.svm 
或者看看这位博主的总结(总结的很到位): 
http://www.cnblogs.com/pinard/p/6117515.html
 

属性:

è¿éåå¾çæè¿°

方法:

和一般模型都一样,训练用的fit(),评分的score(),预测新样本的predict(),还有计算样本点到分离超平面的距离的decision_function()等等。

三、简单实现SVM分类

分别使用三种不同的SVC进行分类

  • SVC:     svm.SVC(kernel='linear')
  • LinearSVC:  svm.LinearSVC()
  • NuSVC:      svm.NuSVC(kernel='linear'

可以看出:

  • LinearSVC训练得到的分离超平面与SVC有所不同;
  • NuSVC模型的支持向量占了一半样本数量,当nu=0.01时,和SVC相同,因此,当对训练误差或支持向量的百分比有要求时,可以选择NuSVC

1、数据集

##用于可视化图表
import matplotlib.pyplot as plt
##用于做科学计算
import numpy as np
##用于做数据分析
import pandas as pd
##用于加载数据或生成数据等
from sklearn import datasets
##加载svm模型
from sklearn import svm
##随机生成一组特征数量为2,样本数量为80的数据集
X, y = datasets.make_blobs(n_samples=80, n_features=2, centers=2, random_state=3)
fig=plt.figure(figsize=(10,8))
plt.xlim(-8,4)  #  设置x轴刻度范围
plt.ylim(-5,8)  #  设置y轴刻度范围
plt.scatter(X[:, 0], X[:, 1], c=y, s=30)
plt.show()

2、 svm.SVC(kernel='linear')

##加载svm的svc模型,选择线性核linear
model_svc=svm.SVC(kernel='linear')
model_svc.fit(X,y)

print("各类的支持向量在训练样本中的索引",model_svc.support_)
print("各类所有的支持向量:\n",model_svc.support_vectors_)
print("各类各有多少个支持向量",model_svc.n_support_)
print("各特征系数",model_svc.coef_)
print("截距",model_svc.intercept_)
print("各样本点到分离超平面的距离:\n",model_svc.decision_function(X))

fig=plt.figure(figsize=(10,8))
plt.xlim(-8,4)  #  设置x轴刻度范围
plt.ylim(-5,8)  #  设置y轴刻度范围
##显示分离超平面
w1=model_svc.coef_[:,0]
w2=model_svc.coef_[:,1]
b=model_svc.intercept_
x1=np.linspace(-8,6,2) 
x2=(w1*x1+b)/(-1*w2)
x2_up=(w1*x1+b+1)/(-1*w2)
x2_down=(w1*x1+b-1)/(-1*w2)
plt.plot(x1,x2,'k-',linewidth=0.8)
plt.plot(x1,x2_up,'k--',linewidth=0.8)
plt.plot(x1,x2_down,'k--',linewidth=0.8)
##显示样本点和支持向量
plt.scatter(X[:, 0], X[:, 1], c=y,s=30)
plt.scatter(model_svc.support_vectors_[:, 0], model_svc.support_vectors_[:, 1],s=80,c='',edgecolors='b')
plt.show()
各类的支持向量在训练样本中的索引 [ 3 77 63]
各类所有的支持向量:
 [[ 0.21219196  1.74387328]
 [-1.23229972  3.89519459]
 [-2.94843418  0.3655385 ]]
各类各有多少个支持向量 [2 1]
各特征系数 [[-0.48951758 -0.32852537]]
截距 [-0.32333516]
各样本点到分离超平面的距离:
 [-1.96224709  1.96992652  1.61830594 -1.00011347 -3.03968748 -1.91355576
 -3.20222196  1.07605938  1.39390527  1.19794817 -3.09852679 -2.99356435
  1.83058651  2.46025289  1.84454041 -1.98203511  1.18207352 -2.21362739
 -1.93596757  1.5062249  -3.13955464 -1.41328098  2.11163776 -2.0100733
  1.23402066 -1.3997197   1.42460256  1.9676612   1.10767531  1.64961948
  1.95638419  1.51193805 -1.2642258   2.06733658  1.99862207  1.49307471
 -1.44123444 -1.54063897  2.21232256  3.39921728  1.08180429  1.72267793
 -3.1813601   1.61914905  1.59985133 -1.70286262 -1.94181226  1.59417872
  2.15236394 -2.64727844 -2.54908967 -1.45290411 -2.30745878 -2.58497233
  2.2307059  -2.6951711  -2.96443813 -1.73637146  2.20696118 -1.77028229
 -2.67467925 -1.60612382  2.59439321  0.99988654 -1.59570877  1.53629311
 -2.69403494  1.44783106 -2.07984685 -1.3734872   1.09058746  1.60125344
  1.76284029 -1.83576229 -1.90749178 -2.44163699  2.01923035 -0.99977302
  2.01835361 -1.9910022 ]

3、svm.LinearSVC()

##加载svm的LinearSVC模型
model_svc=svm.LinearSVC()
model_svc.fit(X,y)
print("各特征系数",model_svc.coef_)
print("截距",model_svc.intercept_)
print("各样本点到分离超平面的距离:\n",model_svc.decision_function(X))

fig=plt.figure(figsize=(10,8))
plt.xlim(-8,4)  #  设置x轴刻度范围
plt.ylim(-5,8)  #  设置y轴刻度范围
##显示分离超平面
w1=model_svc.coef_[:,0]
w2=model_svc.coef_[:,1]
b=model_svc.intercept_
x1=np.linspace(-8,6,2) 
x2=(w1*x1+b)/(-1*w2)
x2_up=(w1*x1+b+1)/(-1*w2)
x2_down=(w1*x1+b-1)/(-1*w2)
plt.plot(x1,x2,'k-',linewidth=0.8)
plt.plot(x1,x2_up,'k--',linewidth=0.8)
plt.plot(x1,x2_down,'k--',linewidth=0.8)

##显示样本点和支持向量
plt.scatter(X[:, 0], X[:, 1], c=y,s=30)
plt.show()
各特征系数 [[-0.43861872 -0.34666587]]
截距 [-0.17687917]
各样本点到分离超平面的距离:
 [-1.93588632  1.87233349  1.51364971 -0.87449188 -2.92992153 -1.76381697
 -3.07749808  1.04025334  1.29833361  1.11381917 -2.93977862 -2.79956624
  1.71631792  2.39358778  1.73195783 -1.92786837  1.09573885 -2.04452242
 -1.82100181  1.42159955 -2.9877508  -1.29033632  2.02059401 -1.88099763
  1.19084793 -1.30551704  1.40518201  1.87446768  0.99415791  1.64725845
  1.9009514   1.43403277 -1.1375335   1.94926655  1.87258846  1.44713253
 -1.30509778 -1.4745769   2.12237058  3.19811264  1.04509393  1.58901995
 -3.04486552  1.48196178  1.52057507 -1.59990501 -1.8120006   1.48499025
  2.06828345 -2.51227207 -2.3304399  -1.36943056 -2.11483449 -2.43410562
  2.09715535 -2.51291992 -2.80568943 -1.64868248  2.14688497 -1.69265193
 -2.59427138 -1.57782921  2.51736177  0.98963954 -1.54715292  1.50308216
 -2.61135208  1.38378795 -1.94731015 -1.30279915  0.96583083  1.58100889
  1.64279966 -1.796035   -1.8219179  -2.28425194  1.91261392 -0.98670045
  1.90619623 -1.79154379]

4、 svm.NuSVC(kernel='linear')

##加载svm的NuSVC模型,nu为默认值0.5
model_svc=svm.NuSVC(kernel='linear')
#model_svc=svm.NuSVC(kernel='linear',nu=0.01)
model_svc.fit(X,y)
print("各类的支持向量在训练样本中的索引",model_svc.support_)
print("各类各有多少个支持向量",model_svc.n_support_)
print("各特征系数",model_svc.coef_)
print("截距",model_svc.intercept_)
print("各样本点到分离超平面的距离:\n",model_svc.decision_function(X))

fig=plt.figure(figsize=(10,8))
plt.xlim(-8,4)  #  设置x轴刻度范围
plt.ylim(-5,8)  #  设置y轴刻度范围
##显示分离超平面
w1=model_svc.coef_[:,0]
w2=model_svc.coef_[:,1]
b=model_svc.intercept_
x1=np.linspace(-8,6,2) 
x2=(w1*x1+b)/(-1*w2)
x2_up=(w1*x1+b+1)/(-1*w2)
x2_down=(w1*x1+b-1)/(-1*w2)
plt.plot(x1,x2,'k-',linewidth=0.8)
plt.plot(x1,x2_up,'k--',linewidth=0.8)
plt.plot(x1,x2_down,'k--',linewidth=0.8)

##显示样本点和支持向量
plt.scatter(X[:, 0], X[:, 1], c=y,s=30)
plt.scatter(model_svc.support_vectors_[:, 0], model_svc.support_vectors_[:, 1],s=80,c='',edgecolors='b')
plt.show()
各类的支持向量在训练样本中的索引 [ 0  3  5 18 21 25 32 36 37 45 46 51 57 59 61 64 69 73 74 77 79  2  7  8
  9 16 19 24 26 28 31 35 40 43 44 47 63 65 67 70 71]
各类各有多少个支持向量 [21 20]
各特征系数 [[-0.26852918 -0.18506518]]
截距 [-0.07402223]
各样本点到分离超平面的距离:
 [-1.00000001  1.18344728  0.98651753 -0.45373219 -1.59369374 -0.9613798
 -1.68303355  0.69021961  0.86209936  0.75377706 -1.62199582 -1.56013705
  1.10412131  1.46001562  1.11206673 -1.00846728  0.74471129 -1.12708414
 -0.97711454  0.92581127 -1.64554153 -0.68461074  1.26315788 -1.017172
  0.77771057 -0.67970603  0.886296    1.18259074  0.70066156  1.01348247
  1.17979741  0.9296235  -0.60106054  1.23592282  1.1968279   0.92205787
 -0.6989911  -0.76097669  1.31946142  1.97167963  0.69334256  1.04208873
 -1.67029696  0.98397159  0.97856961 -0.84810873 -0.97900041  0.97262943
  1.28653695 -1.3723103  -1.30974513 -0.7103885  -1.17727995 -1.33606029
  1.32568017 -1.39466306 -1.54714741 -0.86822923  1.31923904 -0.88809099
 -1.3926683  -0.80103249  1.53393157  0.65006995 -0.79334001  0.94736295
 -1.4032617   0.89512436 -1.0557987  -0.66724352  0.69008091  0.9848262
  1.0657701  -0.92815667 -0.96394481 -1.25544599  1.21013198 -0.46397868
  1.20912877 -1.        ]

四、minst数据集

minist官网: http://yann.lecun.com/exdb/mnist/

官网上的数据集是gz格式,在windows下,解压gz格式比较麻烦,

因此分别采用两种数据集进行训练:

  • 一是解压好的官网数据集,
  • 一是mnist.pkl.gz,并进行比较

1、mnist.pkl.gz

参考:https://blog.csdn.net/chunxiao2008/article/details/50448154

直接调用scikit-learn库中的SVM,使用默认的参数,1000张手写数字图片,判断准确的图片就高达9435张。

以上代码没有用验证集进行验证。这是因为本例中,用测试集和验证集要判断的是一个东西,没有必要刻意用验证集再来验证一遍。

导入数据:

# import cPickle
import _pickle as cPickle
import gzip
import numpy as np
from sklearn import svm
import time

def load_data():
    """
    返回包含训练数据、验证数据、测试数据的元组的模式识别数据
    训练数据包含50,000张图片,测试数据和验证数据都只包含10,000张图片
    """
    f = gzip.open('MNIST_data/mnist.pkl.gz', 'rb')
    # training_data, validation_data, test_data = cPickle.load(f)
    training_data, validation_data, test_data = cPickle.load(f,encoding='bytes')
    f.close()
    return (training_data, validation_data, test_data)

分类:

# 使用SVM分类器,从MNIST数据集中进行手写数字识别的分类程序


def svm_baseline():
    #print time.strftime('%Y-%m-%d %H:%M:%S') 
    print(time.strftime('%Y-%m-%d %H:%M:%S'))
    training_data, validation_data, test_data = load_data()
    # 传递训练模型的参数,这里用默认的参数
    clf = svm.SVC()
    # clf = svm.SVC(C=8.0, kernel='rbf', gamma=0.00,cache_size=8000,probability=False)
    # 进行模型训练
    clf.fit(training_data[0], training_data[1])
    # test
    # 测试集测试预测结果
    predictions = [int(a) for a in clf.predict(test_data[0])]
    num_correct = sum(int(a == y) for a, y in zip(predictions, test_data[1]))
    print("%s of %s test values correct." % (num_correct, len(test_data[1])))
    print(time.strftime('%Y-%m-%d %H:%M:%S'))

if __name__ == "__main__":
    svm_baseline()

结果:

2018-12-17 15:16:57
9435 of 10000 test values correct.
2018-12-17 15:29:36

2、t10k-images.idx3-ubyte等

数据:

import numpy as np
import struct
import matplotlib.pyplot as plt
import os
##加载svm模型
from sklearn import svm
###用于做数据预处理
from sklearn import preprocessing
import time
path='MNIST_data'
def load_mnist_train(path, kind='train'):    
    labels_path = os.path.join(path,'%s-labels.idx1-ubyte'% kind)
    images_path = os.path.join(path,'%s-images.idx3-ubyte'% kind)
    with open(labels_path, 'rb') as lbpath:
        magic, n = struct.unpack('>II',lbpath.read(8))
        labels = np.fromfile(lbpath,dtype=np.uint8)
    with open(images_path, 'rb') as imgpath:
        magic, num, rows, cols = struct.unpack('>IIII',imgpath.read(16))
        images = np.fromfile(imgpath,dtype=np.uint8).reshape(len(labels), 784)
    return images, labels
def load_mnist_test(path, kind='t10k'):
    labels_path = os.path.join(path,'%s-labels.idx1-ubyte'% kind)
    images_path = os.path.join(path,'%s-images.idx3-ubyte'% kind)
    with open(labels_path, 'rb') as lbpath:
        magic, n = struct.unpack('>II',lbpath.read(8))
        labels = np.fromfile(lbpath,dtype=np.uint8)
    with open(images_path, 'rb') as imgpath:
        magic, num, rows, cols = struct.unpack('>IIII',imgpath.read(16))
        images = np.fromfile(imgpath,dtype=np.uint8).reshape(len(labels), 784)
    return images, labels   
train_images,train_labels=load_mnist_train(path)
test_images,test_labels=load_mnist_test(path)

分类:

# 标准化
X=preprocessing.StandardScaler().fit_transform(train_images)  
X_train=X[0:60000]
y_train=train_labels[0:60000]

# 模型训练
print(time.strftime('%Y-%m-%d %H:%M:%S'))
model_svc = svm.SVC()
model_svc.fit(X_train,y_train)
print(time.strftime('%Y-%m-%d %H:%M:%S'))

# 评分并预测
x=preprocessing.StandardScaler().fit_transform(test_images)
x_test=x[0:10000]
y_pred=test_labels[0:10000]
print(model_svc.score(x_test,y_pred))
y=model_svc.predict(x_test)

结果:

2018-12-17 17:20:00
2018-12-17 17:30:53

0.9657

总结:

可见,使用两种数据集,运行时长10分钟余,输出结果有较大的误差,可通过参数调节进行调节

重要参数:

  • C : 浮点型,可选 (默认=1.0)。误差项的惩罚参数C 
  • kernel : 字符型, 可选 (默认=’rbf’)。指定核函数类型。只能是’linear’, ‘poly’, ‘rbf’, ‘sigmoid’, 等
  • degree : 整形, 可选 (默认=3)。用多项式核函数(‘poly’)时,多项式核函数的参数d,用其他核函数,这个参数可忽略 
  • gamma : 浮点型, 可选 (默认=0.0)。’rbf’, ‘poly’ and ‘sigmoid’核函数的系数。如果gamma是0,实际将使用特征维度的倒数值进行运算。也就是说,如果特征是100个维度,实际的gamma是1/100。 
  • oef0 : 浮点型, 可选 (默认=0.0)。核函数的独立项,’poly’ 和’sigmoid’核时才有意义。 

机器学习大牛Andrew Ng说,关于SVM分类算法,他一直用的是高斯核函数,其它核函数他基本就没用过。可见,这个核函数应用最广。 

gamma参数,当使用高斯核进行映射时,如果选得很小的话,高次特征上的权重实际上衰减得非常快,所以实际上(数值上近似一下)相当于一个低维的子空间;反过来,如果gamma选得很大,则可以将任意的数据映射为线性可分——这样容易导致非常严重的过拟合问题。 

C参数是寻找 margin 最大的超平面”和“保证数据点偏差量最小”)之间的权重。C越大,模型允许的偏差越小。 

相同的C,gamma越大,分类边界离样本越近。相同的gamma,C越大,分类越严格。 

如果gamma太大,无论C取多大都不能阻止过拟合。

当gamma很小,分类边界很像线性的。

取中间值时,好的模型的gamma和C大致分布在对角线位置。

还应该注意到,当gamma取中间值时,C取值可以是很大的。 

猜你喜欢

转载自blog.csdn.net/bailixuance/article/details/85051594