. 邏輯回歸
邏輯回歸(Logistic Regression)是用於處理因變量為分類變量的回歸問題,常見的是二分類或二項分布問題,也可以處理多分類問題,它實際上是屬於一種分類方法。
概率p與因變量往往是非線性的,為了解決該類問題,我們引入了logit變換,使得logit(p)與自變量之 間存在線性相關的關系,邏輯回歸模型定義如下:
1 #Sigmoid曲線: 2 import matplotlib.pyplot as plt 3 import numpy as np 4 5 def Sigmoid(x): 6 return 1.0 / (1.0 + np.exp(-x)) 7 8 x= np.arange(-10, 10, 0.1) 9 h = Sigmoid(x) #Sigmoid函數 10 plt.plot(x, h) 11 plt.axvline(0.0, color='k') #坐標軸上加一條豎直的線(0位置) 12 plt.axhspan(0.0, 1.0, facecolor='1.0', alpha=1.0, ls='dotted') 13 plt.axhline(y=0.5, ls='dotted', color='k') #在y=0.5的地方加上黑色虛線 14 plt.yticks([0.0, 0.5, 1.0]) #y軸標度 15 plt.ylim(-0.1, 1.1) #y軸范圍 16 plt.show()
二、鳶尾花分類問題的思路分析
(1)選擇使用LogisticRegression分類器,由於Iris數據集涉及到3個目標分類問題,而邏輯回歸模型是二分類模型,用於二分類問題。因此,可以將其推廣為多項邏輯回歸模型(multi-nominal logistic regression model),用於多分類。
(2)根據多項邏輯回歸模型,編寫代碼,輸入數據集,訓練得到相應參數並作出預測。
(3)對預測出的數據的分類結果和原始數據進行可視化展示。
三、多項邏輯回歸模型的原理及推導過程
假設類別 Y 的取值集合為 {1,2,...,K},那么多項邏輯回歸模型是:
其似然函數為:

其中,
為模型在輸入樣本
時,將其判為類別k 的概率;
起到指示函數的作用,當K 等於樣本
的標簽類別時為1,其余均為0。
對似然函數取對數,然后取負,得到
(簡記為:
),最終要訓練出的模型參數要使得
的值取得最小。
的推導過程如下:

考慮到過擬合的發生,對
加上一個正則項:
則
可以寫成:

對
關於
求梯度,得到:

在上式中,第一項
可以看成是類別k的后驗期望值,第二項
視為類別k 的先驗期望值,第三項是正則化項,用於緩解過擬合。
接下來使用梯度下降法對參數
進行修正更新即可:

