Logistic迴歸之梯度上升優化演算法(二)
阿新 • • 發佈:2018-11-11
Logistic迴歸之梯度上升優化演算法(二)
有了上一篇的知識儲備,這一篇部落格我們就開始Python3實戰
1、資料準備
資料集:資料集下載
資料集內容比較簡單,我們可以簡單理解為第一列X,第二列Y,第三列是分類標籤。根據標籤的不同,對這些資料點進行分類。
import matplotlib.pyplot as plt import numpy as np ''' 函式說明:載入資料 Parameters: None Returns: dataMat - 資料列表 labelMat - 標籤列表 ''' def loadDataSet(): dataMat = [] # 建立資料列表 labelMat = [] # 建立標籤列表 fr = open('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])) # 新增標籤 fr.close() # 關閉檔案 return dataMat, labelMat ''' 函式說明:繪製資料集 Parameters: None Returns: None ''' def plotDataSet(): dataMat, labelMat = loadDataSet() # 載入資料集 dataArr = np.array(dataMat) # 轉換成numpy的array陣列 n = np.shape(dataMat)[0] # 資料個數,即行數 xcord1 = [] ; ycord1 = [] # 正樣本 xcord2 = [] ; ycord2 = [] # 負樣本 for i in range(n): if int(labelMat[i]) == 1: #1為正樣本 xcord1.append(dataMat[i][1]) ycord1.append(dataMat[i][2]) # xcord1.append(dataArr[i, 1]);ycord1.append(dataArr[i, 2]) else: #0為負樣本 xcord2.append(dataMat[i][1]) ycord2.append(dataMat[i][2]) # xcord2.append(dataArr[i, 1]);ycord2.append(dataArr[i, 2]) fig = plt.figure() ax = fig.add_subplot(111) #新增subplot ax.scatter(xcord1,ycord1,s=20,c='red',marker = 's', alpha=.5,label ='1') #繪製正樣本 ax.scatter(xcord2,ycord2,s=20,c='green',marker = 's', alpha=.5,label ='0') #繪製正樣本 plt.title('DataSet') #繪製title plt.xlabel('x'); plt.ylabel('y') #繪製label plt.legend() plt.show() if __name__ == '__main__': plotDataSet()
執行結果如下:
2、訓練演算法:使用梯度上升找到最佳引數
程式碼如下:
import matplotlib.pyplot as plt import numpy as np ''' 函式說明:載入資料 Parameters: None Returns: dataMat - 資料列表 labelMat - 標籤列表 ''' def loadDataSet(): dataMat = [] # 建立資料列表 labelMat = [] # 建立標籤列表 fr = open('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])) # 新增標籤 fr.close() # 關閉檔案 return dataMat, labelMat ''' 函式說明:sigmodi函式 Paremeters: inX - 資料 Returns: sigmoid函式 ''' def sigmoid(inX): return 1.0/(1 + np.exp(-inX)) ''' 函式說明:梯度上升演算法 Parameters: dataMatIn - 資料集 classLables - 資料標籤 Returns: weights.getA() - 求得的權重陣列(最優引數) ''' def gradAscent(dataMatIn, classLables): dataMatrix = np.mat(dataMatIn) #轉換成numpy的mat # print(dataMatrix) labelMat = np.mat(classLables).transpose() #轉換成numpy的mat,並進行轉置 # print(labelMat) m, n =np.shape(dataMatrix)#返回dataMatrix的大小。m為行,n為列 alpha = 0.001 #移動補償,也就是學習速率,控制更新的幅度 maxCycles = 500 #最大迭代次數 weights = np.ones((n,1)) # print(weights) for k in range(maxCycles): h = sigmoid(dataMatrix *weights) #梯度上升向量公式 # print(h) #權重係數計算公式 error = labelMat - h weights = weights + alpha * dataMatrix.transpose()*error return weights.getA() #將矩陣轉換為陣列,返回權重陣列 if __name__ == '__main__': np.set_printoptions(suppress=True) dataMat,labelMat = loadDataSet() print(gradAscent(dataMat,labelMat))
其中在gradAscent()函式中的迴圈裡有一個訓練引數的計算公式,這邊我不做推導直接給出。推導網址
執行結果如圖所示:
到此我們已經求解出迴歸係數[w0,w1,w2]。通過求解出的引數,我們可以確定不同類別資料之間的分隔線,畫出決策邊界。
3、繪製決策邊界
程式碼如下:
import matplotlib.pyplot as plt import numpy as np ''' 函式說明:載入資料 Parameters: None Returns: dataMat - 資料列表 labelMat - 標籤列表 ''' def loadDataSet(): dataMat = [] # 建立資料列表 labelMat = [] # 建立標籤列表 fr = open('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])) # 新增標籤 fr.close() # 關閉檔案 return dataMat, labelMat ''' 函式說明:繪製資料集 Parameters: None Returns: None ''' def plotDataSet(weights): dataMat, labelMat = loadDataSet() # 載入資料集 dataArr = np.array(dataMat) # 轉換成numpy的array陣列 n = np.shape(dataMat)[0] # 資料個數,即行數 xcord1 = [] ; ycord1 = [] # 正樣本 xcord2 = [] ; ycord2 = [] # 負樣本 for i in range(n): if int(labelMat[i]) == 1: #1為正樣本 xcord1.append(dataMat[i][1]) ycord1.append(dataMat[i][2]) # xcord1.append(dataArr[i, 1]);ycord1.append(dataArr[i, 2]) else: #0為負樣本 xcord2.append(dataMat[i][1]) ycord2.append(dataMat[i][2]) # xcord2.append(dataArr[i, 1]);ycord2.append(dataArr[i, 2]) fig = plt.figure() ax = fig.add_subplot(111) #新增subplot ax.scatter(xcord1,ycord1,s=20,c='red',marker = 's', alpha=.5,label ='1') #繪製正樣本 ax.scatter(xcord2,ycord2,s=20,c='green',marker = 's', alpha=.5,label ='0') #繪製正樣本 x = np.arange(-3.0,3.0,0.1) y = (-weights[0] - weights[1] * x) / weights[2] ax.plot(x,y) plt.title('DataSet') #繪製title plt.xlabel('x'); plt.ylabel('y') #繪製label plt.legend() plt.show() ''' 函式說明:sigmodi函式 Paremeters: inX - 資料 Returns: sigmoid函式 ''' def sigmoid(inX): return 1.0/(1 + np.exp(-inX)) ''' 函式說明:梯度上升演算法 Parameters: dataMatIn - 資料集 classLables - 資料標籤 Returns: weights.getA() - 求得的權重陣列(最優引數) ''' def gradAscent(dataMatIn, classLables): dataMatrix = np.mat(dataMatIn) #轉換成numpy的mat # print(dataMatrix) labelMat = np.mat(classLables).transpose() #轉換成numpy的mat,並進行轉置 # print(labelMat) m, n =np.shape(dataMatrix)#返回dataMatrix的大小。m為行,n為列 alpha = 0.001 #移動補償,也就是學習速率,控制更新的幅度 maxCycles = 500 #最大迭代次數 weights = np.ones((n,1)) # print(weights) for k in range(maxCycles): h = sigmoid(dataMatrix *weights) #梯度上升向量公式 # print(h) error = labelMat - h weights = weights + alpha * dataMatrix.transpose()*error return weights.getA() #將矩陣轉換為陣列,返回權重陣列 if __name__ == '__main__': np.set_printoptions(suppress=True) dataMat,labelMat = loadDataSet() weights = gradAscent(dataMat,labelMat) plotDataSet(weights)
其中繪製的分隔線設定了sigmoid函式為0,回憶上一篇內容,0是兩個分類的分解出,因此我們設定,然後接觸X2和X1的關係式(及分割線的方程,注意X0=1)。
執行結果如下:
從分類結果可以看出,還有幾個點是錯的。但是這個方法徐良大量的計算(300次乘法),在下一篇文章會對演算法稍作改進。
4、總結
Logistic迴歸的一般過程:
- 收集資料:採用任一方法收集資料
- 準備資料:需要距離計算,因此要求資料型別為數值型
- 分析資料:採用任意方法對資料進行分析
- 訓練演算法:大部分時間用於訓練,為了找到最佳的分類迴歸洗漱
- 測試演算法:訓練步驟完成,分類將會很快。
參考文獻:
- 《機器學習實戰》第五章內容
- Jack Cui部落格:http://cuijiahua.com/blog/2017/11/ml_6_logistic_1.html