今天登龍跟大家分享下我對多維特徵的讀取、縮放和多變量梯度下降算法的理解,文章不長,有理論也有實際的代碼,下面開始,Go!
一、如何表示多維特徵?
1.1 特徵縮放
實際項目中在讀取多維特徵之前需要先對數據進行縮放,爲什麼呢?
因爲在有了多維特徵向量和多變量梯度下降法後,爲了幫助算法更快地收斂,還需要對選用的特徵進行尺度縮放,其實就是縮小特徵值,將多個特徵的值都縮小到同樣大小的區間,通常是縮小到 [-1, 1] 周圍。
以下圖爲例:
在沒有進行特徵縮放之前,兩參數梯度下降的等高線圖呈豎的橢圓形,這是因爲橫軸和縱軸參數範圍不同,進而導致算法在尋找最小值時會迭代很多次。
而當進行縮放使得橫縱軸範圍大致相同後,等高線圖基本呈圓形,算法在迭代的時候往一個方向很快就能找到最小值,大大減少迭代次數。
縮放的最終結果不一定非要準確到 [-1, 1],比如 [-3, 3],[-2, 1] 這些範圍不是太大都是可以的,一個又常用有簡單的特徵縮放計算方法是:
其中 是平均值, 是(max - min),比如用這個公式將所有的房屋面積和臥室數量進行縮放:
- ,其中 1000 是面積平均值,2000 是最大面積減最小面積。
- ,其中 2 是臥室數量平均值,5 個最大臥室數量減去最小臥室數量。
理論學會後,再來學習下實際的特徵縮放代碼:
# 特徵縮放
def normalize_feature(df):
# 對原始數據每一列應用一個 lambda 函數,mean() 求每列平均值,std() 求標準差
return df.apply(lambda column: (column - column.mean()) / column.std())
我們用這個函數來實際縮放一下含有 2 個特徵的原始房價數據:
# 讀取原始數據
raw_data = pd.read_csv('ex1data2.txt', names = ['square', 'bedrooms', 'price'])
# 顯示前 5 行
raw_data.head()
# 對原始數據進行特徵縮放
data = normalize_feature(raw_data)
# 顯示縮放後的前 5 行數據
data.head()
可以看到縮放後的數據範圍基本都在 區間左右,說明我們的特徵縮放成功了 _!下面來學習如何讀取多維特徵!
1.2 讀取多維特徵
還記得上篇文章我們介紹的第一個機器學習算法嗎?
即通過房屋面積來預測價格,這個問題中只使用一個輸入特徵房屋面積,可現實生活中要解決的問題通常都含有多個特徵,因爲用多個特徵訓練出的模型準確度更高。
那麼如何機器學習算法如何處理多個特徵的輸入呢?
我們還用預測房價的例子,不過這次要增加另外 3 個特徵,臥室數量,房屋樓層,房屋年齡:
這樣一來,我們就有了 4 個輸入特徵了,特徵多了,表示的方法也要升升級了:
-
:輸入特徵的數量,即特徵矩陣列數,也即特徵向量的維度
-
:訓練集中第 個實例向量,就是特徵矩陣的第 行,比如列向量
-
:訓練集中第 個實例的第 個特徵,比如
特徵數量增加了,之前的假設函數肯定也需要修改,要把增加的特徵變量和參數加上:
雖然這樣表示沒問題,但是卻不方便利用向量來計算,因爲參數 有 n + 1 個,但 只有 n 個,那怎麼辦呢?
很簡單,我們額外增加一個 ,則上式變爲:
這樣一來就可以寫成向量相乘的形式:
你可能要問了爲何要寫成向量的形式?主要因爲 2 點:
- 使用向量方便程序編寫,一句計算特徵向量的代碼就可以同時計算多個輸入參數,因爲一個特徵向量中包含所有輸入參數
- 使用向量方便算法執行,梯度下降算法要求參數同時更新,如果不使用向量,那更新起來非常麻煩。
通過增加一個維度 ,最終訓練集的特徵矩陣的大小爲:,其中 m 爲行數,n + 1 爲列數。
那來看下讀取多維數據並添加一列全 1 向量的函數代碼:
# 讀取原始數據,返回 m * (n + 1) 維特徵矩陣
def get_X(df):
# 創建 m 行 1 列的數據幀
ones = pd.DataFrame({'ones': np.ones(len(df))})
# 合併全 1 向量作爲元素數據第一列,axis = 0 按行合併,anix = 1 按列合併
data = pd.concat([ones, df], axis=1)
# 返回特徵矩陣
return data.iloc[:, :-1].iloc[:, :].values
爲了簡單點,這裏假設原始房價數據只有 2 個輸入特徵,即房屋面積和臥室數量:
我們用上面的函數來讀取下數據特徵到向量 X
:
# 讀取原始數據,增加第一列全 1 向量
X = get_X(data)
# 輸出數據、維度和類型
print(X.shape, type(X))
print(X)
輸出結果如下:
# 47 行,3 列 = 47 * (2 + 1)
(47, 3) <class 'numpy.ndarray'>
可以看到特徵矩陣的第一維列向量全爲 1,後兩列不變(數據換成科學計數法表示),這與我們上面介紹的對多維特徵的操作方法結果相同!
讀取多維特徵之後,我們就可以將特徵矩陣 X
的每一行作爲一個特徵向量(就是特徵組成的向量 =_=),並用它們來訓練機器學習算法啦!
以上就是我對多維特徵作爲機器學習算法輸入的一些理解,非常感謝吳恩達老師的公開課 _。
上面的代碼都在文末我的 Github 倉庫,直接下載就能運行,記得給我個 star 哦!
二、多變量梯度下降法
多維特徵讀取後,就可以學習多變量梯度下降法了,其實與上一篇博客的單變量梯度下降原理是一樣的,只不過增加了特徵變量,相應地參數也就增加了。
比如線性迴歸的多變量假設函數、代價函數、梯度下降法分別如下:
- 假設函數:
- 代價函數:
- 多變量梯度下降法
因爲參數增加到 n 個,所以梯度下降的偏導數也要分別對每個參數求一次,然後同時更新 n 個參數:
比如當 時更新前 3 個參數:
我覺得挺好理解的,只需要按照單變量梯度下降的邏輯拓展下變量和參數的數量即可,前提一定要完全理解單變量的梯度下降。
那繼續來看下多變量梯度下降的算法代碼,與單變量梯度下降一毛一樣,先計算偏導數:
# 計算偏導數
def gradient(theta, X, y):
m = X.shape[0]
inner = X.T @ (X @ theta - y)
return inner / m
再迭代下降:
# 批量梯度下降
# epoch: 下降迭代次數
# alpha: 初始學習率
def batch_gradient_decent(theta, X, y, epoch, alpha = 0.01):
# 計算初始成本:theta 都爲 0
cost_data = [lr_cost(theta, X, y)]
# 創建新的 theta 變量,不與原來的混淆
_theta = theta.copy()
for _ in range(epoch):
# 新的 theta = 舊的 theta - 學習率 * 偏導數
_theta = _theta - alpha * gradient(_theta, X, y)
# 累加成本數據,用於可視化
cost_data.append(lr_cost(_theta, X, y))
return _theta, cost_data
來調用下這個梯度下降函數,初始學習率 alpha
設置爲 0.01,迭代 epoch = 500
次:
final_theta, cost_data = batch_gradient_decent(theta, X, y, epoch, alpha = alpha)
這是最終的成本和迭代次數的曲線,可以看到成本 cost 最終基本趨於不變,說明梯度下降算法收斂啦!
話說我之前忘記講解單變量梯度下降的代碼了,下次一定補上!文章內的代碼倉庫:
AI-Notes
OK,今天就跟大家分享這些,喜歡的小夥伴記得關注下面的公衆號,持續關注我哦!
本文原創首發於 同名微信公號「登龍」,微信搜索關注回覆「1024」你懂的!