四、實現步驟
4.1 讀入數據文件
這里需要注意的是,在datas中取前兩列作為特征(為了后期的可視化畫圖更加直觀,故只取前兩列特征值向量進行訓練)
1 attributes=['SepalLength','SepalWidth','PetalLength','PetalWidth'] #鳶尾花的四個屬性名 2 3 datas=[] 4 labels=[] 5 6 # with open('IRIS_dataset.txt','r') as f: 7 # for line in f: 8 # linedata=line.split(',') 9 # datas.append(linedata[:-1]) #前4列是4個屬性的值 10 # labels.append(linedata[-1].replace('\n','')) #最后一列是類別 11 12 #讀入數據集的數據: 13 data_file=open('IRIS_dataset.txt','r') 14 for line in data_file.readlines(): 15 # print(line) 16 linedata = line.split(',') 17 # datas.append(linedata[:-1]) # 前4列是4個屬性的值(誤判的樣本的個數為:7 18 datas.append(linedata[:-3]) # 前2列是2個屬性的值(誤判的樣本的個數為:30 19 labels.append(linedata[-1].replace('\n', '')) # 最后一列是類別 20 21 datas=np.array(datas) 22 datas=datas.astype(float) #將二維的字符串數組轉換成浮點數數組 23 labels=np.array(labels) 24 kinds=list(set(labels)) #3個類別的名字列表
4.2 編寫代碼實現LogisticRegression算法
1 # LogisticRegression算法,訓練數據,傳入參數為數據集(包括特征數據及標簽數據),結果返回訓練得到的參數 W 2 def LogRegressionAlgorithm(datas,labels): 3 kinds = list(set(labels)) # 3個類別的名字列表 4 means=datas.mean(axis=0) #各個屬性的均值 5 stds=datas.std(axis=0) #各個屬性的標准差 6 N,M= datas.shape[0],datas.shape[1]+1 #N是樣本數,M是參數向量的維 7 K=3 #k=3是類別數 8 9 data=np.ones((N,M)) 10 data[:,1:]=(datas-means)/stds #對原始數據進行標准差歸一化 11 12 W=np.zeros((K-1,M)) #存儲參數矩陣 13 priorEs=np.array([1.0/N*np.sum(data[labels==kinds[i]],axis=0) for i in range(K-1)]) #各個屬性的先驗期望值 14 15 liklist=[] 16 for it in range(1000): 17 lik=0 #當前的對數似然函數值 18 for k in range(K-1): #似然函數值的第一部分 19 lik -= np.sum(np.dot(W[k],data[labels==kinds[k]].transpose())) 20 lik +=1.0/N *np.sum(np.log(np.sum(np.exp(np.dot(W,data.transpose())),axis=0)+1)) #似然函數的第二部分 21 liklist.append(lik) 22 23 wx=np.exp(np.dot(W,data.transpose())) 24 probs=np.divide(wx,1+np.sum(wx,axis=0).transpose()) # K-1 *N的矩陣 25 posteriorEs=1.0/N*np.dot(probs,data) #各個屬性的后驗期望值 26 gradients=posteriorEs - priorEs +1.0/100 *W #梯度,最后一項是高斯項,防止過擬合 27 W -= gradients #對參數進行修正 28 print("輸出W為:",W) 29 return W
4.3 編寫predict_fun()預測函數
根據訓練得到的參數W和數據集,進行預測。輸入參數為數據集和由LogisticRegression算法得到的參數W,返回值為預測的值。
1 #根據訓練得到的參數W和數據集,進行預測。輸入參數為數據集和由LogisticRegression算法得到的參數W,返回值為預測的值 2 def predict_fun(datas,W): 3 N, M = datas.shape[0], datas.shape[1] + 1 # N是樣本數,M是參數向量的維 4 K = 3 # k=3是類別數 5 data = np.ones((N, M)) 6 means = datas.mean(axis=0) # 各個屬性的均值 7 stds = datas.std(axis=0) # 各個屬性的標准差 8 data[:, 1:] = (datas - means) / stds # 對原始數據進行標准差歸一化 9 10 # probM每行三個元素,分別表示data中對應樣本被判給三個類別的概率 11 probM = np.ones((N, K)) 12 print("data.shape:", data.shape) 13 print("datas.shape:", datas.shape) 14 print("W.shape:", W.shape) 15 print("probM.shape:", probM.shape) 16 probM[:, :-1] = np.exp(np.dot(data, W.transpose())) 17 probM /= np.array([np.sum(probM, axis=1)]).transpose() # 得到概率 18 19 predict = np.argmax(probM, axis=1).astype(int) # 取最大概率對應的類別 20 print("輸出predict為:", predict) 21 return predict
4.4 繪制圖像
(1)確定坐標軸范圍,x,y軸分別表示兩個特征
1 # 1.確定坐標軸范圍,x,y軸分別表示兩個特征 2 x1_min, x1_max = datas[:, 0].min(), datas[:, 0].max() # 第0列的范圍 3 x2_min, x2_max = datas[:, 1].min(), datas[:, 1].max() # 第1列的范圍 4 x1, x2 = np.mgrid[x1_min:x1_max:150j, x2_min:x2_max:150j] # 生成網格采樣點,橫軸為屬性x1,縱軸為屬性x2 5 grid_test = np.stack((x1.flat, x2.flat), axis=1) # 測試點 6 #.flat 函數將兩個矩陣都變成兩個一維數組,調用stack函數組合成一個二維數組 7 print("grid_test = \n", grid_test) 8 9 grid_hat = predict_fun(grid_test,W) # 預測分類值 10 grid_hat = grid_hat.reshape(x1.shape) # 使之與輸入的形狀相同 11 #grid_hat本來是一唯的,調用reshape()函數修改形狀,將其grid_hat轉換為兩個特征(長度和寬度) 12 print("grid_hat = \n", grid_hat) 13 print("grid_hat.shape: = \n", grid_hat.shape) # (150, 150)
(2)指定默認字體
1 # 2.指定默認字體 2 mpl.rcParams['font.sans-serif'] = [u'SimHei'] 3 mpl.rcParams['axes.unicode_minus'] = False
(3)繪制圖像
1 # 3.繪制圖像 2 cm_light = mpl.colors.ListedColormap(['#A0FFA0', '#FFA0A0', '#A0A0FF']) 3 cm_dark = mpl.colors.ListedColormap(['g', 'r', 'b']) 4 5 alpha = 0.5 6 7 plt.pcolormesh(x1, x2, grid_hat, cmap=plt.cm.Paired) # 預測值的顯示 8 # 調用pcolormesh()函數將x1、x2兩個網格矩陣和對應的預測結果grid_hat繪制在圖片上 9 # 可以發現輸出為三個顏色區塊,分布表示分類的三類區域。cmap=plt.cm.Paired/cmap=cm_light表示繪圖樣式選擇Paired主題 10 # plt.scatter(datas[:, 0], datas[:, 1], c=labels, edgecolors='k', s=50, cmap=cm_dark) # 樣本 11 plt.plot(datas[:, 0], datas[:, 1], 'o', alpha=alpha, color='blue', markeredgecolor='k') 12 ##繪制散點圖 13 plt.scatter(datas[:, 0], datas[:, 1], s=120, facecolors='none', zorder=10) # 圈中測試集樣本 14 plt.xlabel(u'花萼長度', fontsize=13) #X軸標簽 15 plt.ylabel(u'花萼寬度', fontsize=13) #Y軸標簽 16 plt.xlim(x1_min, x1_max) # x 軸范圍 17 plt.ylim(x2_min, x2_max) # y 軸范圍 18 plt.title(u'鳶尾花LogisticRegression二特征分類', fontsize=15) 19 # plt.legend(loc=2) # 左上角繪制圖標 20 # plt.grid() 21 plt.show()
五、 實驗結果
(1)運行程序輸出的參數:
使用二個特征:
| 輸出W為: [[-0.41462351 1.26263398 0.26536423] [-1.07260354 -2.44478672 1.96448439]] 輸出predict為: [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 0 0 0 2 0 2 0 2 0 2 2 2 2 2 2 0 2 2 2 2 2 2 2 2 0 0 0 0 2 2 2 2 2 2 2 0 0 2 2 2 2 2 2 2 2 2 2 0 2 2 0 2 0 0 0 0 2 0 0 0 0 0 0 2 2 0 0 0 0 2 0 2 0 0 0 0 2 2 0 0 0 0 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 0 0 2] 誤判的樣本的個數為:28 |
使用四個特征:
| 輸出W為: [[-0.09363942 -1.41359443 1.17376524 -2.3116611 -2.20018596] [ 1.44071982 -0.05960463 -0.31391519 -0.87589944 -1.83255315]] 輸出predict為: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 2 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 1 2 2 2 2 2 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2] 誤判的樣本的個數為:8 |
(2)數據可視化結果如下:

六、結果分析與比較
由以上實驗結果可以看出,使用了二特征的誤判的樣本個數為28(樣本總數為150),而使用了四個特征的訓練結果,誤判的樣本個數為8,在一定程度上可以解釋使用的特征數過少的話,會導致欠擬合的情況發生。
為了后期的可視化畫圖更加直觀,故只取前兩列特征值向量進行訓練。結果展示如上圖所示。
完整實現代碼詳見:【GitHub 】
【Reference】
