手写数字图像识别-SVM算法投票法实现多分类

z机器学习课程中svm算法的应用,比起对算法的学习,更重要的收获应该是把算法理论和实际的应用结合起来了。记录一下这个简单的项目。

我没有系统得学习过python,基本上是够用就行,代码能跑就行。程序中有很多漏洞,请多指点。程序使用投票法实现0-9的手写数字图像识别。参考材料是《Python机器学习算法:原理、实现与案例》,参考使用了其中的svm算法和训练集、测试集文件。

1.准备函数

要实现多分类,就需要训练多个二分类器,0-9的数字识别,就需要训练45个二分类器。每次预测都要去训练45个分类器太浪费时间了!调用pickle包把训练的二分类器保存下来,之后使用分类器从文件读取变量就可以了,效率起飞!

# 保存变量函数
def save_variable(v,filename):
    f=open(filename,'wb')
    pickle.dump(v,f)
    f.close()
    return filename
# 读取变量函数
def load_variable(filename):
    f=open(filename,'rb')
    r=pickle.load(f)
    f.close()
    return r

第一步,加载数据。为了训练分类器的效率着想,果断标准化。否则代码跑到天荒地老。这里使用的是sklearn的标准化函数,后面计算混淆矩阵、准确率等操作,都是使用sklearn。

# 加载数据集
def load_set(train_set,test_set):
    # train set
    data_train = np.genfromtxt(train_set, delimiter=',', dtype=float)
    X_train, y_train = data_train[:, :-1], data_train[:, -1]
    ss = StandardScaler()
    ss.fit(X_train)
    X_train_std = ss.transform(X_train)
    # test set
    data_test = np.genfromtxt(test_set, delimiter=',', dtype=float)
    X_test, y_test = data_test[:, :-1], data_test[:, -1]
    X_test_std = ss.transform(X_test)
    return X_train,X_train_std,y_train,X_test,X_test_std,y_test

二分类器嘛,要么正例,要么负例,一次只能判断两个值,所以需要对原始的数据集进行处理,提取正例和负例标签。

#标签转换
def extract(x,y,pos,neg):
    y_train = y[(y == pos) | (y == neg)]
    y_train = np.where(y_train == pos, +1, -1)
    X_train = x[(y == pos) | (y == neg)]
    return X_train,y_train

保存图像的函数,我使用的cv2进行保存。每行数据是一个8*8的图像,这里解释一下为什么每个数值都要乘256,我的代码里调用这个函数,输入的是标准化之后的数值,直接输出图片就是一团黑了。如果使用未标准化的数据,就没必要乘以任何数了。 

#保存图像
def genSamplePic(X,y,path):
    for num in range(X.shape[0]):
        img = X[num].reshape(8, 8) * 256
        if y[num] == 1:
            filename = path+"\正例_" + str(num) + ".png"
        else:
            filename = path+"\负例_" + str(num) + ".png"
        cv2.imwrite(filename, img)

 二分类器预测完结果肯定也是要么正例要么负例,把结果还原成原始标签。

#还原标签
def transLabel(clf,res):
    if res==1:
        return clf.posLabel
    else:
        return clf.negLabel

训练二分类器的函数,0-9每两个数字都要有一个对应的分类器,一共需要45个分类器,那还是封装成一个函数调用吧。

#获取二分类器
def genClassifier(X_train,y_train,pos,neg):
    data=extract(X_train,y_train,pos,neg)
    X_trained=data[0]
    y_trained=data[1]
    clf = SMO(C=1, tol=0.01, posLabel=pos, negLabel=neg, kernel='rbf', gamma=0.01)
    clf.train(X_trained, y_trained)
    return clf

 这个函数是实现多分类的关键操作。读取45个分类器,生成一个分类器列表,每个分类器都预测一下这行数据的原始标签,并保存到结果列表里。出现次数最多的结果就是这一行数据最终的预测结果。

#投票法多分类实现
def predictMC(X_test_k):
    #获取分类器
    clf = [[object for l in range(10)] for h in range(9)]
    for pos in range(9):
        for neg in range(pos + 1, 10):
            filename = "res\分类器" + str(pos) + str(neg) + ".txt"
            clf[pos][neg] = load_variable(filename)
    y_predk = list()
    for pos in range(9):
        for neg in range(pos + 1, 10):
            pred = clf[pos][neg].predict(X_test_k.reshape(1,-1))
            pred_raw = transLabel(clf[pos][neg], pred)
            y_predk.append(pred_raw)
    y_bincount = np.bincount(y_predk)
    result = np.argmax(y_bincount)
    return result

2.main

#!/usr/bin/python
# -*- coding:utf-8 -*-
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix
from sklearn.metrics import accuracy_score
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score

from case26 import load_set, predictMC

# 加载数据集
loadset=load_set('optdigits.tra','optdigits.tes')
X_train=loadset[0]
X_train_std=loadset[1]
y_train=loadset[2]
X_test=loadset[3]
X_test_std=loadset[4]
y_test=loadset[5]
print("X_train:\n",X_train)
print("X_train_std:\n",X_train_std)
print("X_train_std shape:",X_train_std.shape)
print("y_train:\n",y_train)
print("y_train shape:",y_train.shape)
#训练分类器并保存(后面通过读取分类器实现预测,所以这一段运行过一次就不需要了)
'''
clf=[[object for l in range(10)] for h in range(9)]
for pos in range(9):
    for neg in range(pos+1,10):
        #图形
        data_tra = extract(X_train_std, y_train, pos, neg)
        X_tra = data_tra[0]
        y_tra = data_tra[1]
        genSamplePic(X_tra, y_tra, "tra")
        data_tes = extract(X_test_std, y_test, pos, neg)
        X_tes = data_tes[0]
        y_tes = data_tes[1]
        genSamplePic(X_tes, y_tes, "tes")
        #训练分类器保存
        clf[pos][neg]=genClassifier(X_train_std,y_train,pos,neg)
        clf_filename = "res\分类器" + str(pos) + str(neg) + ".txt"
        save_variable(clf[pos][neg], clf_filename)
'''
#预测结果
y_pred=list()
for num in range(X_test_std.shape[0]):
    y_pred.append(predictMC(X_test_std[num]))
print("y_pred:\n",y_pred)
print("y_test:\n",y_test)
matrix_tp=confusion_matrix(y_test,y_pred)
print("matrix_tp:\n",matrix_tp)# 混淆矩阵
plt.imshow(matrix_tp,cmap='Greens')
plt.xticks(range(len(matrix_tp)), range(0,10))
plt.yticks(range(len(matrix_tp)), range(0,10))
for first_index in range(len(matrix_tp)):
    for second_index in range(len(matrix_tp[first_index])):
        plt.text(first_index, second_index, matrix_tp[first_index][second_index])
plt.show()#显示混淆矩阵的图形结果
accuracy_tp=accuracy_score(y_test,y_pred)
print("accuracy_tp:",accuracy_tp)# 准确率
precision_tp=precision_score(y_test,y_pred,average="macro")
print("precision_tp:",precision_tp)# 精确率
recall_tp=recall_score(y_test,y_pred,average="macro")
print("recall_tp:",recall_tp)# 召回率

学习率和步长取0.01,准确率、精确率、召回率大概都在0.97左右,混淆矩阵如下图所示。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值