從 0 開始機器學(xué)習(xí) - 一文入門多維特征梯度下降法!

今天登龍跟大家分享下我對多維特征的讀取、縮放和多變量梯度下降算法的理解,文章不長,有理論也有實際的代碼,下面開始,Go!

一、如何表示多維特征?

1.1 特征縮放

實際項目中在讀取多維特征之前需要先對數(shù)據(jù)進行縮放,為什么呢?

因為在有了多維特征向量和多變量梯度下降法后,為了幫助算法更快地收斂,還需要對選用的特征進行尺度縮放,其實就是縮小特征值,將多個特征的值都縮小到同樣大小的區(qū)間,通常是縮小到 [-1, 1] 周圍。

以下圖為例:

image

在沒有進行特征縮放之前,兩參數(shù)梯度下降的等高線圖呈豎的橢圓形,這是因為橫軸和縱軸參數(shù)范圍不同,進而導(dǎo)致算法在尋找最小值時會迭代很多次。

而當(dāng)進行縮放使得橫縱軸范圍大致相同后,等高線圖基本呈圓形,算法在迭代的時候往一個方向很快就能找到最小值,大大減少迭代次數(shù)。

縮放的最終結(jié)果不一定非要準(zhǔn)確到 [-1, 1],比如 [-3, 3],[-2, 1] 這些范圍不是太大都是可以的,一個又常用有簡單的特征縮放計算方法是:

x_n=\frac{x_n - \mu_n}{s_n}

其中 {\mu_{n}} 是平均值,{s_{n}} 是(max - min),比如用這個公式將所有的房屋面積和臥室數(shù)量進行縮放:

  • x_1 = (size - 1000) / 2000,其中 1000 是面積平均值,2000 是最大面積減最小面積。
  • x_2 = (bedrooms - 2) / 5,其中 2 是臥室數(shù)量平均值,5 個最大臥室數(shù)量減去最小臥室數(shù)量。

理論學(xué)會后,再來學(xué)習(xí)下實際的特征縮放代碼:

# 特征縮放
def normalize_feature(df):
    # 對原始數(shù)據(jù)每一列應(yīng)用一個 lambda 函數(shù),mean() 求每列平均值,std() 求標(biāo)準(zhǔn)差
    return df.apply(lambda column: (column - column.mean()) / column.std())

我們用這個函數(shù)來實際縮放一下含有 2 個特征的原始房價數(shù)據(jù):

# 讀取原始數(shù)據(jù)
raw_data = pd.read_csv('ex1data2.txt', names = ['square', 'bedrooms', 'price'])

# 顯示前 5 行
raw_data.head()
image
# 對原始數(shù)據(jù)進行特征縮放
data = normalize_feature(raw_data)

# 顯示縮放后的前 5 行數(shù)據(jù)
data.head()
image

可以看到縮放后的數(shù)據(jù)范圍基本都在 [-1, 1] 區(qū)間左右,說明我們的特征縮放成功了 _!下面來學(xué)習(xí)如何讀取多維特征!

1.2 讀取多維特征

還記得上篇文章我們介紹的第一個機器學(xué)習(xí)算法嗎?

即通過房屋面積來預(yù)測價格,這個問題中只使用一個輸入特征房屋面積,可現(xiàn)實生活中要解決的問題通常都含有多個特征,因為用多個特征訓(xùn)練出的模型準(zhǔn)確度更高。

那么如何機器學(xué)習(xí)算法如何處理多個特征的輸入呢?

我們還用預(yù)測房價的例子,不過這次要增加另外 3 個特征,臥室數(shù)量,房屋樓層,房屋年齡:

image

這樣一來,我們就有了 4 個輸入特征了,特征多了,表示的方法也要升升級了:

  • n:輸入特征的數(shù)量,即特征矩陣列數(shù),也即特征向量的維度

  • {x^{\left( i \right)}}:訓(xùn)練集中第 i 個實例向量,就是特征矩陣的第 i 行,比如列向量 {x}^{(2)}\text{=}\begin{bmatrix} 1416 & 3 & 2 & 40 \end{bmatrix}^T

  • {x_j}^{\left( i \right)}:訓(xùn)練集中第 i 個實例的第 j 個特征,比如 x_2^{\left( 2 \right)}=3

特征數(shù)量增加了,之前的假設(shè)函數(shù)肯定也需要修改,要把增加的特征變量和參數(shù)加上:

h_{\theta}\left( x \right)={\theta_{0}}+{\theta_{1}}{x_{1}}+{\theta_{2}}{x_{2}}+...+{\theta_{n}}{x_{n}}

雖然這樣表示沒問題,但是卻不方便利用向量來計算,因為參數(shù) \theta 有 n + 1 個,但 x 只有 n 個,那怎么辦呢?

很簡單,我們額外增加一個 {x_0}=1,則上式變?yōu)椋?/p>

h_{\theta} \left( x \right)={\theta_{0}}{x_{0}}+{\theta_{1}}{x_{1}}+{\theta_{2}}{x_{2}}+...+{\theta_{n}}{x_{n}}

這樣一來就可以寫成向量相乘的形式:

h_{\theta} \left( x \right)={\theta^{T}}X

你可能要問了為何要寫成向量的形式?主要因為 2 點:

  • 使用向量方便程序編寫,一句計算特征向量的代碼就可以同時計算多個輸入?yún)?shù),因為一個特征向量中包含所有輸入?yún)?shù)
  • 使用向量方便算法執(zhí)行,梯度下降算法要求參數(shù)同時更新,如果不使用向量,那更新起來非常麻煩。

