1. 程式人生 > 其它 >Kaggle案例——使用scikit-learn解決DigitRecognition問題

Kaggle案例——使用scikit-learn解決DigitRecognition問題

1、scikit-learn簡介

scikit-learn是一個基於NumPy、SciPy、Matplotlib的開源機器學習工具包,採用Python語言編寫,主要涵蓋分類、

迴歸和聚類等演算法,例如knn、SVM、邏輯迴歸、樸素貝葉斯、隨機森林、k-means等等諸多演算法,官網上程式碼和文件

都非常不錯,對於機器學習開發者來說,是一個使用方便而強大的工具,節省不少開發時間。

scikit-learn官網指南:http://scikit-learn.org/stable/user_guide.html

上一篇文章《大資料競賽平臺—Kaggle入門》(回覆本公眾號“kaggle”可獲取) 我分兩部分內容介紹了Kaggle,在第二部分中,我記錄瞭解決Kaggle上的競賽專案DigitRecognition的整個過程,當時我是用自己寫的kNN演算法,儘管自己寫歌kNN演算法並不會花很多時間,但是當我們想嘗試更多、更復雜的演算法,如果每個演算法都自己實現的話,會很浪費時間,這時候scikit-learn就發揮作用了,我們可以直接呼叫scikit-learn的演算法包。當然,對於初學者來說,最好還是在理解了演算法的基礎上,來呼叫這些演算法包,如果有時間,自己完整地實現一個演算法相信會讓你對演算法掌握地更深入。

2、使用scikit-learn解決DigitRecognition

