国庆前后才慢慢开始学习机器学习,在师姐的推荐下选了kaggle上的入门题目,手写体数字识别练练手。一开始接触kaggle感觉想要用一个好的学习算法解决题目还是有难度得,数据量大,还要保证正确率。由于是初学并且刚好最近在书上看到过用KNN算法解决该题目的,所以选择了比较简单的KNN算法。
首先在kaggle上阅读了题目和数据的描述,数据是用.csv格式保存的。训练数据有785列,包括第一列标记,后面的则是784个像素值(0-255,越大约暗),总有42000个例子。测试数据则有28000个例子,同样是784个像素值。
上面已经讲了数据的基本格式,现在准备读取数据并写出前面几行。
import pandas as pd
import numpy as np
import operator
import time
dataset = pd.read_csv('train.csv')
print('dataset{0[0]},{0[1]}'.format(dataset.shape))
print(dataset.head())
从上图中可以看到第一行是label值,因为我们用到的KNN算法中需要比较的只是后面的像素值,所以需要将数据分为两个,一个包含标签,一个是比较的数据。
datalabel = dataset.iloc[:,0].values
datamat = dataset.iloc[:,1:].values
#看到网上有人在这里将矩阵二值化为0,1。想了一下可能会将不同数字二值化为同一个矩阵。
KNN算法非常简单,就是计算出每个训练样本离测试样本的距离,选择最近的一个。下面的代码参考了机器学习实战上的代码。
def handwritting_classify(inx, dataset, labels, k):
"""inx是用于分类的输入向量,输入样本的训练集为dataset,标签向量是labels,k表示最近邻居的数目"""
dataset_size = dataset.shape[0]
diffmat = np.tile(inx,(dataset_size,1)) - dataset
sqdiffmat = diffmaat ** 2
#axis=1,表示将矩阵的每一行相加。
sqdistances = sqdiffmat.sum(axis=1)
distances = sqdistances ** 0.5
#argsort()返回从小到大数值的索引值。
sorted_distindicies = distances.argsort()
classcount = {}
for i in range(k):
vote_label = labels[sorted_distindicies[i]]
classCount[vote_label] = classCount.get(vote_label,0) + 1
#从大到小排序
sorted_classcount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
return sorted_classcount[0][0]
有了分类算法,现在需要对测试集进行分类。这里我们要注意,test.csv没有lable项,重要读取像素值就行了。因为我们用的是KNN算法所以在跑程序时会比较慢,最好在程序里面加入一些能够说明所需时间的变量。
def handwriting_classtest(trainfile, testfile):
#读取训练,测试数据跟开头讲的方法一样,也可以写一个函数在这里调用
#mtest是测试用的数据
mtest = len(testmat)
result = []
for i in range(m):
start_time = time.clock()
result.append(handwritting_classify(testmat[i,:], trainmat, trainlabel, 3))
circletime = time.clock() - start_time
print("%d tasks lest,you need wait %.2f hours" % (mtest-1-i, (mtest-1-i)*circletime/3600))
return result
也是利用pandas中的函数。首先生成能被pandas使用的数据结构DataFrame
result = handwriting_classtest('train.csv', 'test.csv')
submissions = pd.DataFrame({"Imageld":list(range(1,len(pred)+1)), "Label":pred})
submissions.to_csv("submissions.csv",index=False,header=True)
程序跑完总共用了将近4个小时,这也是KNN算法的缺点,每一个测试数据都要重新计算与训练样本的距离。最终精确度是0.96多,排名1000多,百分之60,是比较偏下的名次了。需要进步的还有很多。看了kaggle上的许多笔记,下次可以试着用神经网络去解决这道题目,还要学会用其他的工具来改进程序。希望下次更新时,能得到一个较好的名次。