機器學習與數據挖掘-logistic回歸及手寫識別實例的實現

jopen 8年前發布 | 25K 次閱讀 機器學習

本文主要介紹logistic回歸相關知識點和一個手寫識別的例子實現

一、logistic回歸介紹:

logistic回歸算法很簡單,這里簡單介紹一下:

1、和線性回歸做一個簡單的對比

下圖就是一個簡單的線性回歸實例,簡單一點就是一個線性方程表示


(就是用來描述自變量和因變量已經偏差的方程)


2、logistic回歸

可以看到下圖,很難找到一條線性方程能將他們很好的分開。這里也需要用到logistic回歸來處理了。



logistic回歸本質上是線性回歸,只是在特征到結果的映射中加入了一層函數映射,即先把特征線性求和,然后使用函數g(z)將最為假設函數來預測。g(z)可以將連續值映射到0和1上。
logistic回歸的假設函數如下,線性回歸假設函數只是clip_image025



logistic回歸用來分類0/1問題,也就是預測結果屬于0或者1的二值分類問題。這里假設了二值滿足伯努利分布,也就是



其實這里求的是最大似然估計,然后求導,最后得到迭代公式結果為

clip_image007


可以看到與線性回歸類似。

3、logistic回歸原理介紹

(1)找一個合適的預測函數,一般表示為h函數,該函數就是我們需要找的分類函數,它用來預測輸入數據的判斷結果。


(2)構造一個Cost函數(損失函數),該函數表示預測的輸出(h)與訓練數據類別(y)之間的偏差,可以是二者之間的差(h-y)或者是其他的形式。綜合考慮所有訓練數據的“損失”,將Cost求和或者求平均,記為J(θ)函數,表示所有訓練數據預測值與實際類別的偏差。



實際上這里的Cost函數和J(θ)函數是基于最大似然估計推導得到的,這里也就不詳細講解了。

(3)我們可以看出J(θ)函數的值越小表示預測函數越準確(即h函數越準確),所以這一步需要做的是找到J(θ)函數的最小值,Logistic Regression實現時有的是梯度下降法(Gradient Descent)。

clip_image007


梯度下降法是按下面的流程進行的:
1)首先對θ賦值,這個值可以是隨機的,也可以讓θ是一個全零的向量。
2)改變θ的值,使得J(θ)按梯度下降的方向進行減少。
梯度方向由J(θ)對θ的偏導數確定,由于求的是極小值,因此梯度方向是偏導數的反方向。結果為

clip_image007
迭代更新的方式有兩種,一種是批梯度下降,也就是對全部的訓練數據求得誤差后再對θ進行更新,另外一種是增量梯度下降,每掃描一步都要對θ進行更新。前一種方法能夠不斷收斂,后一種方法結果可能不斷在收斂處徘徊。


二、手寫識別的例子實現

1、簡介
手寫識別的概念:是指將在手寫設備上書寫時產生的軌跡信息轉化為具體字碼。
手寫識別系統是個很大的項目,識別漢字、英語、數字、其他字符。本文重點不在手寫識別而在于理解logistic,因此只識別0~9單個數字。

講到用logistic算法識別數字0~9,這是個十類別問題,如果要用logistic回歸,得做10次logistic回歸,第一次將0作為一個類別,1~9作為另外一個類別,這樣就可以識別出0或非0。同樣地可以將1作為一個類別,0、2~9作為一個類別,這樣就可以識別出1或非1........


本文的實例為了簡化,我只選出0和1的樣本,這是個二分類問題。


輸入格式:每個手寫數字已經事先處理成32*32的二進制文本,存儲為txt文件。


工程文件目錄說明:



logistic regression.py實現的功能:從train里面讀取訓練數據,然后用梯度上升算法訓練出參數Θ,接著用參數Θ來預test里面的測試樣本,同時計算錯誤率。


打開test或者train一個文件看看:




2、簡單實現:

(1)將每個圖片(即txt文本)轉化為一個向量,即32*32的數組轉化為1*1024的數組,這個1*1024的數組用機器學習的術語來說就是特征向量。

