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