Python實現鳶尾花數據集分類問題——使用LogisticRegression分類器


. 邏輯回歸   

邏輯回歸(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

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】

1、Logistic回歸多分類之鳶尾花

2、https://blog.csdn.net/BTUJACK/article/details/79761461

3、https://blog.csdn.net/eastmount/article/details/77920470


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM