李航,統計學習方法-感知機原理剖析及實現

統計學習方法|感知機原理剖析及實現

 代碼寫思路很清晰,膜拜下

import numpy as np
import time

def loadData(fileName):
    '''
    加載Mnist數據集
    :param fileName:要加載的數據集路徑
    :return: list形式的數據集及標記
    '''
    print('start to read data')
    # 存放數據及標記的list
    dataArr = []; labelArr = []
    # 打開文件
    fr = open(fileName, 'r')
    # 將文件按行讀取
    for line in fr.readlines():
        # 對每一行數據按切割福','進行切割,返回字段列表
        curLine = line.strip().split(',')

        # Mnsit有0-9是個標記,由於是二分類任務,所以將>=5的作爲1,<5爲-1
        if int(curLine[0]) >= 5:
            labelArr.append(1)
        else:
            labelArr.append(-1)
        #存放標記
        #[int(num) for num in curLine[1:]] -> 遍歷每一行中除了以第一哥元素(標記)外將所有元素轉換成int類型
        #[int(num)/255 for num in curLine[1:]] -> 將所有數據除255歸一化(非必須步驟,可以不歸一化)
        dataArr.append([int(num)/255 for num in curLine[1:]])

    #返回data和label
    return dataArr, labelArr

def perceptron(dataArr, labelArr, iter=50):
    '''
    感知器訓練過程
    :param dataArr:訓練集的數據 (list)
    :param labelArr: 訓練集的標籤(list)
    :param iter: 迭代次數,默認50
    :return: 訓練好的w和b
    '''
    print('start to trans')
    #將數據轉換成矩陣形式(在機器學習中因爲通常都是向量的運算,轉換稱矩陣形式方便運算)
    #轉換後的數據中每一個樣本的向量都是橫向的
    dataMat = np.mat(dataArr)
    #將標籤轉換成矩陣,之後轉置(.T爲轉置)。
    #轉置是因爲在運算中需要單獨取label中的某一個元素,如果是1xN的矩陣的話,無法用label[i]的方式讀取
    #對於只有1xN的label可以不轉換成矩陣,直接label[i]即可,這裏轉換是爲了格式上的統一
    labelMat = np.mat(labelArr).T
    #獲取數據矩陣的大小,爲m*n
    m, n = np.shape(dataMat)
    #創建初始權重w,初始值全爲0。
    #np.shape(dataMat)的返回值爲m,n -> np.shape(dataMat)[1])的值即爲n,與
    #樣本長度保持一致
    w = np.zeros((1, np.shape(dataMat)[1]))
    #初始化偏置b爲0
    b = 0
    #初始化步長,也就是梯度下降過程中的n,控制梯度下降速率
    h = 0.0001

    #進行iter次迭代計算
    for k in range(iter):
        #對於每一個樣本進行梯度下降
        #李航書中在2.3.1開頭部分使用的梯度下降,是全部樣本都算一遍以後,統一
        #進行一次梯度下降
        #在2.3.1的後半部分可以看到(例如公式2.6 2.7),求和符號沒有了,此時用
        #的是隨機梯度下降,即計算一個樣本就針對該樣本進行一次梯度下降。
        #兩者的差異各有千秋,但較爲常用的是隨機梯度下降。
        for i in range(m):
            #獲取當前樣本的向量
            xi = dataMat[i]
            #獲取當前樣本所對應的標籤
            yi = labelMat[i]
            #判斷是否是誤分類樣本
            #誤分類樣本特診爲: -yi(w*xi+b)>=0,詳細可參考書中2.2.2小節
            #在書的公式中寫的是>0,實際上如果=0,說明改點在超平面上,也是不正確的
            if -1 * yi * (w * xi.T + b) >= 0:
                #對於誤分類樣本,進行梯度下降,更新w和b
                w = w + h *  yi * xi
                b = b + h * yi
        #打印訓練進度
        print('Round %d:%d training' % (k, iter))

    #返回訓練完的w、b
    return w, b


def test(dataArr, labelArr, w, b):
    '''
    測試準確率
    :param dataArr:測試集
    :param labelArr: 測試集標籤
    :param w: 訓練獲得的權重w
    :param b: 訓練獲得的偏置b
    :return: 正確率
    '''
    print('start to test')
    #將數據集轉換爲矩陣形式方便運算
    dataMat = np.mat(dataArr)
    #將label轉換爲矩陣並轉置,詳細信息參考上文perceptron中
    #對於這部分的解說
    labelMat = np.mat(labelArr).T

    #獲取測試數據集矩陣的大小
    m, n = np.shape(dataMat)
    #錯誤樣本數計數
    errorCnt = 0
    #遍歷所有測試樣本
    for i in range(m):
        #獲得單個樣本向量
        xi = dataMat[i]
        #獲得該樣本標記
        yi = labelMat[i]
        #獲得運算結果
        result = -1 * yi * (w * xi.T + b)
        #如果-yi(w*xi+b)>=0,說明該樣本被誤分類,錯誤樣本數加一
        if result >= 0: errorCnt += 1
    #正確率 = 1 - (樣本分類錯誤數 / 樣本總數)
    accruRate = 1 - (errorCnt / m)
    #返回正確率
    return accruRate

if __name__ == '__main__':
    #獲取當前時間
    #在文末同樣獲取當前時間,兩時間差即爲程序運行時間
    start = time.time()

    #獲取訓練集及標籤
    trainData, trainLabel = loadData('../Mnist/mnist_train.csv')
    #獲取測試集及標籤
    testData, testLabel = loadData('../Mnist/mnist_test.csv')

    #訓練獲得權重
    w, b = perceptron(trainData, trainLabel, iter = 30)
    #進行測試,獲得正確率
    accruRate = test(testData, testLabel, w, b)

    #獲取當前時間,作爲結束時間
    end = time.time()
    #顯示正確率
    print('accuracy rate is:', accruRate)
    #顯示用時時長
    print('time span:', end - start)

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章