sklearn中SVM与AdaBoost对手写体数字进行识别

       最近比较忙,自从写了第一篇博客之后,好久没写博客。最近自己捣鼓了一下基于SVM与AdaBoost的手写体数字识别,和大家分享一下这个过程吧。

       首先,数据集的准备,选用的是比较有名的MINIST数据集(数据集可以在这个地方下载点击打开链接,其实,在学习过程中,要用到的大部分数据集在这个地方都可以下载到的)。

       然后,要做的第一件事就是将要用到的包导入:

import numpy as np
import pandas as pd
from sklearn import svm
import matplotlib.colors
import matplotlib.pyplot as plt
from sklearn.metrics import accuracy_score
from sklearn.model_selection import GridSearchCV
from time import time
from sklearn.ensemble import AdaBoostClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
        接下来,我们将准备好的数据集导入,并对训练集和测试集的输入输出进行划分,这个地方我分别采用了pandas.read_csv和numpy.loadtxt这两种方法来导入数据集:

    data = pd.read_csv('optdigits.tra', header=None)#使用pandas载入训练样本
    x, y = data[range(64)].values, data[64].values#划分训练集的输入与输出
    images_tra = x.reshape(-1, 8, 8)#其实每一个8x8的小矩阵表示一个数字,为下面将错误样本画出做准备
    y_tra = y.ravel().astype(np.int)#将数组变为1维数组

    #load test dataset
    datatest = np.loadtxt('optdigits.tes',dtype=np.float, delimiter=',')#其实这个地方也可以采用pandas读入数据
    x_test, y_test = np.split(datatest, (-1,), axis=1)#划分测试样本集的输入与输出
    print y_test.shape
    images_tes = x_test.reshape(-1, 8, 8)#同上
    y_test = y_test.ravel().astype(np.int)
    print images_tes.shape
         在接下来,我们先用svm算法来对手写体数字进行识别:

    model = svm.SVC(C=10.0, kernel='rbf', gamma=0.001)#设置模型参数
    tt1 = time()
    model.fit(x, y_tra)#训练模型
    tt2 = time()
    delta_tt = tt2 - tt1
    print 'SVMxun训练模型耗时:%d分%.3f秒' % ((int)(delta_tt / 60), delta_tt - 60*((int)(delta_tt/60)))
    y_hat = model.predict(x_test)#做预测
    print 'SVC训练集准确率:', accuracy_score(y_tra, model.predict(x))
    print 'SVC测试集准确率:', accuracy_score(y_test, y_hat)
    print y_test
    print y_hat
    num = []
    tmp = []
    for index in range(len(y_test)):
        if (y_test[index] != y_hat[index]):#打印出模型分类的测试样本对应的真实值与模型预测的实际值,以及对应的index
            print y_test[index], y_hat[index], index
            tmp.append(index)#将错误的index记录下来
            num.append(y_test[index])#将这些错误预测结果对应的正确数字保存下来
    print '*************************'
    # print tmp
    # print num



         在识别的过程中,我将测试集中,识别错误的样本下标以及它所对应的正确数字值分别用num数组和tmp数组进行了保存进行了保存。在svm模型参数的设置上,我主要考虑了C,kernel和gamma这三个参数。

C:C-SVC的惩罚参数C,默认值是1.0。C越大,相当于惩罚松弛变量,希望松弛变量接近0,即对误分类的惩罚增大,趋向于对训练集全分对的情

况,这样对训练集测试时准确率很高,但泛化能力弱。C值小,对误分类的惩罚减小,允许容错,将他们当成噪声点,泛化能力较强。

