1. 程式人生 > >小批量梯度下降演算法的Python實現

小批量梯度下降演算法的Python實現

小批量梯度下降演算法的核心思想仍然是基於梯度,通過對目標函式中的引數不斷迭代更新,使得目標函式逐漸靠近最小值。它是批量梯度下降與隨機梯度下降的折中,有著訓練過程較快,同時又能保證得到較為精確的訓練結果。在一些情況下,小批量梯度下降比批量梯度下降和隨機梯度下降的速度都要快。

具體程式碼實現如下:

先匯入要用到的各種包:

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

讀入資料並檢視資料的相關資訊:

檢視data中前五條資料:

data = pd.read_excel('gongyeyuan.xlsx','Sheet2')
data.head()

檢視data的各描述統計量資訊:

data.describe()

繪製原始資料的散點圖:

fig,axes = plt.subplots()
data.plot(kind='scatter',x='Area',y='Price',marker='o',color='k',ax=axes)
axes.set(xlabel='Area',ylabel='Price',title='Price vs. Area')
fig.savefig('p1.png')

向data中新增一列便於矩陣計算的輔助列:

data.insert(0,'Ones',1)
data.head()

小批量梯度下降的實現:

# 定義資料特徵和標籤的提取函式:
def get_fea_lab(train_data):
    
    cols = train_data.shape[1]
    X = train_data.iloc[:,0:cols-1]       # X取data中不包括索引列的前兩列
    y = train_data.iloc[:,cols-1:cols]    # y取data中的最後一列
    
    X = np.matrix(X.values)
    y = np.matrix(y.values)
    
    return X,y


# 定義小批量樣本的代價函式:
def computeCost(train_data,theta,k,mb_size):
    
    X,y = get_fea_lab(train_data)
    X = X[k:k+mb_size]
    y = y[k:k+mb_size]
    inner = np.power(((X*theta.T)-y),2)
    term = np.sum(inner)/(2*mb_size)
    
    return term


#定義小批量梯度下降函式:
def mb_gradient_descent(train_data,theta,alpha,mb_size):
    
    X,y = get_fea_lab(train_data)
    temp = np.matrix(np.zeros(theta.shape))      # temp用於存放theta引數的值
    parameters = int(theta.shape[1])             # parameter用於存放theta引數的個數
    m = len(X)                                   # m用於存放資料集中的樣本個數
    cost = np.zeros(int(np.floor(m/mb_size)))    # cost用於存放代價函式
    st_posi = list(np.arange(0,m,mb_size))       # st_posi用於存放每次小批量迭代開始的位置
    new_st_posi = st_posi[:len(cost)]            # 去掉最後一次小批量迭代開始的位置
    k = 0
    
    for i in new_st_posi:
        
        cost[k] = computeCost(train_data,theta,i,mb_size)
        k = k + 1
        error = (X*theta.T) - y
        
        for j in range(parameters):
            
            t = np.multiply(error,X[:,j])
            term = t[i:i + mb_size]
            temp[0,j] = theta[0,j] - (alpha/mb_size)*(np.sum(term))
                            
        theta = temp
                            
    return theta, cost


# 初始化相關引數:
theta = np.matrix(np.array([0,0]))
alpha = 0.00001
mb_size = 50


# 呼叫隨機梯度下降函式來計算線性迴歸中的theat引數:
new_data = data.sample(frac=1)  # 打亂資料,沒有這一步也可以
g,cost = mb_gradient_descent(new_data,theta,alpha,mb_size)

# g的值為matrix([[0.02717606, 3.3047963 ]])

繪製代價函式的值與迭代次數的關係影象:

fig, axes = plt.subplots()
axes.plot(np.arange(len(cost)), cost, 'r')
axes.set_xlabel('iters')
axes.set_ylabel('cost')
axes.set_title('cost vs. iters')
fig.savefig('p2.png')

本文所用的資料集中一共有5106條資料。在小批量梯度下降演算法中,筆者採用的mini_batch_size(即演算法中的mb_size引數)為50。從上圖中我們可以看到在僅僅迭代了20次後,代價函式的值已經開始在某個值上下進行小範圍波動。經過大約100次迭代後,得到的theta引數值為matrix([[0.02717606, 3.3047963 ]])。而用正規方程求出的theta引數的精確值為matrix([[-2.34868067],[ 3.31348565]]),可以看出兩者差別在一定程度上是可以接受的。關於用正規方程求解線性迴歸引數可以參考:https://blog.csdn.net/qq_41080850/article/details/85292769https://blog.csdn.net/qq_41080850/article/details/85159645

根據前文計算出的theta引數值,繪製原始資料的線性擬合圖:

x = np.linspace(data.Area.min(),data.Area.max(),100)
f = g[0,0] + g[0,1]*x

fig,axes = plt.subplots()
axes.plot(x,f,'r',label='Fitted')
axes.scatter(x=data.Area,y=data.Price,label='Trainning data')
axes.legend(loc='best')
axes.set(xlabel='Area',ylabel='Price',title='Area vs. Price')
fig.savefig('p3.png')

參考:Andrew Ng機器學習公開課

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