1. 程式人生 > >利用批量梯度下降和正規方程求解線性迴歸引數(Python實現)

利用批量梯度下降和正規方程求解線性迴歸引數(Python實現)

說明:本文使用的工具為Python3+Jupyter Notebook。

利用批量梯度下降

先匯入要用到的各種包:

%matplotlib notebook
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

構造並檢視資料:

# 構造資料集:
data = {'Ones':[1,1,1,1,1,1,1,1,1],'x_train':[3,5,6,8,12,13,15,20,23],
'y_train':[8,15,23,28,37,49,55,64,85]}
train_data = pd.DataFrame(data)

# 檢視具體資料(train_data中的'Ones'列是為了便於矩陣計算而構造的輔助列)
train_data

train_data資料結構如下圖所示:

畫出資料的散點圖:

# 繪製資料的散點圖:

fig,axes = plt.subplots()
train_data.plot(kind='scatter',x='x_train',y='y_train',ax=axes)
fig.savefig('p1.png')

上述程式碼繪製的散點圖如下所示:

在進行梯度下降前對資料做預處理:

cols = train_data.shape[1]
X = train_data.iloc[:,0:cols-1] # X是train_data中不包括最後一列的所有行
y = train_data.iloc[:,cols-1:cols] # y即最後一列

# 將X和y轉化成矩陣形式:
X = np.matrix(X.values)
y = np.matrix(y.values)
theta = np.matrix(np.array([0,0])) # 初始化theta引數

運用批量梯度下降演算法求解線性迴歸引數:

# 定義代價函式:
def computeCost(X,y,theta):
    inner = np.power(((X*theta.T)-y),2)
    return np.sum(inner)/(2 * len(X))

# 定義梯度下降函式:
def batch_gradient_descent(X,y,theta,alpha,iters):
    temp = np.matrix(np.zeros(theta.shape))
    parameters = int(theta.shape[1])
    cost = np.zeros(iters)
    
    for i in range(iters):
        error = (X * theta.T) - y
        
        for j in range(parameters):
            term = np.multiply(error, X[:,j])
            temp[0,j] = theta[0,j] - ((alpha / len(X)) * np.sum(term))
            
        theta = temp
        cost[i] = computeCost(X, y, theta)
        
    return theta, cost  # cost指根據每次迭代更新後的theta引數計算出的代價函式的具體值

# 初始化學習率和迭代次數:
alpha = 0.001
iters = 100

# 呼叫梯度下降函式計算引數theta的值:
g, cost = batch_gradient_descent(X, y, theta, alpha, iters)

# print(g)    theta引數的值為[[0.18629876 3.48668984]]

# 根據已計算出的theat引數對原始資料進行線性擬合:
x = np.linspace(train_data.x_train.min(), train_data.x_train.max(), 100)
f = g[0, 0] + (g[0, 1] * x)

fig, axes = plt.subplots()
axes.plot(x, f, 'r', label='Prediction')  # 線性擬合圖
axes.scatter(train_data.x_train, train_data.y_train, label='Traning Data') # 原始資料散點圖
axes.legend(loc='best')
axes.set_xlabel('x')
axes.set_ylabel('y')
axes.set_title('Predicted x vs. y')
fig.savefig('p2.png')

上述程式碼繪製的圖如下所示:

此外,我們還可以繪製代價函式的具體值與迭代次數之間的關係影象:

fig, axes = plt.subplots()
axes.plot(np.arange(iters), cost, 'r')
axes.set_xlabel('Iterations')
axes.set_ylabel('Cost')
axes.set_title('Error vs. Training Epoch')
fig.savefig('p3.png')

具體影象如下所示:

從上圖中,我們可以看到當迭代次數為20時,代價函式的值就已經接近收斂了。前面利用梯度下降演算法求解線性迴歸引數,我們設定的最大迭代次數為100,此時計算出的theta引數值為:matrix([[0.18629876, 3.48668984]])

利用正規方程

# 定義正規方程函式:

def normalEqn(X, y):
    theta = np.linalg.inv([email protected])@[email protected]  # [email protected]等價於X.T.dot(X)
    return theta

# 呼叫正規方程函式計算線性迴歸引數:

final_theta=normalEqn(X, y) 
# final_theta的具體值為:
# matrix([[-1.60933806],[ 3.60460993]])

利用正規方程求出的線性迴歸引數可以說是精確的解。由前文可知,當最大迭代次數設為100次時,批量梯度下降演算法求出的線性迴歸引數值為matrix([[0.18629876, 3.48668984]])。假如想要讓批量梯度下降演算法求出的引數值更加接近正規方程的解,可以增加批量梯度下降演算法中的最大迭代次數。經測試得到:當把批量梯度下降演算法中的最大迭代次數設為50000時,求得的引數值為matrix([[-1.60932272, 3.60460892]]),可以看到已經與正規方程的解特別接近。

PS1:關於批量梯度下降和正規方程詳細的理論推導,可以參考:https://blog.csdn.net/qq_41080850/article/details/85292769

PS2:本文為博主原創文章,轉載請註明出處。