通過增加一個維度 x_0 = 1,最終訓(xùn)練集的特征矩陣的大小為:m * (n + 1),其中 m 為行數(shù),n + 1 為列數(shù)。

那來看下讀取多維數(shù)據(jù)并添加一列全 1 向量的函數(shù)代碼:

# 讀取原始數(shù)據(jù),返回 m * (n + 1) 維特征矩陣
def get_X(df):
    # 創(chuàng)建 m 行 1 列的數(shù)據(jù)幀
    ones = pd.DataFrame({'ones': np.ones(len(df))})
    
    # 合并全 1 向量作為元素數(shù)據(jù)第一列,axis = 0 按行合并,anix = 1 按列合并
    data = pd.concat([ones, df], axis=1)
    
    # 返回特征矩陣
    return data.iloc[:, :-1].values

為了簡單點,這里假設(shè)原始房價數(shù)據(jù)只有 2 個輸入特征,即房屋面積和臥室數(shù)量:

[圖片上傳失敗...(image-4d05e3-1585821392478)]

我們用上面的函數(shù)來讀取下數(shù)據(jù)特征到向量 X

# 讀取原始數(shù)據(jù),增加第一列全 1 向量
X = get_X(data)

# 輸出數(shù)據(jù)、維度和類型
print(X.shape, type(X))
print(X)

輸出結(jié)果如下:

# 47 行,3 列 = 47 * (2 + 1)
(47, 3) <class 'numpy.ndarray'>

可以看到特征矩陣的第一維列向量全為 1,后兩列不變(數(shù)據(jù)換成科學(xué)計數(shù)法表示),這與我們上面介紹的對多維特征的操作方法結(jié)果相同!

[圖片上傳失敗...(image-2f453e-1585821392478)]

讀取多維特征之后,我們就可以將特征矩陣 X 的每一行作為一個特征向量(就是特征組成的向量 =_=),并用它們來訓(xùn)練機器學(xué)習(xí)算法啦!

以上就是我對多維特征作為機器學(xué)習(xí)算法輸入的一些理解,非常感謝吳恩達(dá)老師的公開課 _。

上面的代碼都在文末我的 Github 倉庫,直接下載就能運行,記得給我個 star 哦!

二、多變量梯度下降法

多維特征讀取后,就可以學(xué)習(xí)多變量梯度下降法了,其實與上一篇博客的單變量梯度下降原理是一樣的,只不過增加了特征變量,相應(yīng)地參數(shù)也就增加了。

比如線性回歸的多變量假設(shè)函數(shù)、代價函數(shù)、梯度下降法分別如下:

  • 假設(shè)函數(shù):

h_{\theta}\left( x \right)=\theta^{T}X={\theta_{0}}+{\theta_{1}}{x_{1}}+{\theta_{2}}{x_{2}}+...+{\theta_{n}}{x_{n}}

  • 代價函數(shù):

J \left( \theta_0, \theta_1 ... \theta_n\right) = \frac{1}{2m}\sum\limits_{i=1}^m \left( h_{\theta}(x^{(i)})-y^{(i)} \right)^{2}

  • 多變量梯度下降法
image

因為參數(shù)增加到 n 個,所以梯度下降的偏導(dǎo)數(shù)也要分別對每個參數(shù)求一次,然后同時更新 n 個參數(shù):

image

比如當(dāng) n>=1 時更新前 3 個參數(shù):

image

我覺得挺好理解的,只需要按照單變量梯度下降的邏輯拓展下變量和參數(shù)的數(shù)量即可,前提一定要完全理解單變量的梯度下降。

那繼續(xù)來看下多變量梯度下降的算法代碼,與單變量梯度下降一毛一樣,先計算偏導(dǎo)數(shù):

# 計算偏導(dǎo)數(shù)
def gradient(theta, X, y):
    m = X.shape[0]
    
    inner = X.T @ (X @ theta - y)
    
    return inner / m

再迭代下降:

# 批量梯度下降
# epoch: 下降迭代次數(shù)
# alpha: 初始學(xué)習(xí)率
def batch_gradient_decent(theta, X, y, epoch, alpha = 0.01):
    # 計算初始成本:theta 都為 0
    cost_data = [lr_cost(theta, X, y)]
    
    # 創(chuàng)建新的 theta 變量,不與原來的混淆
    _theta = theta.copy()
    
    for _ in range(epoch):
        # 新的 theta = 舊的 theta - 學(xué)習(xí)率 * 偏導(dǎo)數(shù)
        _theta = _theta - alpha * gradient(_theta, X, y)
        # 累加成本數(shù)據(jù),用于可視化
        cost_data.append(lr_cost(_theta, X, y))
        
    return _theta, cost_data

來調(diào)用下這個梯度下降函數(shù),初始學(xué)習(xí)率 alpha 設(shè)置為 0.01,迭代 epoch = 500 次:

final_theta, cost_data = batch_gradient_decent(theta, X, y, epoch, alpha = alpha)

這是最終的成本和迭代次數(shù)的曲線,可以看到成本 cost 最終基本趨于不變,說明梯度下降算法收斂啦!

image

話說我之前忘記講解單變量梯度下降的代碼了,下次一定補上!文章內(nèi)的代碼倉庫
https://github.com/DLonng/AI-Notes/blob/master/MachineLearning/code/ex1-linear-regression/multi_feature.ipynb

OK,今天就跟大家分享這些,喜歡的小伙伴記得持續(xù)關(guān)注我哦!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容