《機器學習實戰》學習總結(五)——Logistic回歸
摘要
1. Logistic回歸分類
2. 梯度下降法
3. 代碼實現與解釋
Logistic回歸
邏輯斯特回歸(logistic regression)是一種非常經典的分類方法。其用到的分類函數一般為Sigmoid函數,其函數形式為:
其圖形表示如下:
從圖中我們可以看到,當z=0時,函數值為0.5。隨著z值的增加,對應的函數值將逼近於1;隨著z值的減小,函數值將逼近於0。
因此為了實現logistic回歸,對於樣本,我們可以在每個特徵上乘以一個回歸係數,然後將所有的結果值相加,將總和帶入sigmoid函數中,進而得到一個範圍在0~1之間的數值。大於0.5的數據被分到1類,小於0.5的即被分到0類。
二分類問題
對於Logistic回歸中的二分類問題,當我們給定數據樣本x時,其被分到1類和0類的條件概率分別為:
其中,
那麼上式就可改寫為:
我們現在需要做的,就是怎麼來確定模型中的參數w呢?
模型參數估計
在Logistic回歸參數學習中,對於給定的訓練數據集T={(x1,y1),(x2,y2),...(xN,yN)},我們用極大似然估計法估計模型參數w,從而得到logistic回歸模型。
當我們對L(w)求得極大值,也就得到了參數w的估計值。
這樣,問題就變成了以對數似然估計為目標函數的最優化問題。而我們解決這個問題我們一般採用梯度下降法和擬牛頓法。
多分類問題
當然,上述的logistic模型同樣可以推廣到多分類問題。設Y的取值為{1,2,3,...K},那麼回歸模型即為:
梯度下降法
梯度下降法可以解決上面對於參數w的優化問題。
梯度下降法是一種迭代演算法,通過選取適當的初始值,不斷迭代,對參數值不斷更新,進行目標函數的極小化,直到收斂。由於負梯度方向是函數值減小最快的方向,所以在迭代的每一步,我們向負梯度方向更新參數值,從而減小函數值。
梯度演算法的迭代公式為:
其中:
同理,梯度上升法,就是向梯度方向移動,以求得函數的極大值。
隨機梯度下降法
在實現梯度下降法時,我們發現在進行梯度下降法的回歸係數更新時需要遍歷整個數據集,如果樣本或者特徵過多的話,這種方法計算複雜度太高。
有一種改進的方法,就是一次我們只隨機用一個樣本點來更新回歸係數,那麼該方法就叫做隨機梯度下降法。
這兩種演算法在下面的代碼部分都有實現,讀者可以自行參考。
求解回歸係數w的方法除了上面提到的梯度下降法,還有擬牛頓法,想要詳細了解的同學可以見《統計學習方法》附錄B。
上面一部分,我們系統地從分類函數講到怎麼確定優化目標函數,再到怎麼解優化目標函數。
至此我們就完成了Logistic回歸原理部分的學習。下面是代碼部分。
代碼實現
1.回歸梯度上升優化演算法
程序清單:
from numpy import *# 打開文本文件函數def loadDataSet(): dataMat=[];labelMat=[] # 打開文本文件 fr=open(r"C:\UsersAdministratorDesktopMliAMLiA_SourceCodemachinelearninginactionCh05 estSet.txt") # 逐行讀取 for line in fr.readlines(): # 對文本進行處理,處理為一個列表 lineArr=line.strip().split() # 加到dataMat中,並把第一個值設為1.0 dataMat.append([1.0,float(lineArr[0]),float(lineArr[1])]) # 求得類別標籤 labelMat.append(int(lineArr[2])) return dataMat,labelMat# 利用sigmoid函數進行計算def sigmoid(inX): return 1.0/(1+exp(-inX))# 梯度上升演算法# dataMatIn里存放的是特徵,但是第一列都為1.0,實際上為100*3的矩陣# classLabels里存放的是類別標籤,1*100的行向量def gradAscent(dataMatIn,classLabels): # 轉換為Numpy矩陣類型 dataMatrix=mat(dataMatIn) # 轉化為矩陣類型並求轉置 labelMat=mat(classLabels).transpose() # 求得矩陣大小 m,n=shape(dataMatrix) # alpha是目標移動的步長 alpha=0.01 # 設置迭代次數 maxCycle=500 # 權重初始化為1 weights=ones((n,1)) for k in range(maxCycle): # 注意,這裡h是一個m*1的列向量 h=sigmoid(dataMatrix*weights) # 求得誤差 error=(labelMat-h) # 更新權重 weights=weights+alpha*dataMatrix.transpose()*error return weights
2.畫出數據集最佳擬合直線
程序清單:
# 作圖def plotBestFit(weights): import matplotlib.pyplot as plt dataMat,labelMat=loadDataSet() # 將dataMat類型變成數組 dataArr=array(dataMat) # 得到數據的樣本數 n=shape(dataArr)[0] xcord1=[];ycord1=[] xcord2=[];ycord2=[] # 將樣本分成兩類,放到列表中 for i in range(n): if int(labelMat[i])==1: xcord1.append(dataArr[i,1]);ycord1.append(dataArr[i,2]) else: xcord2.append(dataArr[i,1]);ycord2.append(dataArr[i,2]) fig=plt.figure() ax=fig.add_subplot(111) # 兩個種類用不同的顏色表示 ax.scatter(xcord1,ycord1,s=30,c="red",marker="s") ax.scatter(xcord2,ycord2,s=30,c="green") # 標註X軸的範圍與步長 x=arange(-3.0,3.0,0.1) # 表示出分界線的方程 y=(-weights[0]-weights[1]*x)/weights[2] ax.plot(x,y) # 坐標名稱 plt.xlabel("X1");plt.ylabel("X2") plt.show()
3.隨機梯度上升演算法
程序清單:
# 隨機梯度上升演算法# 這裡的程序與梯度上升相差不大,唯一的區別是這裡的h、error都是值,不是矩陣def stocGraAscent0(dataMatrix,classLabels): m,n=shape(dataMatrix) alpha=0.01 weights=ones(n) for i in range(m): h=sigmoid(sum(dataMatrix[i]*weights)) error=classLabels[i]-h weights=weights+alpha*error*dataMatrix[i] return weights
4.改進的隨機梯度上升演算法
程序清單:
# 改進的隨即梯度上升演算法def stocGraAscent1(dataMatrix,classLabels,numIter=150): m,n=shape(dataMatrix) alpha=0.01 weights=ones(n) for j in range(numIter): dataIndex=list(range(m)) for i in range(m): # 每次調整alpha alpha=4/(1.0+j+i)+0.01 # 隨機選取樣本來更新回歸係數 randIndex=int(random.uniform(0,len(dataIndex))) h=sigmoid(sum(dataMatrix[randIndex]*weights)) error=classLabels[randIndex]-h weights=weights+alpha*error*dataMatrix[randIndex] # 刪除已經使用過的樣本 del(dataIndex[randIndex]) return weights
5.用Logistic回歸進行分類
程序清單:
#sigmoid()分類函數def classifyVector(inX,weights): prob=sigmoid(sum(inX*weights)) # 值如果大於0.5,歸為1.0類 if(prob>0.5):return 1.0 else:return 0.0def colicTest(): # 打開訓練集合 frTrain=open(r"C:\UsersAdministratorDesktopMliA" "MLiA_SourceCodemachinelearninginactionCh05 horseColicTraining.txt") # 打開測試集合 frTest=open(r"C:\UsersAdministratorDesktopMliA" "MLiA_SourceCodemachinelearninginactionCh05horseColicTest.txt") # 初始化訓練集和標籤的列表 trainingSet=[] trainingLabels=[] for line in frTrain.readlines(): # 對訓練集的數據格式化處理 currLine=line.strip().split(" ") lineArr=[] for i in range(21): # 將每一行的特徵數據放到lineArr中 lineArr.append(float(currLine[i])) # 再將lineArr作為列表放到trainingSet中 trainingSet.append(lineArr) # 將標籤放到trainingLabels中 trainingLabels.append(float(currLine[21])) # 得到訓練集的權重 trainWeights=stocGraAscent1(array(trainingSet),trainingLabels,500) errorCount=0;numTestVec=0.0 # 對測試集進行測試 for line in frTest.readlines(): # 計算測試集的個數 numTestVec+=1.0 # 對測試數據進行格式化處理 currLine=line.strip().split(" ") lineArr=[] for i in range(21): lineArr.append(float(currLine[i])) # 如果學習出來的結果和真實結果不一致,則錯誤數加一 if(int(classifyVector(array(lineArr),trainWeights))!=int(currLine[21])): errorCount+=1 # 計算錯誤率 errorRate=(float(errorCount)/numTestVec) print("the error rate of this test is %f"%errorRate) return errorRate# 調用colicTest()函數多次,計算錯誤率的平均值def multiTest(): numTests=10 errorSum=0.0 for k in range(numTests): errorSum+=colicTest() print("after %d iterations the arrange error rate is:%f" % (numTests,errorSum/float(numTests)))
至此,我們完成了Logistic回歸分類的原理和代碼部分的學習。個人建議推導部分最好自己手動推導一遍,會有效加深自己的理解。下一節學習支持向量機。
聲明
最後,所有資料均本人自學整理所得,如有錯誤,歡迎指正,有什麼建議也歡迎交流,讓我們共同進步!轉載請註明作者與出處。
以上原理部分主要來自於《機器學習》—周志華,《統計學習方法》—李航,《機器學習實戰》—Peter Harrington。代碼部分主要來自於《機器學習實戰》,文中代碼用Python3實現,這是機器學習主流語言,本人也會儘力對代碼做出較為詳盡的注釋。
推薦閱讀:
※R & Python-機器學習演算法速查表
※【小林的OpenCV基礎課 4】滑動條什麼的
※用 Python 實現常用演算法和數據結構
※Python練習第一題,在圖片上加入數字
TAG:机器学习 | Python | 深度学习DeepLearning |