全面解析并实现逻辑回归(Python)
本文以模型、學(xué)習(xí)目標、優(yōu)化算法的角度解析邏輯回歸(LR)模型,并以Python從頭實現(xiàn)LR訓(xùn)練及預(yù)測。
一、邏輯回歸模型結(jié)構(gòu)
邏輯回歸是一種廣義線性的分類模型且其模型結(jié)構(gòu)可以視為單層的神經(jīng)網(wǎng)絡(luò),由一層輸入層、一層僅帶有一個sigmoid激活函數(shù)的神經(jīng)元的輸出層組成,而無隱藏層。其模型的功能可以簡化成兩步,“通過模型權(quán)重[w]對輸入特征[x]線性求和+sigmoid激活輸出概率”。具體來說,我們輸入數(shù)據(jù)特征x,乘以一一對應(yīng)的模型權(quán)重w后求和,通過輸出層神經(jīng)元激活函數(shù)σ(sigmoid函數(shù))將(wx + b)的計算后非線性轉(zhuǎn)換為0~1區(qū)間的概率數(shù)值后輸出。學(xué)習(xí)訓(xùn)練(優(yōu)化模型權(quán)重)的過程是通過梯度下降學(xué)到合適的模型權(quán)重[W],使得模型輸出值Y=sigmoid(wx + b)與實際值y的誤差最小。
附注:sigmoid函數(shù)是一個s形的曲線,它的輸出值在[0, 1]之間,在遠離0的地方函數(shù)的值會很快接近0或1。對于sigmoid輸出作為概率的合理性,可以參照如下證明:邏輯回歸是一種判別模型,為直接對條件概率P(y|x)建模,假設(shè)P(x|y)是高斯分布,P(y)是多項式分布,如果我們考慮二分類問題,通過公式變換可以得到:可以看到,邏輯回歸(或稱為對數(shù)幾率回歸)的輸出概率和sigmoid形式是一致的。
邏輯回歸模型本質(zhì)上屬于廣義線性分類器(決策邊界為線性)。這點可以從邏輯回歸模型的決策函數(shù)看出,決策函數(shù)Y=sigmoid(wx + b),當(dāng)wx+b>0,Y>0.5;當(dāng)wx+b<0,Y<0.5,以wx+b這條線可以區(qū)分開Y=0或1(如下圖),可見決策邊界是線性的。
二、學(xué)習(xí)目標
邏輯回歸是一個經(jīng)典的分類模型,對于模型預(yù)測我們的目標是:預(yù)測的概率與實際正負樣本的標簽是對應(yīng)的,Sigmoid 函數(shù)的輸出表示當(dāng)前樣本標簽為 1 的概率,y^可以表示為
當(dāng)前樣本預(yù)測為0的概率可以表示為1-y^
對于正樣本y=1,我們期望預(yù)測概率盡量趨近為1 。對于負樣本y=0,期望預(yù)測概率盡量都趨近為0。也就是,我們希望預(yù)測的概率使得下式的概率最大(最大似然法)我們對 P(y|x) 引入 log 函數(shù),因為 log 運算并不會影響函數(shù)本身的單調(diào)性。則有:我們希望 log P(y|x) 越大越好,反過來,只要 log P(y|x) 的負值 -log P(y|x) 越小就行了。那我們就可以引入損失函數(shù),且令 Loss = -log P(y|x),得到損失函數(shù)為:
我們已經(jīng)推導(dǎo)出了單個樣本的損失函數(shù),是如果是計算 m 個樣本的平均的損失函數(shù),只要將 m 個 Loss 疊累加取平均就可以了:
這就在最大似然法推導(dǎo)出的lr的學(xué)習(xí)目標——交叉熵損失(或?qū)?shù)損失函數(shù)),也就是讓最大化使模型預(yù)測概率服從真實值的分布,預(yù)測概率的分布離真實分布越近,模型越好。可以關(guān)注到一個點,如上式邏輯回歸在交叉熵為目標以sigmoid輸出的預(yù)測概率,概率值只能盡量趨近0或1,同理loss也并不會為0。
三、優(yōu)化算法
我們以極小交叉熵為學(xué)習(xí)目標,下面要做的就是,使用優(yōu)化算法去優(yōu)化參數(shù)以達到這個目標。由于最大似然估計下邏輯回歸沒有(最優(yōu))解析解,我們常用梯度下降算法,經(jīng)過多次迭代,最終學(xué)習(xí)到的參數(shù)也就是較優(yōu)的數(shù)值解。梯度下降算法可以直觀理解成一個下山的方法,將損失函數(shù)J(w)比喻成一座山,我們的目標是到達這座山的山腳(即求解出最優(yōu)模型參數(shù)w使得損失函數(shù)為最小值)。
下山要做的無非就是“往下坡的方向走,走一步算一步”,而在損失函數(shù)這座山上,每一位置的下坡的方向也就是它的負梯度方向(直白點,也就是山的斜向下的方向)。在每往下走一步(步長由α控制)到一個位置的時候,求解當(dāng)前位置的梯度,向這一步所在位置沿著最陡峭最易下山的位置再走一步。這樣一步步地走下去,一直走到覺得我們已經(jīng)到了山腳。當(dāng)然這樣走下去,有可能我們不是走到山腳(全局最優(yōu),Global cost minimun),而是到了某一個的小山谷(局部最優(yōu),Local cost minimun),這也梯度下降算法的可進一步優(yōu)化的地方。對應(yīng)的算法步驟:
另外的,以非極大似然估計角度,去求解邏輯回歸(最優(yōu))解析解,可見kexue.fm/archives/8578
四、Python實現(xiàn)邏輯回歸
本項目的數(shù)據(jù)集為癌細胞分類數(shù)據(jù)。基于Python的numpy庫實現(xiàn)邏輯回歸模型,定義目標函數(shù)為交叉熵,使用梯度下降迭代優(yōu)化模型,并驗證分類效果:
#?coding:?utf-8import?numpy?as?np? import?matplotlib.pyplot?as?plt import?h5py import?scipy from?sklearn?import?datasets#?加載數(shù)據(jù)并簡單劃分為訓(xùn)練集/測試集 def?load_dataset():dataset?=?datasets.load_breast_cancer()??train_x,train_y?=?dataset['data'][0:400],?dataset['target'][0:400]test_x,?test_y?=?dataset['data'][400:-1],?dataset['target'][400:-1]return?train_x,?train_y,?test_x,?test_y#?logit激活函數(shù) def?sigmoid(z):s?=?1?/?(1?+?np.exp(-z))????return?s#?權(quán)重初始化0 def?initialize_with_zeros(dim):w?=?np.zeros((dim,?1))b?=?0assert(w.shape?==?(dim,?1))assert(isinstance(b,?float)?or?isinstance(b,?int))return?w,?b#?定義學(xué)習(xí)的目標函數(shù),計算梯度 def?propagate(w,?b,?X,?Y):m?=?X.shape[1]??????A?=?sigmoid(np.dot(w.T,?X)?+?b)?????????#?邏輯回歸輸出預(yù)測值??cost?=?-1?/?m?*??np.sum(Y?*?np.log(A)?+?(1?-?Y)?*?np.log(1?-?A))???#?交叉熵損失為目標函數(shù)dw?=?1?/?m?*?np.dot(X,?(A?-?Y).T)???#?計算權(quán)重w梯度db?=?1?/?m?*?np.sum(A?-?Y)???assert(dw.shape?==?w.shape)assert(db.dtype?==?float)cost?=?np.squeeze(cost)assert(cost.shape?==?())????grads?=?{"dw":?dw,"db":?db}????return?grads,?cost#?定義優(yōu)化算法 def?optimize(w,?b,?X,?Y,?num_iterations,?learning_rate,?print_cost):costs?=?[]????for?i?in?range(num_iterations):????#?梯度下降迭代優(yōu)化grads,?cost?=?propagate(w,?b,?X,?Y)dw?=?grads["dw"]??????????????#?權(quán)重w梯度db?=?grads["db"]w?=?w?-?learning_rate?*?dw???#?按學(xué)習(xí)率(learning_rate)負梯度(dw)方向更新wb?=?b?-?learning_rate?*?dbif?i?%?50?==?0:costs.append(cost)if?print_cost?and?i?%?100?==?0:print?("Cost?after?iteration?%i:?%f"?%(i,?cost))params?=?{"w":?w,"b":?b}grads?=?{"dw":?dw,"db":?db}return?params,?grads,?costs#傳入優(yōu)化后的模型參數(shù)w,b,模型預(yù)測??? def?predict(w,?b,?X):m?=?X.shape[1]Y_prediction?=?np.zeros((1,m))A?=?sigmoid(np.dot(w.T,?X)?+?b)for?i?in?range(A.shape[1]):if?A[0,?i]?<=?0.5:Y_prediction[0,?i]?=?0else:Y_prediction[0,?i]?=?1assert(Y_prediction.shape?==?(1,?m))return?Y_predictiondef?model(X_train,?Y_train,?X_test,?Y_test,?num_iterations,?learning_rate,?print_cost):#?初始化w,?b?=?initialize_with_zeros(X_train.shape[0])?#?梯度下降優(yōu)化模型參數(shù)parameters,?grads,?costs?=?optimize(w,?b,?X_train,?Y_train,?num_iterations,?learning_rate,?print_cost)w?=?parameters["w"]b?=?parameters["b"]#?模型預(yù)測結(jié)果Y_prediction_test?=?predict(w,?b,?X_test)Y_prediction_train?=?predict(w,?b,?X_train)#?模型評估準確率print("train?accuracy:?{}?%".format(100?-?np.mean(np.abs(Y_prediction_train?-?Y_train))?*?100))print("test?accuracy:?{}?%".format(100?-?np.mean(np.abs(Y_prediction_test?-?Y_test))?*?100))????d?=?{"costs":?costs,"Y_prediction_test":?Y_prediction_test,?"Y_prediction_train"?:?Y_prediction_train,?"w"?:?w,?"b"?:?b,"learning_rate"?:?learning_rate,"num_iterations":?num_iterations}????return?d#?加載癌細胞數(shù)據(jù)集 train_set_x,?train_set_y,?test_set_x,?test_set_y?=?load_dataset()???#?reshape train_set_x?=?train_set_x.reshape(train_set_x.shape[0],?-1).T test_set_x?=?test_set_x.reshape(test_set_x.shape[0],?-1).Tprint(train_set_x.shape) print(test_set_x.shape)#訓(xùn)練模型并評估準確率 paras?=?model(train_set_x,?train_set_y,?test_set_x,?test_set_y,?num_iterations?=?100,?learning_rate?=?0.001,?print_cost?=?False)(END)
文章首發(fā)公眾號“算法進階”,文末閱讀原文可訪問文章相關(guān)代碼
往期精彩回顧適合初學(xué)者入門人工智能的路線及資料下載機器學(xué)習(xí)及深度學(xué)習(xí)筆記等資料打印機器學(xué)習(xí)在線手冊深度學(xué)習(xí)筆記專輯《統(tǒng)計學(xué)習(xí)方法》的代碼復(fù)現(xiàn)專輯 AI基礎(chǔ)下載黃海廣老師《機器學(xué)習(xí)課程》視頻課黃海廣老師《機器學(xué)習(xí)課程》711頁完整版課件本站qq群955171419,加入微信群請掃碼:
總結(jié)
以上是生活随笔為你收集整理的全面解析并实现逻辑回归(Python)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jeecg 根据数据类型key查询数据字
- 下一篇: 如何理解面向过程和面向对象?