kernel :核函数,默认是rbf,可以是‘linear’, ‘poly’, ‘rbf’, ‘sigmoid’, ‘precomputed’ 

    0 – 线性:u'v

    1 – 多项式:(gamma*u'*v + coef0)^degree

    2 – RBF函数:exp(-gamma|u-v|^2)

    3 –sigmoid:tanh(gamma*u'*v + coef0)

我这里就选用了'rbf'核函数,其他的核函数可以自己尝试一下。

gamma : ‘rbf’,‘poly’ 和‘sigmoid’的核函数参数。默认是’auto’,则会选择1/n_features

之后,我又采用了AdaBoost算法进行了训练和识别。AdaBoost是一种迭代算法,它有两种形式分别为AdaBoostClassifier和AdaBoostRegressor

它的核心思想是针对一个训练集训练不同的分类器(弱分类器),然后把这些弱分类器集合起来,构成一个更强的最终分类器(强分类器)。

在实际的模型参数设置过程中,我们要设置的参数包括:

base_estimatorAdaBoostClassifier和AdaBoostRegressor都有,即我们的弱分类学习器或者弱回归学习器。理论上可以选择任何一个分类

或者回归学习器,不过需要支持样本权重。我们常用的一般是CART决策树或者神经网络MLP。默认是决策树,即AdaBoostClassifier默认使用CART分

类树DecisionTreeClassifier,而AdaBoostRegressor默认使用CART回归树DecisionTreeRegressor。另外有一个要注意的点是,如果我们选择的

AdaBoostClassifier算法是SAMME.R,则我们的弱分类学习器还需要支持概率预测,也就是在scikit-learn中弱分类学习器对应的预测方法除了predict

还需要有predict_proba。

algorithm:这个参数只有AdaBoostClassifier有。主要原因是scikit-learn实现了两种Adaboost分类算法,SAMME和SAMME.R。两者的主要

区别是弱学习器权重的度量,SAMME使用了和我们的原理篇里二元分类Adaboost算法的扩展,即用对样本集分类效果作为弱学习器权重,而SAMME.R

使用了对样本集分类的预测概率大小来作为弱学习器权重。由于SAMME.R使用了概率度量的连续值,迭代一般比SAMME快,因此AdaBoostClassifier

的默认算法algorithm的值也是SAMME.R。我们一般使用默认的SAMME.R就够了,但是要注意的是使用了SAMME.R, 则弱分类学习器参数

base_estimator必须限制使用支持概率预测的分类器。SAMME算法则没有这个限制。

loss:这个参数只有AdaBoostRegressor有,Adaboost.R2算法需要用到。有线性‘linear’, 平方‘square’和指数 ‘exponential’三种选择, 默认

是线性,一般使用线性就足够了,除非你怀疑这个参数导致拟合程度不好。

n_estimators AdaBoostClassifier和AdaBoostRegressor都有,就是我们的弱学习器的最大迭代次数,或者说最大的弱学习器的个数。一般

来说n_estimators太小,容易欠拟合,n_estimators太大,又容易过拟合,一般选择一个适中的数值。默认是50。在实际调参的过程中,我们常常将

n_estimators和下面介绍的参数learning_rate一起考虑。

learning_rate:  AdaBoostClassifier和AdaBoostRegressor都有,即每个弱学习器的权重缩减系数 ν ν,在原理篇的正则化章节我们也讲到

了,加上了正则化项,我们的强学习器的迭代公式为 fk(x)=fk1(x)+ναkGk(x) fk(x)=fk−1(x)+ναkGk(x) ν ν的取值范围

0<ν1 0<ν≤1。对于同样的训练集拟合效果,较小的 ν ν意味着我们需要更多的弱学习器的迭代次数。通常我们用步长和迭代最大次数一起来决

定算法的拟合效果。所以这两个参数n_estimators和learning_rate要一起调参。一般来说,可以从一个小一点的 ν ν开始调参,默认是1。

在训练过程中,对于AdaBoost中的弱分类器,我这里分别选择了DT和LR。首先来看一下选择DT的情况:

    clf = AdaBoostClassifier(DecisionTreeClassifier(max_depth=5, min_samples_split=5, min_samples_leaf=5), n_estimators=200, learning_rate=0.05, algorithm='SAMME.R')
    t1 = time()
    clf.fit(x, y_tra)
    t2 = time()
    t = t2 - t1
    print 'AdaBoost-DT训练模型耗时:%d分%.3f秒' %  ((int)(t/60), t-60*(int)(t/60))
    y_hat1 = clf.predict(x_test)
    print 'AdaBoost-DT训练集准确率:', accuracy_score(y_tra, clf.predict(x))
    print 'AdaBoost-DT测试集准确率:', accuracy_score(y_test, y_hat1)
    print '*************************'
在决策树参数的选择上,决策树最大深度max_depth我选取5,内部节点再划分所需最小样本数min_samples_split我选取5,叶子节点最少样本数

min_samples_leaf我选在5,其他参数我采用默认值。对于这些参数,我个人觉得,如果给的太大,那么必然会产生过拟合的情况,如果给的太小,

那么就会产生欠你和的情况。

再来看一下选用逻辑回归的情况:

    clf1 = AdaBoostClassifier(LogisticRegression(penalty='l2'), n_estimators=200, learning_rate=0.05, algorithm='SAMME', random_state=None)
    t2 = time()
    clf1.fit(x, y_tra)
    t3 = time()
    delta_t = t3 - t2
    y_hat2 = clf1.predict(x_test)
    print 'AdaBoost-LR训练集准确率:', accuracy_score(y_tra, clf1.predict(x))
    print 'AdaBoost-LR测试集准确率:', accuracy_score(y_test, y_hat2)
    print 'AdaBoost-LR训练模型耗时:%d分%.3f秒' % ((int)(delta_t/60), delta_t-60*(int)(delta_t/60))
这里,在LR参数的选择上,我主要就改了penalty这个参数,具体为啥改成这个参数,我也没有具体的理论依据,只是自己尝试着玩一下的。。。

最后,我们来看一下模型的识别效果:




从模型的表现上来看,SVM有着更好的表现。

代码和数据集我已经上传,可以在这个地方进行下载点击打开链接

大家一起学习,欢迎批评指正。




        


  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值