大家好,又見面了,我是你們的朋友全棧君。
. 邏輯回歸
邏輯回歸(Logistic Regression)是用於處理因變量為分類變量的回歸問題,常見的是二分類或二項分布問題,也可以處理多分類問題,它實際上是屬於一種分類方法。
概率p與因變量往往是非線性的,為了解決該類問題,我們引入了logit變換,使得logit(p)與自變量之 間存在線性相關的關系,邏輯回歸模型定義如下:
1 #Sigmoid曲線:
2 importmatplotlib.pyplot as plt3 importnumpy as np4
5 defSigmoid(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 indata_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 defLogRegressionAlgorithm(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 defpredict_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】
發布者:全棧程序員棧長,轉載請注明出處:https://javaforall.cn/128853.html原文鏈接:https://javaforall.cn