機器學習與數據挖掘-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