機器學習與數據挖掘-logistic回歸及手寫識別實例的實現
本文主要介紹logistic回歸相關知識點和一個手寫識別的例子實現
一、logistic回歸介紹:
logistic回歸算法很簡單,這里簡單介紹一下:
1、和線性回歸做一個簡單的對比
下圖就是一個簡單的線性回歸實例,簡單一點就是一個線性方程表示

(就是用來描述自變量和因變量已經偏差的方程)
2、logistic回歸
可以看到下圖,很難找到一條線性方程能將他們很好的分開。這里也需要用到logistic回歸來處理了。

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

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

其實這里求的是最大似然估計,然后求導,最后得到迭代公式結果為
![]()
可以看到與線性回歸類似。
3、logistic回歸原理介紹
(1)找一個合適的預測函數,一般表示為h函數,該函數就是我們需要找的分類函數,它用來預測輸入數據的判斷結果。

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

實際上這里的Cost函數和J(θ)函數是基于最大似然估計推導得到的,這里也就不詳細講解了。
(3)我們可以看出J(θ)函數的值越小表示預測函數越準確(即h函數越準確),所以這一步需要做的是找到J(θ)函數的最小值,Logistic Regression實現時有的是梯度下降法(Gradient Descent)。
![]()
梯度下降法是按下面的流程進行的:
1)首先對θ賦值,這個值可以是隨機的,也可以讓θ是一個全零的向量。
2)改變θ的值,使得J(θ)按梯度下降的方向進行減少。
梯度方向由J(θ)對θ的偏導數確定,由于求的是極小值,因此梯度方向是偏導數的反方向。結果為
![]()
迭代更新的方式有兩種,一種是批梯度下降,也就是對全部的訓練數據求得誤差后再對θ進行更新,另外一種是增量梯度下降,每掃描一步都要對θ進行更新。前一種方法能夠不斷收斂,后一種方法結果可能不斷在收斂處徘徊。
二、手寫識別的例子實現
講到用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