<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【機(jī)器學(xué)習(xí):理論+實(shí)戰(zhàn)】線性回歸,你還只會(huì)調(diào)包嗎?

          共 16293字,需瀏覽 33分鐘

           ·

          2021-11-12 21:58

          自己動(dòng)手實(shí)現(xiàn)線性回歸

          我們往往會(huì)用類似sklearn的linear_model模塊直接調(diào)包去使用線性回歸處理一些回歸問題,但我們絕不能只會(huì)調(diào)包!

          接下來我們就用面向?qū)ο蟮姆绞?,自己?shí)現(xiàn)一個(gè)線性回歸類,并且在這個(gè)過程中體會(huì)從數(shù)學(xué)公式到python代碼的美妙。

          在這里我將不會(huì)講解線性回歸的原理和公式(畢竟這是python為主題的公眾號),而是聚焦于”從公式到代碼“的過程。所以如果對公式原理以及一些線性回歸的相關(guān)術(shù)語不熟悉,可以去看相關(guān)的資料充充電,這并不難,畢竟線性回歸是機(jī)器學(xué)習(xí)里最簡單直觀的算法了

          簡述線性回歸模型

          線性回歸就是輸入一堆數(shù)據(jù)(假設(shè)有m條,每條數(shù)據(jù)有n個(gè)屬性,也就是m行n列),結(jié)果訓(xùn)練后得到模型參數(shù)(也就是線性回歸方程中與每個(gè)屬性相乘的那些值,有幾n個(gè)屬性,就有對應(yīng)的n個(gè)參數(shù))的過程。

          訓(xùn)練的方法有許多,我大致分兩類,一類就是正則方程,也就是直接通過解矩陣方程得到參數(shù)。另一類就是梯度下降,它又可以細(xì)分為批量梯度下降算法、隨機(jī)梯度下降算法以及小批量梯度下降算法。梯度下降更加有通用性,因?yàn)槠渌鼨C(jī)器學(xué)習(xí)模型的損失函數(shù)都極其復(fù)雜,無法獲得最值的解析解,所以可以說正則方程法算是線性回歸模型的”特色“。

          設(shè)計(jì)自定義的線性回歸類

          初始化函數(shù):

          初始化函數(shù)接收參與訓(xùn)練的數(shù)據(jù)集,并且隨機(jī)設(shè)定模型參數(shù)

          getNormalEquation函數(shù)

          正則方程函數(shù)

          BGD函數(shù)

          BGD函數(shù)是梯度下降算法的函數(shù)

          SGD函數(shù)

          SGD函數(shù)是隨機(jī)梯度下降算法函數(shù),接收學(xué)習(xí)率這個(gè)參數(shù)

          MBGD函數(shù)

          MBGD函數(shù)是小批量梯度下降算法的函數(shù),接收學(xué)習(xí)率這個(gè)參數(shù)

          train_BGD函數(shù)

          用BGD算法訓(xùn)練,接收迭代率和學(xué)習(xí)率兩個(gè)參數(shù)

          train_SGD函數(shù)

          用SGD算法訓(xùn)練,接收迭代率和學(xué)習(xí)率兩個(gè)參數(shù)

          train_MBGD函數(shù)

          用MBGD算法訓(xùn)練,接收迭代率和學(xué)習(xí)率兩個(gè)參數(shù)

          Shuffle函數(shù)

          這個(gè)函數(shù)主要用于生成與訓(xùn)練數(shù)據(jù)集大小相同的隨機(jī)自然數(shù)序列。主要用于SGD函數(shù)和MBGD函數(shù)中,通過隨機(jī)數(shù)序列打亂訓(xùn)練集和標(biāo)簽集,消除訓(xùn)練集順序?qū)GD算法和MBGD算法的影響

          Cost函數(shù)

          這個(gè)函數(shù)就是平均訓(xùn)練的損失函數(shù),計(jì)算訓(xùn)練數(shù)據(jù)集在模型參數(shù)下的預(yù)測結(jié)果與實(shí)際值之間的均方誤差。它主要用于三個(gè)迭代訓(xùn)練函數(shù)中,記錄每次迭代后的誤差

          predict函數(shù)

          這個(gè)函數(shù)是預(yù)測函數(shù),接受一組測試數(shù)據(jù),然后結(jié)合模型參數(shù)對測試數(shù)據(jù)進(jìn)行預(yù)測

          test函數(shù)

          這個(gè)函數(shù)和預(yù)測函數(shù)很相似,都是結(jié)合模型參數(shù)預(yù)測結(jié)果,不同的是這個(gè)函數(shù)接受的是測試數(shù)據(jù)集,它遍歷整個(gè)測試數(shù)據(jù)集,每次都調(diào)用predict函數(shù)進(jìn)行預(yù)測

          自定義線性回歸類的結(jié)構(gòu)

          import?numpy?as?np

          """
          這是一個(gè)關(guān)于線性回歸的模塊
          核心部分就是LinearRegression這個(gè)類
          這個(gè)類有以下幾個(gè)方法
          構(gòu)造方法、根據(jù)參數(shù)計(jì)算預(yù)測值的方法、計(jì)算損失值的方法、生成隨機(jī)數(shù)序列的方法、使用批量梯度下降、隨機(jī)梯度下降、小批量隨機(jī)梯度下降更新參數(shù)的方法
          """

          class?LinearRegress:

          ???def?__init__(self,?input_data,?real_result,?theta):
          ???def?Cost(self):
          ???def?Shuffle(self):
          ???def?BGD(self,alpha):
          ???def?SGD(self,alpha):
          ???def?MBGD(self,alpha,batch_size):
          ???def?train_BGD(self,iter,alpha):
          ???def?train_SGD(self,iter,alpha):
          ???def?train_MBGD(self,iter,batch_size,alpha):
          ???def?predict(self,data):
          ???def?test(self,test_data):

          初始化函數(shù)的代碼實(shí)現(xiàn)

          初始化函數(shù)__init__的參數(shù)是訓(xùn)練數(shù)據(jù)集input_data、訓(xùn)練結(jié)果集real_result以及參數(shù)theta。在初始化函數(shù)內(nèi),主要完成訓(xùn)練數(shù)據(jù)集、結(jié)果集以及模型參數(shù)的初始化,與此同時(shí)還要遍歷每組數(shù)據(jù),并且要對數(shù)據(jù)進(jìn)行拓展,也就是增加一維常數(shù)屬性1(因?yàn)榫€性回歸方程都是z=ax+by+c這種類似形式,c前面的系數(shù)是1) 當(dāng)theta的默認(rèn)值是None,如果是None,那么就用正態(tài)分布隨機(jī)給模型參數(shù)賦值,如若不是,就用theta作為模型參數(shù)

          import?numpy?as?np


          class?LinearRegress:

          ?def?__init__(self,?input_data,?real_result,?theta):
          ??"""
          ? inputData :輸入數(shù)據(jù)??(m條記錄,n個(gè)屬性,m*n)
          ? realResult :真實(shí)數(shù)據(jù)??(m條記錄,1個(gè)值,m*1)
          ? theta :線性回歸的參數(shù),也就是這個(gè)算法不斷更新迭代優(yōu)化得到的核心數(shù)據(jù)?(對應(yīng)n個(gè)屬性,n*1)
          ??默認(rèn)為None??如果是None就用正態(tài)分布的數(shù)據(jù)來初始化參數(shù),如果不是None,就用傳進(jìn)來的theta初始化參數(shù)
          ??"""


          ??#?輸入數(shù)據(jù)集的形狀
          ??row,?col?=?np.shape(input_data)
          ??#?通過輸入數(shù)據(jù)集,建立這個(gè)類里面的成員變量Data,先初始化為m個(gè)0組成的列表
          ??self.Data?=?[0]?*?row
          ??#?給m條數(shù)據(jù)中的每一條數(shù)據(jù)都添加上一個(gè)常數(shù)項(xiàng)1,這一步是為了與線性回歸模型中的偏置b對應(yīng)起來
          ??for?(index,?data)?in?enumerate(input_data):
          ???#?將每一條數(shù)據(jù)構(gòu)成的列表后面都追加一個(gè)1.0,并且根據(jù)序號index將它們存放到成員變量Data相應(yīng)位置中
          ????self.Data[index]?=?list(data).append(1.0)
          ??#?轉(zhuǎn)化為numpy的格式更加高效
          ??self.Data?=?np.array(self.Data)

          ??#?通過輸入的結(jié)果數(shù)據(jù)集,建立這個(gè)類中的成員變量Result
          ??self.Result?=?real_result

          ??#?如果參數(shù)不為None的時(shí)候,利用傳入的theta初始化相應(yīng)參數(shù)
          ??if?theta?is?not?None:
          ???self.Theta?=?theta
          ??#?不然就用正態(tài)分布的數(shù)據(jù)來初始化
          ??else:
          ???#?此處選取了(n+1*1)的數(shù)據(jù),也是為了和偏置匹配
          ???self.Theta?=?np.random.normal((col?+?1,?1))

          輔助函數(shù)的編寫

          在前面一章我們已經(jīng)提到了這個(gè)線性回歸類的函數(shù)(方法)集合,我們先來看一看一些輔助函數(shù),它們往往運(yùn)用在其它的函數(shù)中,因此先對它們進(jìn)行介紹。

          Shuffle函數(shù)

          功能:在運(yùn)行SGD算法函數(shù)或者M(jìn)BGD算法函數(shù)前,隨機(jī)打亂原始的數(shù)據(jù)集以及對應(yīng)的標(biāo)簽集。

          ??def?Shuffle(self):
          ??????"""
          ??????這是在運(yùn)行SGD算法或者M(jìn)BGD算法之前,隨機(jī)打亂后原始數(shù)據(jù)集的函數(shù)
          ??????"""

          ??????#?首先獲得訓(xùn)練集規(guī)模,之后按照規(guī)模生成自然數(shù)序列
          ??????length?=?len(self.InputData)
          ??????sequence?=?list(range(length))
          ??????#?利用numpy的隨機(jī)打亂函數(shù)打亂訓(xùn)練數(shù)據(jù)下標(biāo)
          ??????random_sequence?=?np.random.permutation(sequence)
          ??????#?返回?cái)?shù)據(jù)集隨機(jī)打亂后的數(shù)據(jù)序列
          ??????return?random_sequence
          Cost函數(shù)

          功能:計(jì)算訓(xùn)練數(shù)據(jù)集self.InputData在模型參數(shù)self.Theta下的預(yù)測結(jié)果(也就是它們之間進(jìn)行矩陣的乘法)與實(shí)際值之間的均方誤差。主要運(yùn)用在三種梯度下降算法函數(shù)中,記錄每次迭代訓(xùn)練后的均方誤差。

          ??def?Cost(self):
          ??????"""
          ??????這是計(jì)算損失函數(shù)的函數(shù)
          ??????"""

          ??????#?在線性回歸里的損失函數(shù)定義為真實(shí)結(jié)果與預(yù)測結(jié)果之間的均方誤差
          ??????#?首先計(jì)算輸入數(shù)據(jù)的預(yù)測結(jié)果
          ??????predict?=?self.InputData.dot(self.Theta).T
          ??????#?計(jì)算真實(shí)結(jié)果與預(yù)測結(jié)果之間的均方誤差
          ??????cost?=?predict-self.Result.T
          ??????cost?=?np.average(cost**2)
          ??????return?cost
          predict函數(shù)

          功能:對輸入的測試數(shù)據(jù)(1* n+1),結(jié)合模型參數(shù)(n+1* 1),作矩陣乘法獲得預(yù)測結(jié)果

          ??def?predict(self,data):
          ??????"""
          ??????這是對一組測試數(shù)據(jù)預(yù)測的函數(shù)
          ??????:param?data:?測試數(shù)據(jù)
          ??????"""

          ??????#?對測試數(shù)據(jù)加入1維特征,以適應(yīng)矩陣乘法
          ??????tmp?=?[1.0]
          ??????tmp.extend(data)
          ??????data?=?np.array(tmp)
          ??????#?計(jì)算預(yù)測結(jié)果,計(jì)算結(jié)果形狀為(1,),為了分析數(shù)據(jù)的方便
          ??????#?這里只返矩陣的第一個(gè)元素
          ??????predict_result?=?data.dot(self.Theta)[0]
          ??????return?predict_result
          ????????
          test函數(shù)

          功能:循環(huán)調(diào)用predict函數(shù),遍歷整個(gè)測試數(shù)據(jù)集,m條測試數(shù)據(jù)進(jìn)行預(yù)測

          ??def?test(self,test_data):
          ??????"""
          ??????這是對測試數(shù)據(jù)集的線性回歸預(yù)測函數(shù)
          ??????:param?test_data:?測試數(shù)據(jù)集
          ??????"""

          ??????#?定義預(yù)測結(jié)果數(shù)組
          ??????predict_result?=?[]
          ??????#?對測試數(shù)據(jù)進(jìn)行遍歷
          ??????for?data?in?test_data:
          ??????????#?預(yù)測每組data的結(jié)果
          ??????????predict_result.append(self.predict(data))
          ??????predict_result?=?np.array(predict_result)
          ??????return?predict_result
          train_BGD函數(shù)

          利用BGD算法函數(shù)進(jìn)行訓(xùn)練的函數(shù),iter代表迭代的次數(shù),alpha代表學(xué)習(xí)率,也就是每次更新模型參數(shù)的幅度大小

          ??def?train_BGD(self,iter,alpha):
          ??????"""
          ??????這是利用BGD算法迭代優(yōu)化的函數(shù)
          ??????:param?iter:?迭代次數(shù)
          ??????:param?alpha:?學(xué)習(xí)率
          ??????"""

          ??????#?定義訓(xùn)練損失數(shù)組,記錄每輪迭代的訓(xùn)練數(shù)據(jù)集的損失
          ??????Cost?=?[]
          ??????#?開始進(jìn)行迭代訓(xùn)練
          ??????for?i?in?range(iter):
          ??????????#?利用學(xué)習(xí)率alpha,結(jié)合BGD算法對模型進(jìn)行訓(xùn)練
          ??????????self.BGD(alpha)
          ??????????#?記錄每次迭代的訓(xùn)練損失
          ??????????Cost.append(self.Cost())
          ??????Cost?=?np.array(Cost)
          ??????return?Cost
          train_SGD函數(shù)

          利用SGD算法函數(shù)進(jìn)行訓(xùn)練的函數(shù),參數(shù)說明同上

          ??def?train_SGD(self,iter,alpha):
          ??????"""
          ??????這是利用SGD算法迭代優(yōu)化的函數(shù)
          ??????:param?iter:?迭代次數(shù)
          ??????:param?alpha:?學(xué)習(xí)率
          ??????"""

          ??????#?定義訓(xùn)練損失數(shù)組,記錄每輪迭代的訓(xùn)練數(shù)據(jù)集的損失
          ??????Cost?=?[]
          ??????#?開始進(jìn)行迭代訓(xùn)練
          ??????for?i?in?range(iter):
          ??????????#?利用學(xué)習(xí)率alpha,結(jié)合SGD算法對模型進(jìn)行訓(xùn)練
          ??????????self.SGD(alpha)
          ??????????#?記錄每次迭代的訓(xùn)練損失
          ??????????Cost.append(self.Cost())
          ??????Cost?=?np.array(Cost)
          ??????return?Cost
          train_MBGD函數(shù)

          利用MBGD算法函數(shù)進(jìn)行訓(xùn)練的函數(shù),參數(shù)說明同上

          ??def?train_MBGD(self,iter,batch_size,alpha):
          ??????"""
          ??????這是利用MBGD算法迭代優(yōu)化的函數(shù)
          ??????:param?iter:?迭代次數(shù)
          ??????:param?batch_size:?小樣本規(guī)模
          ??????:param?alpha:?學(xué)習(xí)率
          ??????"""

          ??????#?定義訓(xùn)練損失數(shù)組,記錄每輪迭代的訓(xùn)練數(shù)據(jù)集的損失
          ??????Cost?=?[]
          ??????#?開始進(jìn)行迭代訓(xùn)練
          ??????for?i?in?range(iter):
          ??????????#?利用學(xué)習(xí)率alpha,結(jié)合MBGD算法對模型進(jìn)行訓(xùn)練
          ??????????self.MBGD(alpha,batch_size)
          ??????????#?記錄每次迭代的訓(xùn)練損失
          ??????????Cost.append(self.Cost())
          ??????Cost?=?np.array(Cost)
          ??????return?Cost

          正則方程法

          所謂正則方程法就是用矩陣求導(dǎo)的方法,求取損失函數(shù)的最小值 在求導(dǎo)的過程中,會(huì)求解導(dǎo)函數(shù)等于零的方程,最終將會(huì)解得模型參數(shù)值為:訓(xùn)練數(shù)據(jù)集的轉(zhuǎn)置乘以訓(xùn)練數(shù)據(jù)集本身,之后對相乘結(jié)果求一個(gè)逆矩陣,再將整個(gè)逆矩陣乘以訓(xùn)練數(shù)據(jù)集本身,最后與結(jié)果數(shù)據(jù)集相乘。具體的推導(dǎo)過程可以看下圖

          值得注意的是,正則方程法需要保證訓(xùn)練數(shù)據(jù)集的轉(zhuǎn)置乘以訓(xùn)練數(shù)據(jù)集本身,記為XT*X可以求得逆矩陣,但是在實(shí)際問題中,數(shù)據(jù)集的特征數(shù)n可能會(huì)大于數(shù)據(jù)集規(guī)模m,這就導(dǎo)致了XTX不可逆。故而在實(shí)際的編程過程中,會(huì)在XTX的基礎(chǔ)上加一個(gè)很小的可逆矩陣,例如0.001E,這樣就可以保證可逆了。

          ??def?getNormalEquation(self):
          ??????"""
          ??????這是利用正規(guī)方程計(jì)算模型參數(shù)Thetha
          ??????"""

          ??????"""
          ????????0.001*np.eye(np.shape(self.InputData.T))是
          ????????防止出現(xiàn)原始XT的行列式為0,即防止原始XT不可逆
          ?????"""

          ??????#?獲得輸入數(shù)據(jù)數(shù)組形狀
          ??????col,rol?=?np.shape(self.InputData.T)
          ??????#?計(jì)算輸入數(shù)據(jù)矩陣的轉(zhuǎn)置
          ??????XT?=?self.InputData.T+0.001*np.eye(col,rol)
          ??????#?計(jì)算矩陣的逆
          ??????inv?=?np.linalg.inv(XT.dot(self.InputData))
          ??????#?計(jì)算模型參數(shù)Thetha
          ??????self.Theta?=?inv.dot(XT.dot(self.Result))

          梯度下降算法

          梯度下降算法是求取最值的通法,通過每次的迭代更新,逐步逼近最優(yōu)解,常用于機(jī)器學(xué)習(xí)和人工智能當(dāng)中用來遞歸性地逼近最小偏差模型。

          在線性回歸模型中,我們在求解損失函數(shù)的最小值時(shí),可以通過梯度下降法來一步步的迭代求解,得到最小化的損失函數(shù)和模型參數(shù)值。

          具體可分為三種:批量梯度下降算法(Batch Gradient Descent)BGD、隨機(jī)梯度下降算法(Stochastic Gradient Descent)SGD 以及 小批量梯度下降算法(Mini Batch Gradient Descent)MBGD,下面我們來依次介紹這些算法的思想以及具體的編程實(shí)現(xiàn)。

          批量梯度下降算法

          算法流程:每次迭代遍歷數(shù)據(jù)集時(shí),保存每組訓(xùn)練數(shù)據(jù)對應(yīng)的梯度增量,待到遍歷結(jié)束后,計(jì)算所有梯度增量之和,再與當(dāng)前模型參數(shù)相加,更新模型參數(shù),重復(fù)上述過程,直到模型參數(shù)值收斂。顯然,經(jīng)過不斷的優(yōu)化迭代后,BGD算法幾乎可以收斂于全局最優(yōu)解(當(dāng)然還受限于學(xué)習(xí)率這個(gè)超參數(shù),它代表模型參數(shù)更新的幅度)。

          ??def?BGD(self,alpha):
          ??????"""
          ??????這是利用BGD算法進(jìn)行一次迭代調(diào)整參數(shù)的函數(shù)
          ??????:param?alpha:?學(xué)習(xí)率
          ??????"""

          ??????#?定義梯度增量數(shù)組
          ??????gradient_increasment?=?[]
          ??????#?對輸入的訓(xùn)練數(shù)據(jù)及其真實(shí)結(jié)果進(jìn)行依次遍歷
          ??????for?(input_data,real_result)?in?zip(self.InputData,self.Result):
          ??????????#?計(jì)算每組input_data的梯度增量,并放入梯度增量數(shù)組
          ??????????g?=?(real_result-input_data.dot(self.Theta))*input_data
          ??????????gradient_increasment.append(g)
          ??????#?按列計(jì)算屬性的平均梯度增量
          ??????avg_g?=?np.average(gradient_increasment,0)
          ??????#?改變平均梯度增量數(shù)組形狀
          ??????avg_g?=?avg_g.reshape((len(avg_g),1))
          ??????#?更新參數(shù)Theta
          ??????self.Theta?=?self.Theta?+?alpha*avg_g

          BGD算法每次迭代都需要遍歷整個(gè)訓(xùn)練數(shù)據(jù)集,保存每組數(shù)據(jù)對應(yīng)的梯度增量,當(dāng)數(shù)據(jù)規(guī)模較大時(shí),會(huì)帶來很大的空間開銷?;诖?,隨機(jī)梯度下降算法 SGD 應(yīng)運(yùn)而生!

          隨機(jī)梯度下降算法

          BGD算法雖然可以幾乎收斂于全局最優(yōu)解,但是開銷太大,速度慢,適應(yīng)性不強(qiáng)。究其原因,還是每次都要遍歷整個(gè)訓(xùn)練數(shù)據(jù)集這個(gè)過程花銷太大了,所以就想到了每次就用一條數(shù)據(jù)來更新參數(shù)的方法,這就是隨機(jī)梯度下降算法!

          算法流程:在規(guī)模為m的數(shù)據(jù)集中,每次取出一條,來計(jì)算對應(yīng)的模型參數(shù)梯度,每次都用這個(gè)梯度來更新模型參數(shù)。也就是說在迭代過程中更新m次。重復(fù)上述過程直到收斂,在這個(gè)過程中會(huì)先講數(shù)據(jù)集打亂。

          這個(gè)算法與批量梯度下降的最大不同就是:前者需要累積整個(gè)數(shù)據(jù)集的梯度增量之和,而后再更新;而隨機(jī)梯度下降則是將每條數(shù)據(jù)產(chǎn)生的梯度增量立即更新到模型參數(shù)上。后者的空間開銷顯然要小

          ?def?SGD(self,alpha):
          ??????"""
          ??????這是利用SGD算法進(jìn)行一次迭代調(diào)整參數(shù)的函數(shù)
          ??????:param?alpha:?學(xué)習(xí)率
          ??????"""

          ??????#?首先將數(shù)據(jù)集隨機(jī)打亂,減小數(shù)據(jù)集順序?qū)?shù)調(diào)優(yōu)的影響
          ??????shuffle_sequence?=?self.Shuffle()
          ??????self.InputData?=?self.InputData[shuffle_sequence]
          ??????self.Result?=?self.Result[shuffle_sequence]
          ??????#?對訓(xùn)練數(shù)據(jù)集進(jìn)行遍歷,利用每組訓(xùn)練數(shù)據(jù)對參數(shù)進(jìn)行調(diào)整
          ??????for?(input_data,real_result)?in?zip(self.InputData,self.Result):
          ??????????#?計(jì)算每組input_data的梯度增量
          ??????????g?=?(real_result-input_data.dot(self.Theta))*input_data
          ??????????#?調(diào)整每組input_data的梯度增量的形狀
          ??????????g?=?g.reshape((len(g),1))
          ??????????#?更新線性回歸模型參數(shù)
          ??????????self.Theta?=?self.Theta?+?alpha?*?g

          然而,SGD也有其缺陷,雖然相比于BGD頻繁調(diào)整了參數(shù),加快了收斂速度,但是每次都用一條數(shù)據(jù)的梯度來更新,不能代表全體數(shù)據(jù)集的梯度方向,屬實(shí)是”以偏概全“了,屬于貪心算法,理論上不能獲得最優(yōu)解,常常只能獲得次優(yōu)解?;赟GD和BGD的優(yōu)點(diǎn)不同,小批量隨機(jī)梯度下降 MBGD 算法應(yīng)運(yùn)而生!

          小批量隨機(jī)梯度下降算法

          這個(gè)算法的思想就是:首先打亂數(shù)據(jù)集順序,并且劃分為若干批小樣本,而后每次迭代后遍歷一個(gè)批次里的所有樣本,計(jì)算梯度增量平均值,據(jù)此來更新模型參數(shù)。在小批量樣本的規(guī)模足夠大的時(shí)候,小批量樣本的梯度向量平均值也近似等于整個(gè)訓(xùn)練數(shù)據(jù)集的平均值了,這樣就結(jié)合了BGD的”廣泛性“和SGD的”快速性“

          ??def?MBGD(self,alpha,batch_size):
          ??????"""
          ??????這是利用MBGD算法進(jìn)行一次迭代調(diào)整參數(shù)的函數(shù)
          ??????:param?alpha:?學(xué)習(xí)率
          ??????:param?batch_size:?小樣本規(guī)模
          ??????"""

          ??????#?首先將數(shù)據(jù)集隨機(jī)打亂,減小數(shù)據(jù)集順序?qū)?shù)調(diào)優(yōu)的影響
          ??????shuffle_sequence?=?self.Shuffle()
          ??????self.InputData?=?self.InputData[shuffle_sequence]
          ??????self.Result?=?self.Result[shuffle_sequence]
          ??????#?遍歷每個(gè)小批量樣本
          ??????for?start?in?np.arange(0,?len(shuffle_sequence),?batch_size):
          ??????????#?判斷start+batch_size是否大于數(shù)組長度,
          ??????????#?防止最后一組小樣本規(guī)??赡苄∮赽atch_size的情況
          ??????????end?=?np.min([start?+?batch_size,?len(shuffle_sequence)])
          ??????????#?獲取訓(xùn)練小批量樣本集及其標(biāo)簽
          ??????????mini_batch?=?shuffle_sequence[start:end]
          ??????????Mini_Train_Data?=?self.InputData[mini_batch]
          ??????????Mini_Train_Result?=?self.Result[mini_batch]
          ??????????#?定義梯度增量數(shù)組
          ??????????gradient_increasment?=?[]
          ??????????#?對小樣本訓(xùn)練集進(jìn)行遍歷,利用每個(gè)小樣本的梯度增量的平均值對模型參數(shù)進(jìn)行更新
          ??????????for?(data,result)?in?zip(Mini_Train_Data,Mini_Train_Result):
          ??????????????#?計(jì)算每組input_data的梯度增量,并放入梯度增量數(shù)組
          ??????????????g?=?(result?-?data.dot(self.Theta))?*?data
          ??????????????gradient_increasment.append(g)
          ??????????#?按列計(jì)算每組小樣本訓(xùn)練集的梯度增量的平均值,并改變其形狀
          ??????????avg_g?=?np.average(gradient_increasment,?0)
          ??????????avg_g?=?avg_g.reshape((len(avg_g),?1))
          ??????????#?更新模型參數(shù)theta
          ??????????self.Theta?=?self.Theta?+?alpha?*?avg_g

          MBGD兼顧了BGD算法和SGD算法的優(yōu)點(diǎn),是中庸的選擇

          訓(xùn)練線性回歸模型

          在這個(gè)章節(jié)中,將會(huì)用sklearn內(nèi)置的波士頓房價(jià)數(shù)據(jù)集結(jié)合我們自己實(shí)現(xiàn)的線性回歸去預(yù)測波士頓郊區(qū)的房價(jià)。

          波士頓房價(jià)數(shù)據(jù)集共有14個(gè)屬性,其中13個(gè)是輸入屬性,還有1個(gè)屬性是輸出屬性”房屋價(jià)格“。13個(gè)輸入屬性中的第6個(gè)屬性就是”房間數(shù)目“,結(jié)合常識,房間數(shù)目約等于面積,對房價(jià)的影響很大。為了簡化案例,我們就聚焦于”房間數(shù)目“,據(jù)此預(yù)測房屋價(jià)格。

          波士頓房價(jià)數(shù)據(jù)集是很知名的數(shù)據(jù)集,如果對這個(gè)數(shù)據(jù)集的結(jié)構(gòu)不了解的同學(xué)可以去搜一下相關(guān)資料。

          在本章的代碼中,會(huì)用到numpy、pandas、matplotlib以及sklearn,對這些模塊不熟悉的同學(xué),可以去看看螞蟻老師的相關(guān)課程!

          Merge函數(shù):將實(shí)驗(yàn)數(shù)據(jù)轉(zhuǎn)換為結(jié)構(gòu)化數(shù)據(jù)

          因?yàn)槲蚁M麑⒌玫降膶?shí)驗(yàn)結(jié)果存入到excel文件中,就先定義了Merge函數(shù),將sklearn中的數(shù)據(jù)轉(zhuǎn)換為pandas的dataframe形式,方便后續(xù)操作。

          def?Merge(data,col):
          ????"""
          ????這是生成DataFrame數(shù)據(jù)的函數(shù)
          ????:param?data:輸入數(shù)據(jù)
          ????:param?col:列名稱數(shù)組
          ????"""

          ????Data?=?np.array(data).T
          ????return?pd.DataFrame(Data,columns=col)
          數(shù)據(jù)預(yù)處理

          首先導(dǎo)入數(shù)據(jù)集,并且對它進(jìn)行預(yù)處理,用load_boston()函數(shù)加載數(shù)據(jù)集,并且只選取第六個(gè)特征值”平均房間數(shù)目“,通過Merge生成dataframe,而后保存為excel文件。然后將改變一下訓(xùn)練數(shù)據(jù)集和結(jié)果(房價(jià))數(shù)據(jù)集的形狀,最后將這些數(shù)據(jù)集劃分為訓(xùn)練集和測試集。

          from?sklearn.model_selection?import?train_test_split
          from?sklearn.datasets?import?load_boston
          #?導(dǎo)入數(shù)據(jù)以及劃分訓(xùn)練數(shù)據(jù)與測試數(shù)據(jù)
          InputData,?Result?=?load_boston(return_X_y=True)
          #?為了方便實(shí)驗(yàn),只取第6維特征。第6列為平均房間數(shù)目
          InputData?=?np.array(InputData)[:,5]
          #?保存原始數(shù)據(jù)集
          Data?=?Merge([InputData,Result],['平均房間數(shù)目','房價(jià)'])
          Data.to_excel('./原始數(shù)據(jù).xlsx')
          #?改變數(shù)據(jù)集與真實(shí)房價(jià)數(shù)組的形狀
          InputData?=?InputData.reshape((len(InputData),?1))
          Result?=?np.array(Result).reshape((len(Result),?1))

          #?把數(shù)據(jù)集分成訓(xùn)練數(shù)據(jù)集和測試數(shù)據(jù)集
          train_data,test_data,train_result,test_result?=?\
          ????train_test_split(InputData,Result,test_size=0.1,random_state=50)
          數(shù)據(jù)可視化

          我們會(huì)用到matplotlib庫,對這些數(shù)據(jù)進(jìn)行可視化

          import?matplotlib?as?mpl
          import?matplotlib.pyplot?as?plt
          #?解決Matplotlib中的中文亂碼問題,以便于后面實(shí)驗(yàn)結(jié)果可視化
          mpl.rcParams['font.sans-serif']?=?[u'simHei']
          mpl.rcParams['axes.unicode_minus']?=?False

          #?利用散點(diǎn)圖可視化測試數(shù)據(jù)集,并保存可視化結(jié)果
          col?=?['真實(shí)房價(jià)']
          plt.scatter(test_data,test_result,alpha=0.5,c='b',s=10)
          plt.grid(True)
          plt.legend(labels?=?col,loc='best')
          plt.xlabel("房間數(shù)")
          plt.ylabel("真實(shí)房價(jià)")
          plt.savefig("./測試集可視化.jpg",bbox_inches='tight')
          plt.show()
          plt.close()
          構(gòu)建模型

          首先,隨機(jī)生成模型參數(shù),而后將訓(xùn)練數(shù)據(jù)和模型參數(shù),引入我們的線性回歸類,將訓(xùn)練數(shù)據(jù)和模型參數(shù)傳入我們寫好的線性回歸對象中,每一種算法都實(shí)例化出一個(gè)對象。

          from?LinearRegression.LinearRegression?import?LinearRegress
          #?開始構(gòu)建線性回歸模型
          col?=?np.shape(train_data)[1]+1
          #?初始化線性回歸參數(shù)theta
          theta?=?np.random.random((col,1))
          #?BGD優(yōu)化的線性回歸模型
          linearregression_BGD?=?LinearRegression(train_data,?train_result,theta)
          #?SGD優(yōu)化的線性回歸模型
          linearregression_SGD?=?LinearRegression(train_data,?train_result,theta)
          #?MBGD優(yōu)化的線性回歸模型
          linearregression_MBGD?=?LinearRegression(train_data,?train_result,theta)
          #?正則方程優(yōu)化的線性回歸模型
          linearregression_NormalEquation?=?LinearRegression(train_data,?train_result,theta)

          之后設(shè)定迭代次數(shù)、學(xué)習(xí)率、小批量樣本個(gè)數(shù)這些超參數(shù),并且傳入相應(yīng)的對象中

          #?訓(xùn)練模型
          iter?=?30000?????????????#?迭代次數(shù)
          alpha?=?0.001????????????#?學(xué)習(xí)率
          batch_size?=?64??????????#?小樣本規(guī)模
          #?BGD的訓(xùn)練損失
          BGD_train_cost?=?linearregression_BGD.train_BGD(iter,alpha)
          #?SGD的訓(xùn)練損失
          SGD_train_cost?=?linearregression_SGD.train_SGD(iter,alpha)
          #?MBGD的訓(xùn)練損失
          MBGD_train_cost?=?linearregression_MBGD.train_MBGD(iter,batch_size,alpha)
          #?利用正規(guī)方程獲取參數(shù)
          linearregression_NormalEquation.getNormalEquation()
          記錄迭代訓(xùn)練誤差結(jié)果并進(jìn)行可視化

          訓(xùn)練結(jié)束后,就將訓(xùn)練的結(jié)果進(jìn)行可視化,觀察比較算法之間的差異,并且將這些信息保存為excel文件

          #?三種梯度下降算法迭代訓(xùn)練誤差結(jié)果可視化,并保存可視化結(jié)果
          col?=?['BGD','SGD','MBGD']
          iter?=?np.arange(iter)
          plt.plot(iter,?BGD_train_cost,?'r-.')
          plt.plot(iter,?SGD_train_cost,?'b-')
          plt.plot(iter,?MBGD_train_cost,?'k--')
          plt.grid(True)
          plt.xlabel("迭代次數(shù)")
          plt.ylabel("平均訓(xùn)練損失")
          plt.legend(labels?=?col,loc?=?'best')
          plt.savefig("./三種梯度算法的平均訓(xùn)練損失.jpg",bbox_inches='tight')
          plt.show()
          plt.close()

          #?三種梯度下降算法的訓(xùn)練損失
          #?整合三種梯度下降算法的訓(xùn)練損失到DataFrame
          train_cost?=?[BGD_train_cost,SGD_train_cost,MBGD_train_cost]
          train_cost?=?Merge(train_cost,col)
          #?保存三種梯度下降算法的訓(xùn)練損失及其統(tǒng)計(jì)信息
          train_cost.to_excel("./三種梯度下降算法的訓(xùn)練訓(xùn)練損失.xlsx")
          train_cost.describe().to_excel("./三種梯度下降算法的訓(xùn)練訓(xùn)練損失統(tǒng)計(jì).xlsx")
          用訓(xùn)練好的模型擬合曲線

          計(jì)算4種算法訓(xùn)練的線性回歸模型的擬合曲線,并可視化

          #?計(jì)算4種調(diào)優(yōu)算法下的擬合曲線
          x?=?np.arange(int(np.min(test_data)),?int(np.max(test_data)+1))
          x?=?x.reshape((len(x),1))
          #?BGD算法的擬合曲線
          BGD?=?linearregression_BGD.test(x)
          #?SGD算法的擬合曲線
          SGD?=?linearregression_SGD.test(x)
          #?MBGD算法的擬合曲線
          MBGD?=?linearregression_MBGD.test(x)
          #?正則方程的擬合曲線
          NormalEquation?=?linearregression_NormalEquation.test(x)

          #?4種模型的擬合直線可視化,并保存可視化結(jié)果
          col?=?['BGD',?'SGD',?'MBGD',?'正則方程']
          plt.plot(x,?BGD,'r-.')
          plt.plot(x,?SGD,?'b-')
          plt.plot(x,?MBGD,?'k--')
          plt.plot(x,?NormalEquation,?'g:',)
          plt.scatter(test_data,test_result,alpha=0.5,c='b',s=10)
          plt.grid(True)
          plt.xlabel("房間數(shù)")
          plt.ylabel("預(yù)測值")
          plt.legend(labels?=?col,loc?=?'best')
          plt.savefig("./預(yù)測值比較.jpg",bbox_inches='tight')
          plt.show()
          plt.close()

          對模型進(jìn)行驗(yàn)證

          前文介紹了模型的訓(xùn)練過程,那如何評判訓(xùn)練好的模型效果呢?方法是用測試集了驗(yàn)證模型預(yù)測值與實(shí)際值的誤差去判斷效果。

          在這里,將會(huì)使用4種實(shí)例化對象的test方法得到模型的預(yù)測結(jié)果,然后使用pandas將預(yù)測結(jié)果和統(tǒng)計(jì)信息保存為excel文件

          #?利用測試集進(jìn)行線性回歸預(yù)測
          #?BGD算法的預(yù)測結(jié)果
          BGD_predict?=?linearregression_BGD.test(test_data)
          #?SGD算法的預(yù)測結(jié)果
          SGD_predict?=?linearregression_SGD.test(test_data)
          #?MBGD算法的預(yù)測結(jié)果
          MBGD_predict?=?linearregression_MBGD.test(test_data)
          #?正則方程的預(yù)測結(jié)果
          NormalEquation_predict?=?linearregression_NormalEquation.test(test_data)

          #?保存預(yù)測數(shù)據(jù)
          #?A.tolist()是將numpy.array轉(zhuǎn)化為python的list類型的函數(shù),是將A的所有元素
          #?當(dāng)作一個(gè)整體作為list的一個(gè)元素,因此我們只需要A.tolist()的第一個(gè)元素
          data?=?[test_data.T.tolist()[0],test_result.T.tolist()[0],BGD_predict,
          ????????????SGD_predict,MBGD_predict,NormalEquation_predict]
          col?=?["平均房間數(shù)目","真實(shí)房價(jià)",'BGD預(yù)測結(jié)果','SGD預(yù)測結(jié)果','MBGD預(yù)測結(jié)果','正規(guī)方程預(yù)測結(jié)果']
          Data?=?Merge(data,col)
          Data.to_excel('./測試數(shù)據(jù)與預(yù)測結(jié)果.xlsx')

          #?計(jì)算4種算法的均方誤差以及其統(tǒng)計(jì)信息
          #?test_result之前的形狀為(num,1),首先計(jì)算其轉(zhuǎn)置后
          #?獲得其第一個(gè)元素即可
          test_result?=?test_result.T[0]
          #?BGD算法的均方誤差
          BGD_error?=?((BGD_predict-test_result)**2)
          #?SGD算法的均方誤差
          SGD_error?=?((SGD_predict-test_result)**2)
          #?MBGD算法的均方誤差
          MBGD_error?=?((MBGD_predict-test_result)**2)
          #?正則方程的均方誤差
          NormalEquation_error?=?((NormalEquation_predict-test_result)**2)
          #?整合四種算法的均方誤差到DataFrame
          error?=?[BGD_error,SGD_error,MBGD_error,NormalEquation_error]
          col?=?['BGD',?'SGD',?'MBGD',?'正則方程']
          error?=?Merge(error,col)
          #?保存四種均方誤差及其統(tǒng)計(jì)信息
          error.to_excel("./四種算法的均方預(yù)測誤差原始數(shù)據(jù).xlsx")
          error.describe().to_excel("./四種算法的均方預(yù)測誤差統(tǒng)計(jì).xlsx")

          分析本次實(shí)驗(yàn)的結(jié)果

          原始數(shù)據(jù)集

          我們來看看原始數(shù)據(jù)集長什么樣子

          可視化測試集

          看表格不直觀,我們來看看其中測試集的可視化結(jié)果吧!

          可以明顯看到平均房間數(shù)和房價(jià)之間存在正相關(guān)的關(guān)系

          對比3種梯度下降算法在訓(xùn)練過程中的平均損失
          img
          對3種梯度下降算法的均方誤差進(jìn)行統(tǒng)計(jì)
          img

          顯然可以發(fā)現(xiàn),BGD算法的斂速度最慢,且在訓(xùn)練結(jié)束后,BGD算法的訓(xùn)練均方誤差最終在48.533,SGD的收斂速度最快(最快到達(dá)拐點(diǎn)),但由于貪心算法的特性(每條數(shù)據(jù)的梯度增量都作用于模型參數(shù))它會(huì)在最小值附近震蕩,而MBGD收斂速度居中,且沒有震蕩,誤差基本上都是一路下跌

          這些結(jié)果和我們的前期判斷一致

          驗(yàn)證模型

          接下來我們看看4中算法訓(xùn)練出來的模型應(yīng)用在測試集的數(shù)據(jù)上是什么效果吧!

          預(yù)測結(jié)果可視化
          img

          在上圖中,圓點(diǎn)代表真實(shí)數(shù)據(jù),從上到下4條線形不一的直線分別代表BGD、SGD、MBGD以及正則方程算法訓(xùn)練出來的線性回歸模型的預(yù)測擬合直線。從圖中來看,除了少量離群點(diǎn),絕大多數(shù)點(diǎn)都均勻分布在4條擬合直線的左右,大致可以判定,效果都還不錯(cuò)。

          預(yù)測結(jié)果量化分析

          為了更好地對比4中算法的優(yōu)缺點(diǎn),下圖給出測試集的預(yù)測房價(jià)與真實(shí)房價(jià)之間的均方誤差統(tǒng)計(jì)信息

          可以看出來,MBGD的均方誤差在測試集上是最小的,正則方程緊隨其后,BGD第三,SGD誤差最大 再次驗(yàn)證了我們之前的判斷。

          總結(jié)

          線性回歸是機(jī)器學(xué)習(xí)回歸問題中最簡單的模型,其模型參數(shù)通常用梯度下降和正則方程求解。在三種梯度下降算法中,BGD能近似獲得全局最優(yōu)解,穩(wěn)定性強(qiáng),但是收斂速度慢;SGD則是收斂速度快,但無法獲得全局最優(yōu)解,且穩(wěn)定性欠佳;MBGD則是中庸方案。至于正則方程,則適用于大規(guī)模的數(shù)據(jù)集,但其時(shí)間復(fù)雜度較大(涉及大量矩陣相乘)。

          推薦我的機(jī)器學(xué)習(xí)實(shí)戰(zhàn)課程

          一個(gè)機(jī)器學(xué)習(xí)系列,從模型訓(xùn)練到在線預(yù)估,到Linux線上部署,包含大量的工程細(xì)節(jié),推薦給大家我自己的機(jī)器學(xué)習(xí)實(shí)戰(zhàn)課程:

          掃碼購買
          《機(jī)器學(xué)習(xí) Sklearn二手車價(jià)格預(yù)估》

          課程介紹


          購買后加老師微信:ant_learn_python

          會(huì)提供微信答疑,拉VIP會(huì)員交流群

          瀏覽 126
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  在线免费视频a | 抽插美女大逼网页 | 欧洲操逼视频 | 操逼逼啊啊啊 | 波多野结衣一区在线 |