python 怎么算l2范数_数学推导+纯Python实现机器学习算法13:Lasso回归
版權說明:本公號轉載文章旨在學習交流,不用于任何商業用途,版權歸原作者所有,如有異議,敬請后臺聯絡我們,議定合作或刪除,我們將第一時間按版權法規定妥善處理,非常感謝!
Python機器學習算法實現
Author:louwill
本節我們要介紹的是基于L1正則化的Lasso模型,下一節介紹基于L2正則化的Ridge模型。在正式介紹這兩種模型之前,筆者還是想帶大家復習一下過擬合和正則化等機器學習關鍵問題。
正則化與L1范數
?????正則化是防止模型過擬合的核心技術之一,關于欠擬合和過擬合的問題,這里筆者就不再展開來說,不了解的朋友可以看看筆者很早之前寫的一篇文章:談談過擬合。
?????總的來說,監督機器學習的核心原理莫過于如下公式:
????? 該公式可謂是機器學習中最核心最關鍵最能概述監督學習的核心思想的公式了:所有的有監督機器學習,無非就是正則化參數的同時最小化經驗誤差函數。最小化經驗誤差是為了極大程度的擬合訓練數據,正則化參數是為了防止過分的擬合訓練數據。你看,多么簡約數學哲學。正如之前所說,監督機器學習是為了讓我們建立的模型能夠發現數據中普遍的一般的規律,這個普遍的一般的規律無論對于訓練集還是未知的測試集,都具有較好的擬合性能。
????? 繼續回到公式。第一項經驗誤差函數在機器學習中無疑地位重要,但它不是筆者今天要講的,今天要講的是公式的第二項:正則化項。第二項中 λ 為正則化系數,通常是大于 0 的,是一種調整經驗誤差項和正則化項之間關系的系數。λ = 0 時相當于該公式沒有正則化項,模型全力討好第一項,將經驗誤差進行最小化,往往這也是最容易發生過擬合的時候。隨著 λ 逐漸增大,正則化項在模型選擇中的話語權越來越高,對模型的復雜性的懲罰也越來越厲害。所以,在實際的訓練過程中,λ 作為一種超參數很大程度上決定了模型生死。
???? 系數 λ 說完了,然后就是正則化項,正則化項形式有很多,但常見的也就是 L1 和 L2 正則化。本節我們先來看L1。
????? 在說常見的 L1 和 L2 之前,先來看一下 L0 正則化。L0 正則化也就是 L0 范數,即矩陣中所有非 0 元素的個數。如何我們在正則化過程中選擇了 L0 范數,那該如何理解這個 L0 呢?其實非常簡單,L0 范數就是希望要正則化的參數矩陣 W 大多數元素都為 0。如此簡單粗暴,讓參數矩陣 W 大多數元素為 0 就是實現稀疏而已。說到這里,權且打住,想必同樣在機器學習領域摸爬滾打的你一定想問,據我所知稀疏性不通常都是用 L1 來實現的嗎?這里個中緣由筆者不去細講了,簡單說結論:在機器學習領域,L0 和 L1 都可以實現矩陣的稀疏性,但在實踐中,L1 要比 L0 具備更好的泛化求解特性而廣受青睞。先說了 L1,但還沒解釋 L1 范數是什么,L1 范數就是矩陣中各元素絕對值之和,正如前述所言,L1 范數通常用于實現參數矩陣的稀疏性。至于為啥要稀疏,稀疏有什么用,通常是為了特征選擇和易于解釋方面的考慮。
Lasso
? ? ?Lasso的全稱叫做Least absolute shrinkage and selection operator,直譯過來為最小收縮與選擇算子。其本質就是在常規的線性回歸的基礎上對參數加了一個L1正則化約束。其形式如下所示:
???? 規約到線性回歸模型上,上式的第一項就是MSE損失,第二項則是L1正則化項。我們同樣按照之前線性回歸的打法來對其進行實現,只是需要注意一下L1正則化項的求導處理。我們來看具體的實現代碼。
導入相關package并讀入示例數據:
import numpy as npimport pandas as pddata?=?np.genfromtxt('mystery.dat',?delimiter?=?',')# 選擇特征與標簽x = data[:,0:100] y = data[:,100].reshape(-1,1)# 加一列X = np.column_stack((np.ones((x.shape[0],1)),x))# 劃分訓練集與測試集X_train, y_train = X[:70], y[:70]X_test, y_test = X[70:], y[70:]print(X_train.shape,?y_train.shape,?X_test.shape,?y_test.shape)定義參數初始化函數:
# 定義參數初始化函數def initialize(dims): w = np.zeros((dims, 1)) b = 0 return w, b定義符號函數并進行向量化,用于對L1正則化項的梯度計算:
# 定義符號函數def sign(x): if x > 0: return 1 elif x < 0: return -1 else: return 0?# 利用numpy對符號函數進行向量化vec_sign = np.vectorize(sign)vec_sign(np.zeros((3,1)))?在MSE損失函數的基礎上定義Lasso損失:
# 定義lasso損失函數def l1_loss(X, y, w, b, alpha): num_train = X.shape[0] num_feature = X.shape[1] y_hat = np.dot(X, w) + b loss = np.sum((y_hat-y)**2)/num_train + np.sum(alpha*abs(w)) dw = np.dot(X.T, (y_hat-y)) /num_train + alpha * vec_sign(w) db = np.sum((y_hat-y)) /num_train return y_hat, loss, dw, db定義Lasso訓練過程函數:
# 定義訓練過程def lasso_train(X, y, learning_rate=0.01, epochs=300): loss_list = [] w, b = initialize(X.shape[1]) for i in range(1, epochs): y_hat, loss, dw, db = l1_loss(X, y, w, b, 0.1) w += -learning_rate * dw b += -learning_rate * db loss_list.append(loss) if i % 50 == 0: print('epoch %d loss %f' % (i, loss)) params = { 'w': w, 'b': b } grads = { 'dw': dw, 'db': db } return loss, loss_list, params, grads執行訓練:
# 執行訓練示例loss, loss_list, params, grads = lasso_train(X_train, y_train, 0.01, 500)可以看到,在L1的約束下,在訓練過程中有不少對標簽貢獻率低的特征的系數都變成了0。這就是L1的作用,一定程度上可以進行特征選擇和實現稀疏化。
最后可以簡單寫一個Lasso回歸的class來對上述過程進行封裝:
import numpy as npfrom sklearn.metrics import r2_scoreclass Lasso(): def __init__(self): pass def prepare_data(self): data = np.genfromtxt('./example.dat', delimiter = ',') x = data[:, 0:100] y = data[:, 100].reshape(-1, 1) X = np.column_stack((np.ones((x.shape[0], 1)), x)) X_train, y_train = X[:70], y[:70] X_test, y_test = X[70:], y[70:] return X_train, y_train, X_test, y_test def initialize_params(self, dims): w = np.zeros((dims, 1)) b = 0 return w, b def sign(self, x): if x > 0: return 1 elif x < 0: return -1 else: return 0???????? def l1_loss(self, X, y, w, b, alpha): num_train = X.shape[0] num_feature = X.shape[1] y_hat = np.dot(X, w) + b loss = np.sum((y_hat - y) ** 2) / num_train + np.sum(alpha*abs(w)) dw = np.dot(X.T, (y_hat - y)) / num_train + alpha*np.vectorize(self.sign)(w) db = np.sum((y_hat - y)) / num_train return y_hat, loss, dw, db def lasso_train(self, X, y, learning_rate, epochs): loss_list = [] w, b = self.initialize_params(X.shape[1]) for i in range(1, epochs): y_hat, loss, dw, db = self.l1_loss(X, y, w, b, 0.1) w += -learning_rate * dw b += -learning_rate * db loss_list.append(loss) if i % 300 == 0: print('epoch %d loss %f' % (i, loss)) params = { 'w': w, 'b': b } grads = { 'dw': dw, 'db': db } return loss, loss_list, params, grads def predict(self, X, params): w = params['w'] b = params['b'] y_pred = np.dot(X, w) + b return y_pred????if __name__ == '__main__': lasso = Lasso() X_train, y_train, X_test, y_test = lasso.prepare_data() loss, loss_list, params, grads = lasso.lasso_train(X_train, y_train, 0.01, 3000) print(params) y_pred = lasso.predict(X_test, params) print(r2_score(y_test, y_pred))以上是基于numpy的手動實現Lasso的過程,下面再來看Lasso在sklearn中的實現。
# 導入線性模型模塊from sklearn import linear_model# 創建lasso模型實例sk_lasso = linear_model.Lasso(alpha=0.1)# 對訓練集進行擬合sk_lasso.fit(X_train, y_train)# 打印模型相關系數print("sklearn Lasso intercept :", sk_lasso.intercept_)print("\nsklearn Lasso coefficients :\n", sk_lasso.coef_)print("\nsklearn Lasso number of iterations :", sk_lasso.n_iter_)以上就是本節內容,下一節我們繼續來看基于L2正則化的Ridge回歸。
更多內容可參考筆者GitHub地址:
https://github.com/luwill/machine-learning-code-writing
參考資料:
https://www.analyticsvidhya.com/blog/2017/06/a-comprehensive-guide-for-linear-ridge-and-lasso-regression/
總結
以上是生活随笔為你收集整理的python 怎么算l2范数_数学推导+纯Python实现机器学习算法13:Lasso回归的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: matlab批量修改txt内容_MATL
- 下一篇: python亲密度_Python Ope