參考《機器學習實戰》
利用Logistic回歸進行分類的主要思想:
根據現有數據對分類邊界線建立回歸公式,以此進行分類。
Sigmoid函數圖:
Sigmoid函數的作用:
將所有特征都乘上一個回歸系數,然后將所有結果值相加,將這個總和代入Sigmoid函數中,進而得到一個0~1之間的數值。任何大于0.5的數據被分1類,小于0.5分入0類。
綜上,Sigmoid的輸入可以記為z:
所以向量w即是我們要通過最優化方法找的系數。
w向量的求解:
1)、梯度上升法(思想:沿函數梯度方向找函數最大值)
梯度上升法偽代碼:
更新w系數的細節實現代碼:
要注意的是,作者在這里dataMatrix的特征矢量維度比實際特征矢量多了一維。作者使用的數據是二維[x1,x2],而程序中增加了一維[x0=1,x1,x2].奇怪的是x0加在了最前面的位置,而不是最后的位置。此外,上圖中畫紅線處的公式作者未給出由來,網上搜索了下,找到一篇博文,寫得還不錯。這里帖上點簡要概述:
具體過程如下:(參考:http://blog.csdn.net/yangliuy/article/details/18504921?reload)
參數概率方程:
其中x為訓練特征,y為x對應的類,θ為待估計參數
利用上式中y只取0或1的特點,剛好可以表示為:
似然函數:(這里就是Logistic Regression的目標函數,原書中并未指明,所以如果不網上找logistic的資料區先前學過機器學習,很無法理解書中的做法的)
對數似然函數:
所以極大似然估計:
從而得到梯度上升法的遞歸公式:
這里也就是上面的圖中,我畫紅線處公式的由來了。
這里再上傳下自己寫的代碼(未優化的logistic算法),代碼中的數據來源仍是《機器學習實戰》一書提供的數據:
#-*- coding:cp936 -*-import numpy as npimport matplotlib.pyplot as pltclass Log_REG(): def __init__(self): self._closed=False def loadData(self, dataFile='testSet.txt'): f_file = open(dataFile) lines = f_file.readlines() line_data = lines[0].strip().split() self.num_feature = len(line_data) - 1 self.xData = np.zeros((len(lines), self.num_feature + 1)) self.label = np.zeros((len(lines), 1)) self.num_label = len(lines) line_cnt = 0 for iLine in lines: line_data = iLine.strip().split() for i in range(self.num_feature): self.xData[line_cnt][i] = float(line_data[i]) self.xData[line_cnt][self.num_feature] = 1 self.label[line_cnt] = float(line_data[-1]) line_cnt+=1 def _sigmoid(self, z): return 1.0 / (1 + np.exp(-z)) def gradAscendClass(self): maxIter = 500 self.omiga = np.ones((1, self.num_feature+1)) xDataMat = np.matrix(self.xData) alpha = 0.01 self.omiga_record=[] for i in range(maxIter): h = self._sigmoid(self.omiga * xDataMat.transpose()) # 矩陣乘 error = self.label - h.transpose() self.omiga = self.omiga + alpha * (xDataMat.transpose()*error).transpose() self.omiga_record.append(self.omiga) if np.sum(np.abs(error)) < self.num_label * 0.05: PRint "error very low",i break def stochasticGradAscend(self): pass# maxIter = 150# self.omiga = np.ones((1,self.num_feature+1))# for def plotResult(self): self._close() if self.num_feature != 2: print "Only plot data with 2 features!" return label0x = [] label0y = [] label1x = [] label1y = [] for i in range(self.num_label): if int(self.label[i]) == 1: label1x.append(self.xData[i][0]) label1y.append(self.xData[i][1]) else: label0x.append(self.xData[i][0]) label0y.append(self.xData[i][1]) fig = plt.figure() ax = fig.add_subplot(111) ax.scatter(label0x, label0y, c='b',marker='o') ax.scatter(label1x, label1y, c='r',marker='s') minx = min(min(label0x),min(label1x)) maxx = max(max(label0x),max(label1x)) wx = np.arange(minx,maxx,0.1) wy = (-self.omiga[0,2]-self.omiga[0,0]*wx)/self.omiga[0,1] ax.plot(wx,wy) def plotIteration(self): self._close() iterTimes = len(self.omiga_record) w0=[i[0][0,0] for i in self.omiga_record] w1=[i[0][0,1] for i in self.omiga_record] w2=[i[0][0,2] for i in self.omiga_record] fig = plt.figure() ax1 = fig.add_subplot(3,1,1) ax1.plot(range(iterTimes),w0,c='b')#,marker='*') plt.xlabel('w0') ax2 = fig.add_subplot(3,1,2) ax2.plot(range(iterTimes),w1,c='r')#,marker='s') plt.xlabel('w1') ax3 = fig.add_subplot(3,1,3) ax3.plot(range(iterTimes),w2,c='g')#,marker='o') plt.xlabel('w2') def show(self): plt.show() def _close(self): pass if __name__ =='__main__': testclass = Log_REG() testclass.loadData() testclass.gradAscendClass() testclass.plotResult() testclass.plotIteration() testclass.show()
分類結果
分類參數收斂結果
梯度上升(或下降)算法的改進:
當數據量很大時,上述梯度上升算法每次迭代都要對所有數據進行處理,會造成計算量異常龐大。解決的方法是引入隨機梯度的思想。
隨機梯度下降的基本原理是:不直接計算梯度的精確值,而是用梯度的無偏估計g(w)來代替梯度:
實際操作時,隨機地選取單個數據而非整個數據集參與迭代,詳細的原理推導可參見:http://www.52ml.net/2024.html
改進的隨機梯度上升法:
def stochasticGradAscend2(self): maxIter = 150 self.omiga = np.ones((1,self.num_feature+1)) self.omiga_record=[] for j in range(maxIter): randRange = range(self.xData.shape[0]) for i in range(self.xData.shape[0]): alpha = 4/(1.0+i+j)+0.01 randIndex = int(random.uniform(0,len(randRange)-1)) index = randRange[randIndex] h = self._sigmoid(np.matrix(self.omiga)[0]*np.matrix(self.xData[index,:]).transpose()) error = self.label[index]-h self.omiga = self.omiga+alpha*error*self.xData[index,:] self.omiga_record.append(np.matrix(self.omiga)) del(randRange[randIndex])
從上圖可以看出,改進后的隨機梯度算法收斂很快,上圖只對所有數據做150次迭代。
參考文獻:
http://blog.csdn.net/yangliuy/article/details/18504921?reload
隨機梯度:http://www.52ml.net/2024.html
新聞熱點
疑難解答