我發現自己很喜歡用DigitRecognition這個問題來練習分類演算法,因為足夠簡單。如果你還不知道DigitRecognition問題是什麼,請先簡單瞭解一下(https://www.kaggle.com/c/digit-recognizer),在我上一篇文章《大資料競賽平臺—Kaggle入門》中也有描述。下面我使用scikit-learn中的演算法包kNN(k近鄰)、SVM(支援向量機)、NB(樸素貝葉斯)來解決這個問題,解決問題的關鍵步驟有兩個:

1、處理資料。

2、呼叫演算法。

(1)處理資料

這一部分與上一篇文章《大資料競賽平臺—Kaggle入門》

中第二部分的資料處理是一樣的,本文不打算重複,下面只簡單地羅列各個函式及其功能,在本文最後部分也有詳細的程式碼。

def loadTrainData():
    #這個函式從train.csv檔案中獲取訓練樣本:trainData、trainLabel
def loadTestData():
    #這個函式從test.csv檔案中獲取測試樣本:testData
def toInt(array):
def nomalizing(array):
    #這兩個函式在loadTrainData()和loadTestData()中被呼叫
    #toInt()將字串陣列轉化為整數,nomalizing()歸一化整數
def loadTestResult():
    #這個函式載入測試樣本的參考label,是為了後面的比較
def saveResult(result,csvName):
    #這個函式將result儲存為csv檔案,以csvName命名

“處理資料”部分,我們從train.csv、test.csv檔案中獲取了訓練樣本的feature、訓練樣本的label、測試樣本的feature,在程式中我們用trainData、trainLabel、testData表示。

(2)呼叫scikit-learn中的演算法

kNN演算法

#呼叫scikit的knn演算法包
from sklearn.neighbors import KNeighborsClassifier  
def knnClassify(trainData,trainLabel,testData): 
    knnClf=KNeighborsClassifier()#default:k = 5,defined by yourself:KNeighborsClassifier(n_neighbors=10)
    knnClf.fit(trainData,ravel(trainLabel))
    testLabel=knnClf.predict(testData)
    saveResult(testLabel,'sklearn_knn_Result.csv')
    return testLabel

kNN演算法包可以自己設定引數k,預設k=5,上面的comments有說明。

更加詳細的使用,推薦上官網檢視:http://scikit-learn.org/stable/modules/neighbors.html

SVM演算法

#呼叫scikit的SVM演算法包
from sklearn import svm   
def svcClassify(trainData,trainLabel,testData): 
    svcClf=svm.SVC(C=5.0) #default:C=1.0,kernel = 'rbf'. you can try kernel:‘linear’, ‘poly’, ‘rbf’, ‘sigmoid’, ‘precomputed’  
    svcClf.fit(trainData,ravel(trainLabel))
    testLabel=svcClf.predict(testData)
    saveResult(testLabel,'sklearn_SVC_C=5.0_Result.csv')
    return testLabel

SVC()的引數有很多,核函式預設為'rbf'(徑向基函式),C預設為1.0

更加詳細的使用,推薦上官網檢視:http://scikit-learn.org/stable/modules/svm.html

樸素貝葉斯演算法

#呼叫scikit的樸素貝葉斯演算法包,GaussianNB和MultinomialNB
from sklearn.naive_bayes import GaussianNB      #nb for 高斯分佈的資料
def GaussianNBClassify(trainData,trainLabel,testData): 
    nbClf=GaussianNB()          
    nbClf.fit(trainData,ravel(trainLabel))
    testLabel=nbClf.predict(testData)
    saveResult(testLabel,'sklearn_GaussianNB_Result.csv')
    return testLabel
    
from sklearn.naive_bayes import MultinomialNB   #nb for 多項式分佈的資料    
def MultinomialNBClassify(trainData,trainLabel,testData): 
    nbClf=MultinomialNB(alpha=0.1)      #default alpha=1.0,Setting alpha = 1 is called Laplace smoothing, while alpha < 1 is called Lidstone smoothing.       
    nbClf.fit(trainData,ravel(trainLabel))
    testLabel=nbClf.predict(testData)
    saveResult(testLabel,'sklearn_MultinomialNB_alpha=0.1_Result.csv')
    return testLabel

上面我嘗試了兩種樸素貝葉斯演算法:高斯分佈的和多項式分佈的。多項式分佈的函式有引數alpha可以自設定。

更加詳細的使用,推薦上官網檢視:http://scikit-learn.org/stable/modules/naive_bayes.html

使用方法總結:

第一步:首先確定使用哪種分類器,這一步可以設定各種引數,比如:

svcClf=svm.SVC(C=5.0)

第二步:接這個分類器要使用哪些訓練資料?呼叫fit方法,比如:

svcClf.fit(trainData,ravel(trainLabel))

fit(X,y)說明:

X: 對應trainData

array-like, shape = [n_samples, n_features],X是訓練樣本的特徵向量集,n_samples行n_features列,即每個訓練樣本佔一行,每個訓練樣本有多少特徵就有多少列。

y: 對應trainLabel

array-like, shape = [n_samples],y必須是一個行向量,這也是上面為什麼使用numpy.ravel()函式的原因。

第三步:使用分類器預測測試樣本,比如:

 testLabel=svcClf.predict(testData)

呼叫predict方法。

第四步:儲存結果,這一步是取決於我們解決問題的要求,因為本文以DigitRecognition為例,所以有:

saveResult(testLabel,'sklearn_SVC_C=5.0_Result.csv')

(3)make a submission

上面基本就是整個開發過程了,下面看一下各個演算法的效果,在Kaggle上make a submission

knn演算法的效果,準確率95.871%

樸素貝葉斯,alpha=1.0,準確率81.043%

SVM,linear核,準確率93.943%

3、工程檔案

下載:回覆本公眾號“kaggle”可獲取。

貼一下程式碼:

#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
Created on Tue Dec 16 21:59:00 2014

@author: wepon

@blog:http://blog.csdn.net/u012162613
"""

from numpy import *
import csv

def toInt(array):
    array=mat(array)
    m,n=shape(array)
    newArray=zeros((m,n))
    for i in xrange(m):
        for j in xrange(n):
                newArray[i,j]=int(array[i,j])
    return newArray
    
def nomalizing(array):
    m,n=shape(array)
    for i in xrange(m):
        for j in xrange(n):
            if array[i,j]!=0:
                array[i,j]=1
    return array
    
def loadTrainData():
    l=[]
    with open('train.csv') as file:
         lines=csv.reader(file)
         for line in lines:
             l.append(line) #42001*785
    l.remove(l[0])
    l=array(l)
    label=l[:,0]
    data=l[:,1:]
    return nomalizing(toInt(data)),toInt(label)  #label 1*42000  data 42000*784
    #return trainData,trainLabel
    
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))  #  data 28000*784
    #return testData
    
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])  #  label 28000*1
    
#result是結果列表 
#csvName是存放結果的csv檔名
def saveResult(result,csvName):
    with open(csvName,'wb') as myFile:    
        myWriter=csv.writer(myFile)
        for i in result:
            tmp=[]
            tmp.append(i)
            myWriter.writerow(tmp)
            
            
#呼叫scikit的knn演算法包
from sklearn.neighbors import KNeighborsClassifier  
def knnClassify(trainData,trainLabel,testData): 
    knnClf=KNeighborsClassifier()#default:k = 5,defined by yourself:KNeighborsClassifier(n_neighbors=10)
    knnClf.fit(trainData,ravel(trainLabel))
    testLabel=knnClf.predict(testData)
    saveResult(testLabel,'sklearn_knn_Result.csv')
    return testLabel
    
#呼叫scikit的SVM演算法包
from sklearn import svm   
def svcClassify(trainData,trainLabel,testData): 
    svcClf=svm.SVC(C=5.0) #default:C=1.0,kernel = 'rbf'. you can try kernel:‘linear’, ‘poly’, ‘rbf’, ‘sigmoid’, ‘precomputed’  
    svcClf.fit(trainData,ravel(trainLabel))
    testLabel=svcClf.predict(testData)
    saveResult(testLabel,'sklearn_SVC_C=5.0_Result.csv')
    return testLabel
    
#呼叫scikit的樸素貝葉斯演算法包,GaussianNB和MultinomialNB
from sklearn.naive_bayes import GaussianNB      #nb for 高斯分佈的資料
def GaussianNBClassify(trainData,trainLabel,testData): 
    nbClf=GaussianNB()          
    nbClf.fit(trainData,ravel(trainLabel))
    testLabel=nbClf.predict(testData)
    saveResult(testLabel,'sklearn_GaussianNB_Result.csv')
    return testLabel
    
from sklearn.naive_bayes import MultinomialNB   #nb for 多項式分佈的資料    
def MultinomialNBClassify(trainData,trainLabel,testData): 
    nbClf=MultinomialNB(alpha=0.1)      #default alpha=1.0,Setting alpha = 1 is called Laplace smoothing, while alpha < 1 is called Lidstone smoothing.       
    nbClf.fit(trainData,ravel(trainLabel))
    testLabel=nbClf.predict(testData)
    saveResult(testLabel,'sklearn_MultinomialNB_alpha=0.1_Result.csv')
    return testLabel


def digitRecognition():
    trainData,trainLabel=loadTrainData()
    testData=loadTestData()
    #使用不同演算法
    result1=knnClassify(trainData,trainLabel,testData)
    result2=svcClassify(trainData,trainLabel,testData)
    result3=GaussianNBClassify(trainData,trainLabel,testData)
    result4=MultinomialNBClassify(trainData,trainLabel,testData)
    
    #將結果與跟給定的knn_benchmark對比,以result1為例
    resultGiven=loadTestResult()
    m,n=shape(testData)
    different=0      #result1中與benchmark不同的label個數,初始化為0
    for i in xrange(m):
        if result1[i]!=resultGiven[0,i]:
            different+=1
    print different