(2)訓練樣本中有m個圖片,可以合并成一個m*1024的矩陣,每一行對應一個圖片。

(3)用梯度下降法計算得到回歸系數。

(4)分類,根據參數weigh對測試樣本進行預測,同時計算錯誤率。

代碼如下:


# -*- coding: utf-8 -*-
from numpy import *
from os import listdir

"""
(1)將每個圖片(即txt文本)轉化為一個向量,即32*32的數組轉化為1*1024的數組,這個1*1024的數組用機器學習的術語來說就是特征向量。
實現的功能是從文件夾中讀取所有文件,并將其轉化為矩陣返回
如調用loadData('train'),則函數會讀取所有的txt文件('0_0.txt'一直到'1_150.txt')
并將每個txt文件里的32*32個數字轉化為1*1024的矩陣,最終返回大小是m*1024的矩陣
同時返回每個txt文件對應的數字,0或1
"""
def loadData(direction):
    print(direction)
    trainfileList=listdir(direction)
    m=len(trainfileList)
    dataArray= zeros((m,1024))
    labelArray= zeros((m,1))
    for i in range(m):
        returnArray=zeros((1,1024))  #每個txt文件形成的特征向量
        filename=trainfileList[i]
        fr=open('%s/%s' %(direction,filename))
        for j in range(32):
            lineStr=fr.readline()
            for k in range(32):
                returnArray[0,32*j+k]=int(lineStr[k])
        dataArray[i,:]=returnArray   #存儲特征向量

        filename0=filename.split('.')[0]
        label=filename0.split('_')[0]
        labelArray[i]=int(label)     #存儲類別
    return dataArray,labelArray

#sigmoid(inX)函數
def sigmoid(inX):
    return 1.0/(1+exp(-inX))

#用梯度下降法計算得到回歸系數,alpha是步長,maxCycles是迭代步數。
def gradAscent(dataArray,labelArray,alpha,maxCycles):
    dataMat=mat(dataArray)    #size:m*n
    labelMat=mat(labelArray)      #size:m*1
    m,n=shape(dataMat)
    weigh=ones((n,1)) 
    for i in range(maxCycles):
        h=sigmoid(dataMat*weigh)
        error=labelMat-h    #size:m*1
        weigh=weigh+alpha*dataMat.transpose()*error
    return weigh

#分類函數,根據參數weigh對測試樣本進行預測,同時計算錯誤率
def classfy(testdir,weigh):
    dataArray,labelArray=loadData(testdir)
    dataMat=mat(dataArray)
    labelMat=mat(labelArray)
    h=sigmoid(dataMat*weigh)  #size:m*1
    m=len(h)
    error=0.0
    for i in range(m):
        if int(h[i])>0.5:
            print (int(labelMat[i]),'is classfied as: 1')
            if int(labelMat[i])!=1:
                error+=1
                print ('error')
        else:
            print (int(labelMat[i]),'is classfied as: 0')
            if int(labelMat[i])!=0:
                error+=1
                print ('error')
    print ('error rate is:','%.4f' %(error/m))
"""
用loadData函數從train里面讀取訓練數據,接著根據這些數據,用gradAscent函數得出參數weigh,最后就可以用擬
合參數weigh來分類了。
"""                
def digitRecognition(trainDir,testDir,alpha=0.07,maxCycles=10):
    data,label=loadData(trainDir)
    weigh=gradAscent(data,label,alpha,maxCycles)
    classfy(testDir,weigh)

#運行函數    
digitRecognition('train','test',0.01,50)
當然,digitRecognition('train','test',0.01,50)  這里面的0.01 和 50都是可以調整的
最終結果如下:




整個工程文件包括源代碼、訓練集、測試集,可到點擊下載


參考資料:

https://www.coursera.org/course/ml

http://www.cnblogs.com/jerrylead/archive/2011/03/05/1971867.html

http://blog.csdn.net/dongtingzhizi/article/details/15962797

http://openclassroom.stanford.edu/MainFolder/HomePage.php

https://www.coursera.org/course/ml



來自: http://blog.csdn.net//u011067360/article/details/45624517

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!