第二十二章 logistic regression 演算法(上)

邏輯回歸(LogisticRegression)

Logistic regression (邏輯回歸)是當前業界比較常用的機器學習方法,用於估計某種事物的可能性。類似某用戶購買某商品的可能性,某病人患有某種疾病的可能性啊等等。這個世界是隨機的(當然了,人為的確定性系統除外,但也有可能有雜訊或產生錯誤的結果,只是這個錯誤發生的可能性太小了,小到千萬年不遇,小到忽略不計而已),所以萬物的發生都可以用可能性或者幾率(Odds)來表達。「幾率」指的是某事物發生的可能性與不發生的可能性的比值。

Logistic regression可以用來回歸,也可以用來分類,主要是二分類。它給我們提供的就是你的這個樣本屬於正類的可能性是多少。

假設我們的樣本是{x, y},y是0或者1,表示正類或者負類,x是我們的m維的樣本特徵向量。那麼這個樣本x屬於正類,也就是y=1的「概率」可以通過下面的邏輯函數來表示:

這裡θ是模型參數,也就是回歸係數,σ是sigmoid函數。實際上這個函數是由下面的對數幾率(也就是x屬於正類的可能性和負類的可能性的比值的對數)變換得到的:

換句話說,y也就是我們關係的變數,我們將這些對應x1, x2,…, xm的權值叫做回歸係數,表達為θ1, θ2,…, θm。他們的加權和就是你的總得分了。

所以說上面的logistic回歸就是一個線性分類模型,它與線性回歸的不同點在於:為了將線性回歸輸出的很大範圍的數,例如從負無窮到正無窮,壓縮到0和1之間,這樣的輸出值表達為「可能性」才能說服廣大民眾。當然了,把大值壓縮到這個範圍還有個很好的好處,就是可以消除特別冒尖的變數的影響。而實現這個偉大的功能其實就只需要平凡一舉,也就是在輸出加一個logistic函數。另外,對於二分類來說,可以簡單的認為:如果樣本x屬於正類的概率大於0.5,那麼就判定它是正類,否則就是負類。

所以說,LogisticRegression 就是一個被logistic方程歸一化後的線性回歸,僅此而已。

歸入到正統的機器學習框架下,模型選好了,只是模型的參數θ還是未知的,我們需要用我們收集到的數據來訓練求解得到它。那我們下一步要做的事情就是建立代價函數了。

LogisticRegression最基本的學習演算法是最大似然。

假設我們有n個獨立的訓練樣本{(x1, y1) ,(x2, y2),…, (xn, yn)},y={0, 1}。那每一個觀察到的樣本(xi, yi)出現的概率是:

上面為什麼是這樣呢?當y=1的時候,後面那一項是不是沒有了,那就只剩下x屬於1類的概率,當y=0的時候,第一項是不是沒有了,那就只剩下後面那個x屬於0的概率(1減去x屬於1的概率)。所以不管y是0還是1,上面得到的數,都是(x, y)出現的概率。那我們的整個樣本集,也就是n個獨立的樣本出現的似然函數為(因為每個樣本都是獨立的,所以n個樣本出現的概率就是他們各自出現的概率相乘):

那最大似然法就是求模型中使得似然函數最大的係數取值θ*。這個最大似然就是我們的代價函數(cost function)了。

OK,那代價函數有了,我們下一步要做的就是優化求解了。我們先嘗試對上面的代價函數求導,看導數為0的時候可不可以解出來,也就是有沒有解析解,有這個解的時候,就皆大歡喜了,一步到位。如果沒有就需要通過迭代了,耗時耗力。

我們先變換下L(θ):取自然對數,然後化簡(不要看到一堆公式就害怕哦,很簡單的哦,只需要耐心一點點,自己動手推推就知道了。註:有xi的時候,表示它是第i個樣本,下面沒有做區分了,相信你的眼睛是雪亮的),得到:

這時候,用L(θ)對θ求導,得到:

然後我們令該導數為0,你會很失望的發現,它無法解析求解。不信你就去嘗試一下。所以沒辦法了,只能藉助高大上的迭代來搞定了。這裡選用了經典的梯度下降演算法。

優化求解

梯度下降(gradient descent)

Gradient descent 又叫 steepest descent,是利用一階的梯度信息找到函數局部最優解的一種方法,也是機器學習裡面最簡單最常用的一種優化方法。它的思想很簡單,和我開篇說的那樣,要找最小值,我只需要每一步都往下走(也就是每一步都可以讓代價函數小一點),然後不斷的走,那肯定能走到最小值的地方,例如下圖所示:

但,我同時也需要更快的到達最小值啊,怎麼辦呢?我們需要每一步都找下坡最快的地方,也就是每一步我走某個方向,都比走其他方法,要離最小值更近。而這個下坡最快的方向,就是梯度的負方向了。

對logistic Regression來說,梯度下降演算法新鮮出爐,如下:

其中,參數α叫學習率,就是每一步走多遠,這個參數蠻關鍵的,該參數前的正負號分別表示梯度上升或梯度下降。

梯度上升、隨機梯度上升演算法的python2實現:

from numpy import *def loadDataSet():#打開文本文件並逐行讀取 dataMat = []; labelMat = [] fr = open(C:/Users/HZF/Desktop/machinelearninginaction/Ch05/testSet.txt) for line in fr.readlines(): lineArr = line.strip().split() dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])]) labelMat.append(int(lineArr[2])) return dataMat,labelMatdef sigmoid(inX):#sigmoid函數 return 1.0/(1+exp(-inX))def gradAscent(dataMatIn, classLabels):#梯度上升函數,dataMatIn 為特徵列 dataMatrix = mat(dataMatIn) #convert to NumPy matrix,X0假定為1.0,x1,x2為testSet.txt的前兩列數據 labelMat = mat(classLabels).transpose() #convert to NumPy matrix,將類標籤的矩陣行向量轉置成列向量 m,n = shape(dataMatrix)#計算矩陣大小 alpha = 0.001 maxCycles = 500#maxCycles是迭代次數 weights = ones((n,1)) for k in range(maxCycles): #heavy on matrix operations h = sigmoid(dataMatrix*weights) #matrix mult,計算了m*n次,因為計算量大,所以若應用在真實數據時,需要對該方法改進 error = (labelMat - h) #vector subtraction weights = weights + alpha * dataMatrix.transpose()* error #matrix mult,梯度上升演算法推導 return weightsdef plotBestFit(weights):#畫出數據集和logistic回歸最佳擬合直線的函數,此處的weights=weights(調用函數梯度上升里的weights).getA(), import matplotlib.pyplot as plt 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 = arange(-3.0, 3.0, 0.1) y = (-weights[0]-weights[1]*x)/weights[2]#最佳擬合直線,y=0,因為0是兩個分類0/1的分界處 ax.plot(x, y) plt.xlabel(X1); plt.ylabel(X2); plt.show()#畫出x1與x2特徵數據散點圖的分界線,x0默認是1.0 #梯度上升演算法的改進演算法——隨機梯度上升演算法(一次僅用一個樣本點更新回歸係數,減少計算複雜度)def stocGradAscent0(dataMatrix, classLabels):#隨機梯度上升演算法,該演算法是一個在線學習演算法。 m,n = shape(dataMatrix) alpha = 0.01 weights = ones(n) #initialize to all ones maxCycles = 200 for k in range(maxCycles):#此行為自己實驗添加代碼,經實驗,隨機梯度上升演算法迭代了200次後效果才可與梯度上升演算法效果相近且都比較好 for i in range(m): h = sigmoid(sum(dataMatrix[i]*weights))#h為具體值 error = classLabels[i] - h#error為具體值 weights = weights + alpha * error * dataMatrix[i] return weightsdef classifyVector(inX, weights):#分類函數 prob = sigmoid(sum(inX*weights))#weights取自前面幾種最優化的weights,InX為測試集上的特徵向量 if prob > 0.5: return 1.0 else: return 0.0if __name__=="__main__": #dataMat,labelMat=loadDataSet() #weights=gradAscent(dataMat, labelMat) #print weights #wei=weights.getA() dataMat,labelMat=loadDataSet() dataArr = array(dataMat) #weights=gradAscent(dataMat, labelMat)#迭代500次 #plotBestFit(weights.getA()) weights=stocGradAscent0(array(dataMat), labelMat)#迭代200次,讀者可以不用迭代看看效果 plotBestFit(weights) classifyVector(inX, weights)

上篇就寫邏輯回歸演算法的基本理論、梯度上升,隨機梯度上升的代碼實現這麼多!

參考文獻:

1、機器學習-邏輯回歸理論簡介 - xietingcandice的專欄 - 博客頻道 - CSDN.NET

2、《機器學習》(書)


推薦閱讀:

插入排序
【CV-Semantic Segmentation】deeplabv3+:語義分割領域的新高峰
機器學慣用於金融市場預測難在哪?
演算法導論第二課——漸進分析

TAG:數據挖掘 | 演算法 | 機器學習 |