之前寫了一篇邏輯回歸的理論知識,寫得還算詳盡,包含了公式的詳細推導過程。這篇文章将結合之前的理論推導,通過Python代碼實作邏輯回歸算法,并用來預測鸢尾花種類。由于這篇文章是對照着之前的理論文章進行講解的,是以最好先看前一篇理論文章,再看這篇實踐文章。理論的文章連結為:https://blog.csdn.net/opp003/article/details/8478449
上一篇的文章目标是得到權重矩陣的計算公式,也就是上篇文章中的最後一個公式,式(33)。有了權重矩陣的計算公式,就可以計算出權重矩陣,這樣,結合假設函數,也就是sigmoid函數,就可以進行預測了。下面我們來看代碼。
1.sigmoid函數
sigmoid函數就是我們之前提到的假設函數h(x),也就是前一篇文章中的式(26)。
它的實作代碼如下:
def sigmoid(z):
return 1 / (1 + np.exp(-z))
2.梯度下降法
梯度下降法的理論知識已在上一篇文章中詳細講解了,這裡不再贅述。我們來看核心部分,即權重矩陣的代碼如何實作。權重矩陣的計算公式為上篇文章中的式(33)。
這個核心計算公式的代碼實作如下:
weights = weights - alpha * X.transpose() * (h - y)
其中weights就是我們要計算的權重矩陣,也就是數學公式裡的
。alpha為學習率,也就是公式裡的
。而代碼中的
,也就是公式中的誤差計算部分。
梯度下降法的詳細代碼如下:
def gradDescent(X,y):
m,n = X.shape
#将資料矩陣化
X = np.mat(X)
y = np.mat(y)
y = y.transpose()
#學習率設為0.01
alpha = 0.01
#進行500次訓練,疊代更新權重矩陣
n_estimate = 500
#初始化一個值都為1的權重矩陣
weights = np.ones((n,1))
for k in range(n_estimate):
h = sigmoid(X * weights)
error = h - y
weights = weights - alpha * X.transpose() * error
return weights
3.完整代碼
# -*- coding: utf-8 -*-
# @Time : 2018/12/10 下午6:03
# @Author : yangchen
# @FileName: HandwritingLR.py
# @Software: PyCharm
# @Blog :https://blog.csdn.net/opp003/article
import pandas as pd
import numpy as np
'''
假設函數
h(z) = 1 / (1 + e(-z))
z = theta * x
'''
def sigmoid(z):
return 1 / (1 + np.exp(-z))
'''
梯度下降
X:訓練集
y:訓練集标簽
alpha:梯度下降學習率
n_estimate:訓練次數
'''
def gradDescent(X,y):
m,n = X.shape
#将資料矩陣化
X = np.mat(X)
y = np.mat(y)
y = y.transpose()
#學習率設為0.01
alpha = 0.01
#進行500次訓練,疊代更新權重矩陣
n_estimate = 500
#初始化一個值都為1的權重矩陣
weights = np.ones((n,1))
for k in range(n_estimate):
h = sigmoid(X * weights)
error = h - y
weights = weights - alpha * X.transpose() * error
return weights
'''
加載資料
'''
def loadData():
df = pd.read_csv('iris.csv')
#資料亂序
df = df.sample(frac=1)
#按照8:2的比例分隔資料,分别用來訓練和測試
train_data = df[0:round(len(df)*0.8)]
test_data = df[round(len(df)*0.8):]
y_train = train_data['LABEL']
X_train = train_data.drop('LABEL',axis=1)
y_test = test_data['LABEL']
X_test = test_data.drop('LABEL', axis=1)
#矩陣化測試集
X_test = np.mat(X_test)
#數組化測試集的label
y_test = y_test.tolist()
return X_train,y_train,X_test,y_test
if __name__ == '__main__':
X_train, y_train, X_test, y_test = loadData()
weights = gradDescent(X_train, y_train)
#别忘了要乘上sigmoid函數
X_predict = sigmoid(X_test * weights)
#将資料從二維矩陣轉為數組
X_predict = X_predict.tolist()
for i in range(len(X_predict)):
x = X_predict[i]
y = y_test[i]
prob_of_one = x[0]
if prob_of_one >= 0.5:
print('predict: 1 , ' + 'actual: ' + str(y))
else:
print('predict: 0 , ' + 'actual: ' + str(y))
最後的main函數裡有幾行代碼要解釋下:
X_predict = sigmoid(X_test * weights)
這裡,X_test * weights 計算的是線性部分,即理論篇中的
,而假設函數是
,
是以計算完 X_test * weights 後,要将它放入 sigmoid 函數,進而得到一個結果,這個結果是預測為正樣本,即 label 為 1 的機率,别忘了,邏輯回歸最原始的結果是機率。我們通過0.5來劃分它是1還是0。
還要說明的一點是,我們是通過二維矩陣來計算的。是以得到的結果雖然是一個樣本一個對應值,但結果值也是存放在二維矩陣中。是以需要通過 numpy 的 tolist 方法先轉為二維數組,再通過取 [0] 來得到值。
最後的運作結果如下:
predict: 1 , actual: 1
predict: 0 , actual: 0
predict: 0 , actual: 0
predict: 0 , actual: 0
predict: 0 , actual: 0
predict: 1 , actual: 1
predict: 1 , actual: 1
predict: 0 , actual: 0
predict: 0 , actual: 0
predict: 0 , actual: 0
predict: 1 , actual: 1
predict: 1 , actual: 1
predict: 0 , actual: 0
predict: 1 , actual: 1
predict: 1 , actual: 0
predict: 1 , actual: 1
predict: 1 , actual: 1
predict: 1 , actual: 1
predict: 1 , actual: 1
predict: 0 , actual: 0
我們看預測結果和真實結果的對比,20條測試集裡,隻有一條預測錯了。準确率達到了95%。
文中用到的資料集是鸢尾花的部分資料集,1和0分别代表兩種不同的花種。資料集如下:
col_1,col_2,col_3,col_4,LABEL
7,3.2,4.7,1.4,1
6.4,3.2,4.5,1.5,1
6.9,3.1,4.9,1.5,1
5.5,2.3,4,1.3,1
6.5,2.8,4.6,1.5,1
5.7,2.8,4.5,1.3,1
6.3,3.3,4.7,1.6,1
4.9,2.4,3.3,1,1
6.6,2.9,4.6,1.3,1
5.2,2.7,3.9,1.4,1
5,2,3.5,1,1
5.9,3,4.2,1.5,1
6,2.2,4,1,1
6.1,2.9,4.7,1.4,1
5.6,2.9,3.6,1.3,1
6.7,3.1,4.4,1.4,1
5.6,3,4.5,1.5,1
5.8,2.7,4.1,1,1
6.2,2.2,4.5,1.5,1
5.6,2.5,3.9,1.1,1
5.9,3.2,4.8,1.8,1
6.1,2.8,4,1.3,1
6.3,2.5,4.9,1.5,1
6.1,2.8,4.7,1.2,1
6.4,2.9,4.3,1.3,1
6.6,3,4.4,1.4,1
6.8,2.8,4.8,1.4,1
6.7,3,5,1.7,1
6,2.9,4.5,1.5,1
5.7,2.6,3.5,1,1
5.5,2.4,3.8,1.1,1
5.5,2.4,3.7,1,1
5.8,2.7,3.9,1.2,1
6,2.7,5.1,1.6,1
5.4,3,4.5,1.5,1
6,3.4,4.5,1.6,1
6.7,3.1,4.7,1.5,1
6.3,2.3,4.4,1.3,1
5.6,3,4.1,1.3,1
5.5,2.5,4,1.3,1
5.5,2.6,4.4,1.2,1
6.1,3,4.6,1.4,1
5.8,2.6,4,1.2,1
5,2.3,3.3,1,1
5.6,2.7,4.2,1.3,1
5.7,3,4.2,1.2,1
5.7,2.9,4.2,1.3,1
6.2,2.9,4.3,1.3,1
5.1,2.5,3,1.1,1
5.7,2.8,4.1,1.3,1
6.3,3.3,6,2.5,0
5.8,2.7,5.1,1.9,0
7.1,3,5.9,2.1,0
6.3,2.9,5.6,1.8,0
6.5,3,5.8,2.2,0
7.6,3,6.6,2.1,0
4.9,2.5,4.5,1.7,0
7.3,2.9,6.3,1.8,0
6.7,2.5,5.8,1.8,0
7.2,3.6,6.1,2.5,0
6.5,3.2,5.1,2,0
6.4,2.7,5.3,1.9,0
6.8,3,5.5,2.1,0
5.7,2.5,5,2,0
5.8,2.8,5.1,2.4,0
6.4,3.2,5.3,2.3,0
6.5,3,5.5,1.8,0
7.7,3.8,6.7,2.2,0
7.7,2.6,6.9,2.3,0
6,2.2,5,1.5,0
6.9,3.2,5.7,2.3,0
5.6,2.8,4.9,2,0
7.7,2.8,6.7,2,0
6.3,2.7,4.9,1.8,0
6.7,3.3,5.7,2.1,0
7.2,3.2,6,1.8,0
6.2,2.8,4.8,1.8,0
6.1,3,4.9,1.8,0
6.4,2.8,5.6,2.1,0
7.2,3,5.8,1.6,0
7.4,2.8,6.1,1.9,0
7.9,3.8,6.4,2,0
6.4,2.8,5.6,2.2,0
6.3,2.8,5.1,1.5,0
6.1,2.6,5.6,1.4,0
7.7,3,6.1,2.3,0
6.3,3.4,5.6,2.4,0
6.4,3.1,5.5,1.8,0
6,3,4.8,1.8,0
6.9,3.1,5.4,2.1,0
6.7,3.1,5.6,2.4,0
6.9,3.1,5.1,2.3,0
5.8,2.7,5.1,1.9,0
6.8,3.2,5.9,2.3,0
6.7,3.3,5.7,2.5,0
6.7,3,5.2,2.3,0
6.3,2.5,5,1.9,0
6.5,3,5.2,2,0
6.2,3.4,5.4,2.3,0
5.9,3,5.1,1.8,0