kaggle练习之数字识别(Digit Recognition)

 

题目网址:https://www.kaggle.com/c/digit-recognizer

解题过程:

一、获取数据:

三个csv文件,分别是提交样例、测试集、训练集

 二、分析train.csv

train.csv是训练样本集,大小42001*785,第一行是文字描述,所以实际的样本数据大小是42000*785,其中第一列的每一个数字是它对应行的label,可以将第一列单独取出来,得到42000*1的向量trainLabel,剩下的就是42000*784的特征向量集trainData,所以从train.csv可以获取两个矩阵trainLabel、trainData。

下面给出代码,另外关于如何从csv文件中读取数据,参阅:Python csv模块的使用

def loadTrainData():
    l=[]
    with open('train.csv') as file:
         lines=csv.reader(file)
         for line in lines:
             l.append(line) #42001*785,append()函数把每一行line添加到l的末尾
    l.remove(l[0])   #去掉第一行
    l=array(l)   #把l转为动态数组
    label=l[:,0]  #标签是第0列
    data=l[:,1:]  #数据是第1列到最后一列
    return nomalizing(toInt(data)),toInt(label)  #把data正则化


def toInt(array):
    array=mat(array) #把数组转成矩阵,用来求m、n,方便进行for循环遍历
    m,n=shape(array) #m,n是行数和列数
    newArray=zeros((m,n))  
    for i in range(m):
        for j in range(n):
                newArray[i,j]=int(array[i,j])
    return newArray

array和mat的区别:Python mat与array的区别

nomalizing()函数做的工作是归一化,因为train.csv里面提供的表示图像的数据是0~255的,为了简化运算,我们可以将其转化为二值图像,因此将所有非0的数字,即1~255都归一化为1。nomalizing()函数如下:

def nomalizing(array):
    m,n=shape(array)
    for i in range(m):
        for j in range(n):
            if array[i,j]!=0:
                array[i,j]=1
    return array

三、分析test.csv

test.csv里的数据大小是28001*784,第一行是文字描述,因此实际的测试数据样本是28000*784,与train.csv不同,没有label,28000*784即28000个测试样本,我们要做的工作就是为这28000个测试样本找出正确的label。

def loadTestData():
    l=[]
    with open('test.csv') as file:
         lines=csv.reader(file)
         for line in lines:
             l.append(line)
     #28001*784
    l.remove(l[0])
    data=array(l)
    return nomalizing(toInt(data))  

四、分析knn_benchmark.csv(可选)

这个文件里的数据是28001*2,第一行是文字说明,可以去掉,第一列表示图片序号1~28000,第二列是图片对应的数字。从knn_benchmark.csv可以得到28000*1的测试结果矩阵testResult,代码:

def loadTestResult():
    l=[]
    with open('knn_benchmark.csv') as file:
         lines=csv.reader(file)
         for line in lines:
             l.append(line)
     #28001*2
    l.remove(l[0])
    label=array(l)
    return toInt(label[:,1])

五、KNN算法实现数字识别

分类主体程序,计算欧式距离,选择距离最小的k个,返回k个中出现频率最高的类别

原理:https://blog.csdn.net/u012162613/article/details/41768407

kaggle练习之数字识别(Digit Recognition)_第1张图片

#inX是所要测试的向量    1*784
#dataSet是训练样本集,一行对应一个样本。   42000*784

#dataSet对应的标签向量为labels  
#k是所选的最近邻数目

 

def classify(inX, dataSet, labels, k):
    inX=mat(inX)
    dataSet=mat(dataSet)
    labels=mat(labels)  
    #把inX、dataSet、labels都转化为矩阵
    dataSetSize = dataSet.shape[0]   #shape[0]得出dataSet的行数,即样本个数,42000             
    diffMat = tile(inX, (dataSetSize,1)) - dataSet   
    #tile(A,(m,n))将数组A作为元素构造m行n列的数组,diffMat得到了目标与训练数值之间的差值。
    sqDiffMat = array(diffMat)**2
    sqDistances = sqDiffMat.sum(axis=1) #array.sum(axis=1)按行累加,axis=0为按列累加                 
    distances = sqDistances**0.5
    sortedDistIndicies = distances.argsort() #sortedDistIndicies[0]表示排序后排在第一个的那个数在原来数组中的下标           
    classCount={}                                      
    for i in range(k):
        voteIlabel = labels[0,sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1 #对各个label计数累加
    sortedClassCount = sorted(classCount.iteritems(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]

tile这个函数非常牛逼啊,我只说它在这个里面是什么意思,我们知道inX是个向量,而dataset是个矩阵,两者之间要进行相减的运算,需要把这个向量也补成一个和dataset有相同行数列数的矩阵,怎么个补法呢。这就要看tile()的第二个参数了,也就是上面的(datasetsize,1),这个参数的意思就是把inX补成有datasetsize行数的矩阵。

假如inX是(1,2) datasetsize =3 那么经过tile()转换后产生了一个这样的矩阵([1,2],[1,2],[1,2]),然后和dataset相减就是根据矩阵的减法进行的

#get(key,x)从字典中获取key对应的value,没有key的话返回0。

对于测试集里28000个样本,调用28000次这个函数即可。

classify0函数详解:knn算法 -classify0函数详解

六、保存结果

def saveResult(result):
    with open('result.csv','w',newline='') as myFile:    
        myWriter=csv.writer(myFile)
        for i in result:
            tmp=[]
            tmp.append(i)
            myWriter.writerow(tmp)

七、综合各函数

def handwritingClassTest():
    trainData,trainLabel=loadTrainData()
    testData=loadTestData()
    testLabel=loadTestResult()
    m,n=shape(testData)
    errorCount=0
    resultList=[]
    for i in range(m):
         classifierResult = classify(testData[i], trainData, trainLabel, 5)
         resultList.append(classifierResult)
         print("the classifier came back with: %d, the real answer is: %d" % (classifierResult, testLabel[0,i]))
         if (classifierResult != testLabel[0,i]): errorCount += 1.0
    print("\nthe total number of errors is: %d" % errorCount)
    print("\nthe total error rate is: %f" % (errorCount/float(m)))
    saveResult(resultList)
handwritingClassTest();

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(kaggle练习赛)