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

来源:互联网 发布:java中的注解怎么用 编辑:程序博客网 时间:2024/06/16 05:40

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

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

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

import numpy as npimport pandas as pdfrom sklearn import svmimport matplotlib.colorsimport matplotlib.pyplot as pltfrom sklearn.metrics import accuracy_scorefrom sklearn.model_selection import GridSearchCVfrom time import timefrom sklearn.ensemble import AdaBoostClassifierfrom sklearn.linear_model import LogisticRegressionfrom 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<ν10<ν≤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有着更好的表现。

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

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




        

 
阅读全文
0 0
原创粉丝点击