收藏!!如何 Get 机器学习必备的算法技能? | 逻辑回归
本文是吳恩達老師的機器學習課程[1]的筆記和代碼復現部分(邏輯回歸)。
作者:黃海廣[2]
備注:筆記和作業(含數據、原始作業文件)、視頻都在github[3]中下載。
我將陸續將課程筆記和課程代碼發布在公眾號“機器學習初學者”,敬請關注。這個是第二部分:邏輯回歸,是原教程的第三周,包含了筆記和作業代碼(原課程作業是 OCTAVE 的,這里是復現的 python 代碼)
第一部分:回歸代碼
本文作業代碼[4]可以下載完整版
筆記的markdown 文件[5]
筆記的pdf 文件[6]
筆記部分目錄
六、邏輯回歸(Logistic Regression)
6.1 分類問題
6.2 假說表示
6.3 判定邊界
6.4 代價函數
6.5 簡化的成本函數和梯度下降
6.6 高級優化
6.7 多類別分類:一對多
七、正則化(Regularization)
7.1 過擬合的問題
7.2 代價函數
7.3 正則化線性回歸
7.4 正則化的邏輯回歸模型
六、邏輯回歸(Logistic Regression)
6.1 分類問題
參考文檔: 6 - 1 - Classification (8 min).mkv
在這個以及接下來的幾個視頻中,開始介紹分類問題。
在分類問題中,你要預測的變量??是離散的值,我們將學習一種叫做邏輯回歸 (Logistic Regression) 的算法,這是目前最流行使用最廣泛的一種學習算法。
在分類問題中,我們嘗試預測的是結果是否屬于某一個類(例如正確或錯誤)。分類問題的例子有:判斷一封電子郵件是否是垃圾郵件;判斷一次金融交易是否是欺詐;之前我們也談到了腫瘤分類問題的例子,區別一個腫瘤是惡性的還是良性的。
我們從二元的分類問題開始討論。
我們將因變量(dependent variable)可能屬于的兩個類分別稱為負向類(negative class)和正向類(positive class),則因變量?,其中 0 表示負向類,1 表示正向類。
如果我們要用線性回歸算法來解決一個分類問題,對于分類,??取值為 0 或者 1,但如果你使用的是線性回歸,那么假設函數的輸出值可能遠大于 1,或者遠小于 0,即使所有訓練樣本的標簽??都等于 0 或 1。盡管我們知道標簽應該取值 0 或者 1,但是如果算法得到的值遠大于 1 或者遠小于 0 的話,就會感覺很奇怪。所以我們在接下來的要研究的算法就叫做邏輯回歸算法,這個算法的性質是:它的輸出值永遠在 0 到 1 之間。
順便說一下,邏輯回歸算法是分類算法,我們將它作為分類算法使用。有時候可能因為這個算法的名字中出現了“回歸”使你感到困惑,但邏輯回歸算法實際上是一種分類算法,它適用于標簽??取值離散的情況,如:1 0 0 1。
在接下來的視頻中,我們將開始學習邏輯回歸算法的細節。
6.2 假說表示
參考視頻: 6 - 2 - Hypothesis Representation (7 min).mkv
在這段視頻中,我要給你展示假設函數的表達式,也就是說,在分類問題中,要用什么樣的函數來表示我們的假設。此前我們說過,希望我們的分類器的輸出值在 0 和 1 之間,因此,我們希望想出一個滿足某個性質的假設函數,這個性質是它的預測值要在 0 和 1 之間。
回顧在一開始提到的乳腺癌分類問題,我們可以用線性回歸的方法求出適合數據的一條直線:
根據線性回歸模型我們只能預測連續的值,然而對于分類問題,我們需要輸出 0 或 1,我們可以預測:
當時,預測?。
當時,預測??。
對于上圖所示的數據,這樣的一個線性模型似乎能很好地完成分類任務。假使我們又觀測到一個非常大尺寸的惡性腫瘤,將其作為實例加入到我們的訓練集中來,這將使得我們獲得一條新的直線。
這時,再使用 0.5 作為閥值來預測腫瘤是良性還是惡性便不合適了。可以看出,線性回歸模型,因為其預測的值可以超越[0,1]的范圍,并不適合解決這樣的問題。
我們引入一個新的模型,邏輯回歸,該模型的輸出變量范圍始終在 0 和 1 之間。邏輯回歸模型的假設是:??其中:??代表特征向量??代表邏輯函數(logistic function)是一個常用的邏輯函數為S形函數(Sigmoid function),公式為:?。
python代碼實現:
import numpy as npdef sigmoid(z):return 1 / (1 + np.exp(-z))該函數的圖像為:
合起來,我們得到邏輯回歸模型的假設:
對模型的理解:?。
的作用是,對于給定的輸入變量,根據選擇的參數計算輸出變量=1 的可能性(estimated probablity)即?例如,如果對于給定的,通過已經確定的參數計算得出,則表示有 70%的幾率為正向類,相應地為負向類的幾率為 1-0.7=0.3。
6.3 判定邊界
參考視頻: 6 - 3 - Decision Boundary (15 min).mkv
現在講下決策邊界(decision boundary)的概念。這個概念能更好地幫助我們理解邏輯回歸的假設函數在計算什么。
在邏輯回歸中,我們預測:
當時,預測?。
當時,預測??。
根據上面繪制出的 S 形函數圖像,我們知道當
?時?
?時?
?時?
又??,即:??時,預測???時,預測?
現在假設我們有一個模型:
并且參數?是向量[-3 1 1]。則當,即時,模型將預測?。我們可以繪制直線,這條線便是我們模型的分界線,將預測為 1 的區域和預測為 0 的區域分隔開。
假使我們的數據呈現這樣的分布情況,怎樣的模型才能適合呢?
因為需要用曲線才能分隔??的區域和??的區域,我們需要二次方特征:是[-1 0 0 1 1],則我們得到的判定邊界恰好是圓點在原點且半徑為 1 的圓形。
我們可以用非常復雜的模型來適應非常復雜形狀的判定邊界。
6.4 代價函數
參考視頻: 6 - 4 - Cost Function (11 min).mkv
在這段視頻中,我們要介紹如何擬合邏輯回歸模型的參數。具體來說,我要定義用來擬合參數的優化目標或者叫代價函數,這便是監督學習問題中的邏輯回歸模型的擬合問題。
對于線性回歸模型,我們定義的代價函數是所有模型誤差的平方和。理論上來說,我們也可以對邏輯回歸模型沿用這個定義,但是問題在于,當我們將帶入到這樣定義了的代價函數中時,我們得到的代價函數將是一個非凸函數(non-convexfunction)。
這意味著我們的代價函數有許多局部最小值,這將影響梯度下降算法尋找全局最小值。
線性回歸的代價函數為:?。我們重新定義邏輯回歸的代價函數為:,其中
與?之間的關系如下圖所示:
這樣構建的函數的特點是:當實際的??且也為 1 時誤差為 0,當??但不為 1 時誤差隨著變小而變大;當實際的??且也為 0 時代價為 0,當?但不為 0 時誤差隨著?的變大而變大。將構建的?簡化如下:??帶入代價函數得到:??即:
Python代碼實現:
import?numpy?as?np def cost(theta, X, y):theta?=?np.matrix(theta)X = np.matrix(X)y = np.matrix(y)first = np.multiply(-y, np.log(sigmoid(X* theta.T)))second = np.multiply((1 - y), np.log(1 - sigmoid(X* theta.T)))return np.sum(first - second) / (len(X))在得到這樣一個代價函數以后,我們便可以用梯度下降算法來求得能使代價函數最小的參數了。算法為:
Repeat {??(simultaneously update all ) }
求導后得到:
Repeat {??(simultaneously update all ) }
在這個視頻中,我們定義了單訓練樣本的代價函數,凸性分析的內容是超出這門課的范圍的,但是可以證明我們所選的代價值函數會給我們一個凸優化問題。代價函數會是一個凸函數,并且沒有局部最優值。
推導過程:
?考慮:??則:???
所以:?????????
注:雖然得到的梯度下降算法表面上看上去與線性回歸的梯度下降算法一樣,但是這里的與線性回歸中不同,所以實際上是不一樣的。另外,在運行梯度下降算法之前,進行特征縮放依舊是非常必要的。
一些梯度下降算法之外的選擇:除了梯度下降算法以外,還有一些常被用來令代價函數最小的算法,這些算法更加復雜和優越,而且通常不需要人工選擇學習率,通常比梯度下降算法要更加快速。這些算法有:共軛梯度(Conjugate Gradient),局部優化法(Broyden fletcher goldfarb shann,BFGS)和有限內存局部優化法(LBFGS) 。
6.5 簡化的成本函數和梯度下降
參考視頻: 6 - 5 - Simplified Cost Function and Gradient Descent (10 min).mkv
在這段視頻中,我們將會找出一種稍微簡單一點的方法來寫代價函數,來替換我們現在用的方法。同時我們還要弄清楚如何運用梯度下降法,來擬合出邏輯回歸的參數。因此,聽了這節課,你就應該知道如何實現一個完整的邏輯回歸算法。
這就是邏輯回歸的代價函數:
這個式子可以合并成:
?
即,邏輯回歸的代價函數:???
根據這個代價函數,為了擬合出參數,該怎么做呢?我們要試圖找盡量讓?取得最小值的參數。??所以我們想要盡量減小這一項,這將我們將得到某個參數。如果我們給出一個新的樣本,假如某個特征?,我們可以用擬合訓練樣本的參數,來輸出對假設的預測。另外,我們假設的輸出,實際上就是這個概率值:,就是關于?以為參數,?的概率,你可以認為我們的假設就是估計??的概率,所以,接下來就是弄清楚如何最大限度地最小化代價函數,作為一個關于的函數,這樣我們才能為訓練集擬合出參數。
最小化代價函數的方法,是使用梯度下降法(gradient descent)。這是我們的代價函數:
?
如果我們要最小化這個關于的函數值,這就是我們通常用的梯度下降法的模板。
我們要反復更新每個參數,用這個式子來更新,就是用它自己減去學習率??乘以后面的微分項。求導后得到:
如果你計算一下的話,你會得到這個等式:??我把它寫在這里,將后面這個式子,在??到??上求和,其實就是預測誤差乘以?,所以你把這個偏導數項放回到原來式子這里,我們就可以將梯度下降算法寫作如下形式:?
所以,如果你有??個特征,也就是說:,參數向量包括???一直到,那么你就需要用這個式子:
來同時更新所有的值。
現在,如果你把這個更新規則和我們之前用在線性回歸上的進行比較的話,你會驚訝地發現,這個式子正是我們用來做線性回歸梯度下降的。
那么,線性回歸和邏輯回歸是同一個算法嗎?要回答這個問題,我們要觀察邏輯回歸看看發生了哪些變化。實際上,假設的定義發生了變化。
對于線性回歸假設函數:
而現在邏輯函數假設函數:
因此,即使更新參數的規則看起來基本相同,但由于假設的定義發生了變化,所以邏輯函數的梯度下降,跟線性回歸的梯度下降實際上是兩個完全不同的東西。
在先前的視頻中,當我們在談論線性回歸的梯度下降法時,我們談到了如何監控梯度下降法以確保其收斂,我通常也把同樣的方法用在邏輯回歸中,來監測梯度下降,以確保它正常收斂。
當使用梯度下降法來實現邏輯回歸時,我們有這些不同的參數,就是???一直到,我們需要用這個表達式來更新這些參數。我們還可以使用 for 循環來更新這些參數值,用 for i=1 to n,或者 for i=1 to n+1。當然,不用 for 循環也是可以的,理想情況下,我們更提倡使用向量化的實現,可以把所有這些?個參數同時更新。
最后還有一點,我們之前在談線性回歸時講到的特征縮放,我們看到了特征縮放是如何提高梯度下降的收斂速度的,這個特征縮放的方法,也適用于邏輯回歸。如果你的特征范圍差距很大的話,那么應用特征縮放的方法,同樣也可以讓邏輯回歸中,梯度下降收斂更快。
就是這樣,現在你知道如何實現邏輯回歸,這是一種非常強大,甚至可能世界上使用最廣泛的一種分類算法。
6.6 高級優化
參考視頻: 6 - 6 - Advanced Optimization (14 min).mkv
在上一個視頻中,我們討論了用梯度下降的方法最小化邏輯回歸中代價函數。在本次視頻中,我會教你們一些高級優化算法和一些高級的優化概念,利用這些方法,我們就能夠使通過梯度下降,進行邏輯回歸的速度大大提高,而這也將使算法更加適合解決大型的機器學習問題,比如,我們有數目龐大的特征量。現在我們換個角度來看什么是梯度下降,我們有個代價函數,而我們想要使其最小化,那么我們需要做的是編寫代碼,當輸入參數??時,它們會計算出兩樣東西:?以及?等于 0、1 直到??時的偏導數項。
假設我們已經完成了可以實現這兩件事的代碼,那么梯度下降所做的就是反復執行這些更新。另一種考慮梯度下降的思路是:我們需要寫出代碼來計算?和這些偏導數,然后把這些插入到梯度下降中,然后它就可以為我們最小化這個函數。對于梯度下降來說,我認為從技術上講,你實際并不需要編寫代碼來計算代價函數。你只需要編寫代碼來計算導數項,但是,如果你希望代碼還要能夠監控這些?的收斂性,那么我們就需要自己編寫代碼來計算代價函數和偏導數項。所以,在寫完能夠計算這兩者的代碼之后,我們就可以使用梯度下降。然而梯度下降并不是我們可以使用的唯一算法,還有其他一些算法,更高級、更復雜。如果我們能用這些方法來計算代價函數和偏導數項兩個項的話,那么這些算法就是為我們優化代價函數的不同方法,共軛梯度法 BFGS (變尺度法) 和L-BFGS (限制變尺度法) 就是其中一些更高級的優化算法,它們需要有一種方法來計算?,以及需要一種方法計算導數項,然后使用比梯度下降更復雜的算法來最小化代價函數。這三種算法的具體細節超出了本門課程的范疇。實際上你最后通常會花費很多天,或幾周時間研究這些算法,你可以專門學一門課來提高數值計算能力,不過讓我來告訴你他們的一些特性:
這三種算法有許多優點:
一個是使用這其中任何一個算法,你通常不需要手動選擇學習率?,所以對于這些算法的一種思路是,給出計算導數項和代價函數的方法,你可以認為算法有一個智能的內部循環,而且,事實上,他們確實有一個智能的內部循環,稱為線性搜索(line search)算法,它可以自動嘗試不同的學習速率?,并自動選擇一個好的學習速率?,因此它甚至可以為每次迭代選擇不同的學習速率,那么你就不需要自己選擇。這些算法實際上在做更復雜的事情,不僅僅是選擇一個好的學習速率,所以它們往往最終比梯度下降收斂得快多了,不過關于它們到底做什么的詳細討論,已經超過了本門課程的范圍。
這部分略
我希望你們從這個幻燈片中學到的主要內容是:寫一個函數,它能返回代價函數值、梯度值,因此要把這個應用到邏輯回歸,或者甚至線性回歸中,你也可以把這些優化算法用于線性回歸,你需要做的就是輸入合適的代碼來計算這里的這些東西。
現在你已經知道如何使用這些高級的優化算法,有了這些算法,你就可以使用一個復雜的優化庫,它讓算法使用起來更模糊一點。因此也許稍微有點難調試,不過由于這些算法的運行速度通常遠遠超過梯度下降。
所以當我有一個很大的機器學習問題時,我會選擇這些高級算法,而不是梯度下降。有了這些概念,你就應該能將邏輯回歸和線性回歸應用于更大的問題中,這就是高級優化的概念。
在下一個視頻,我想要告訴你如何修改你已經知道的邏輯回歸算法,然后使它在多類別分類問題中也能正常運行。
6.7 多類別分類:一對多
參考視頻: 6 - 7 - Multiclass Classification_ One-vs-all (6 min).mkv
在本節視頻中,我們將談到如何使用邏輯回歸 (logistic regression)來解決多類別分類問題,具體來說,我想通過一個叫做"一對多" (one-vs-all) 的分類算法。
先看這樣一些例子。
第一個例子:假如說你現在需要一個學習算法能自動地將郵件歸類到不同的文件夾里,或者說可以自動地加上標簽,那么,你也許需要一些不同的文件夾,或者不同的標簽來完成這件事,來區分開來自工作的郵件、來自朋友的郵件、來自家人的郵件或者是有關興趣愛好的郵件,那么,我們就有了這樣一個分類問題:其類別有四個,分別用、、、?來代表。
第二個例子是有關藥物診斷的,如果一個病人因為鼻塞來到你的診所,他可能并沒有生病,用??這個類別來代表;或者患了感冒,用??來代表;或者得了流感用來代表。
第三個例子:如果你正在做有關天氣的機器學習分類問題,那么你可能想要區分哪些天是晴天、多云、雨天、或者下雪天,對上述所有的例子,?可以取一個很小的數值,一個相對"謹慎"的數值,比如 1 到 3、1 到 4 或者其它數值,以上說的都是多類分類問題,順便一提的是,對于下標是 0 1 2 3,還是 1 2 3 4 都不重要,我更喜歡將分類從 1 開始標而不是 0,其實怎樣標注都不會影響最后的結果。
然而對于之前的一個,二元分類問題,我們的數據看起來可能是像這樣:
對于一個多類分類問題,我們的數據集或許看起來像這樣:
我用 3 種不同的符號來代表 3 個類別,問題就是給出 3 個類型的數據集,我們如何得到一個學習算法來進行分類呢?
我們現在已經知道如何進行二元分類,可以使用邏輯回歸,對于直線或許你也知道,可以將數據集一分為二為正類和負類。用一對多的分類思想,我們可以將其用在多類分類問題上。
下面將介紹如何進行一對多的分類工作,有時這個方法也被稱為"一對余"方法。
現在我們有一個訓練集,好比上圖表示的有 3 個類別,我們用三角形表示?,方框表示,叉叉表示?。我們下面要做的就是使用一個訓練集,將其分成 3 個二元分類問題。
我們先從用三角形代表的類別 1 開始,實際上我們可以創建一個,新的"偽"訓練集,類型 2 和類型 3 定為負類,類型 1 設定為正類,我們創建一個新的訓練集,如下圖所示的那樣,我們要擬合出一個合適的分類器。
這里的三角形是正樣本,而圓形代表負樣本。可以這樣想,設置三角形的值為 1,圓形的值為 0,下面我們來訓練一個標準的邏輯回歸分類器,這樣我們就得到一個正邊界。
為了能實現這樣的轉變,我們將多個類中的一個類標記為正向類(),然后將其他所有類都標記為負向類,這個模型記作。接著,類似地第我們選擇另一個類標記為正向類(),再將其它類都標記為負向類,將這個模型記作?,依此類推。最后我們得到一系列的模型簡記為:?其中:
最后,在我們需要做預測時,我們將所有的分類機都運行一遍,然后對每一個輸入變量,都選擇最高可能性的輸出變量。
總之,我們已經把要做的做完了,現在要做的就是訓練這個邏輯回歸分類器:, 其中??對應每一個可能的?,最后,為了做出預測,我們給出輸入一個新的??值,用這個做預測。我們要做的就是在我們三個分類器里面輸入?,然后我們選擇一個讓??最大的,即。
你現在知道了基本的挑選分類器的方法,選擇出哪一個分類器是可信度最高效果最好的,那么就可認為得到一個正確的分類,無論值是多少,我們都有最高的概率值,我們預測就是那個值。這就是多類別分類問題,以及一對多的方法,通過這個小方法,你現在也可以將邏輯回歸分類器用在多類分類的問題上。
七、正則化(Regularization)
7.1 過擬合的問題
參考視頻: 7 - 1 - The Problem of Overfitting (10 min).mkv
到現在為止,我們已經學習了幾種不同的學習算法,包括線性回歸和邏輯回歸,它們能夠有效地解決許多問題,但是當將它們應用到某些特定的機器學習應用時,會遇到過擬合(over-fitting)的問題,可能會導致它們效果很差。
在這段視頻中,我將為你解釋什么是過度擬合問題,并且在此之后接下來的幾個視頻中,我們將談論一種稱為正則化(regularization)的技術,它可以改善或者減少過度擬合問題。
如果我們有非常多的特征,我們通過學習得到的假設可能能夠非常好地適應訓練集(代價函數可能幾乎為 0),但是可能會不能推廣到新的數據。
下圖是一個回歸問題的例子:
第一個模型是一個線性模型,欠擬合,不能很好地適應我們的訓練集;第三個模型是一個四次方的模型,過于強調擬合原始數據,而丟失了算法的本質:預測新數據。我們可以看出,若給出一個新的值使之預測,它將表現的很差,是過擬合,雖然能非常好地適應我們的訓練集但在新輸入變量進行預測時可能會效果不好;而中間的模型似乎最合適。
分類問題中也存在這樣的問題:
就以多項式理解,?的次數越高,擬合的越好,但相應的預測的能力就可能變差。
問題是,如果我們發現了過擬合問題,應該如何處理?
丟棄一些不能幫助我們正確預測的特征。可以是手工選擇保留哪些特征,或者使用一些模型選擇的算法來幫忙(例如PCA)
正則化。保留所有的特征,但是減少參數的大小(magnitude)。
7.2 代價函數
參考視頻: 7 - 2 - Cost Function (10 min).mkv
上面的回歸問題中如果我們的模型是:??我們可以從之前的事例中看出,正是那些高次項導致了過擬合的產生,所以如果我們能讓這些高次項的系數接近于 0 的話,我們就能很好的擬合了。所以我們要做的就是在一定程度上減小這些參數?的值,這就是正則化的基本方法。我們決定要減少和的大小,我們要做的便是修改代價函數,在其中和?設置一點懲罰。這樣做的話,我們在嘗試最小化代價時也需要將這個懲罰納入考慮中,并最終導致選擇較小一些的和。修改后的代價函數如下:
通過這樣的代價函數選擇出的和?對預測結果的影響就比之前要小許多。假如我們有非常多的特征,我們并不知道其中哪些特征我們要懲罰,我們將對所有的特征進行懲罰,并且讓代價函數最優化的軟件來選擇這些懲罰的程度。這樣的結果是得到了一個較為簡單的能防止過擬合問題的假設:
其中又稱為正則化參數(**Regularization Parameter**)。注:根據慣例,我們不對?進行懲罰。經過正則化處理的模型與原模型的可能對比如下圖所示:
如果選擇的正則化參數?過大,則會把所有的參數都最小化了,導致模型變成?,也就是上圖中紅色直線所示的情況,造成欠擬合。那為什么增加的一項?可以使的值減小呢?因為如果我們令??的值很大的話,為了使Cost Function 盡可能的小,所有的??的值(不包括)都會在一定程度上減小。但若?的值太大了,那么(不包括)都會趨近于 0,這樣我們所得到的只能是一條平行于軸的直線。所以對于正則化,我們要取一個合理的??的值,這樣才能更好的應用正則化。回顧一下代價函數,為了使用正則化,讓我們把這些概念應用到到線性回歸和邏輯回歸中去,那么我們就可以讓他們避免過度擬合了。
7.3 正則化線性回歸
參考視頻: 7 - 3 - Regularized Linear Regression (11 min).mkv
對于線性回歸的求解,我們之前推導了兩種學習算法:一種基于梯度下降,一種基于正規方程。
正則化線性回歸的代價函數為:
如果我們要使用梯度下降法令這個代價函數最小化,因為我們未對進行正則化,所以梯度下降算法將分兩種情形:
??{
?
?
??
}
對上面的算法中?時的更新式子進行調整可得:
?可以看出,正則化線性回歸的梯度下降算法的變化在于,每次都在原有算法更新規則的基礎上令值減少了一個額外的值。
我們同樣也可以利用正規方程來求解正則化線性回歸模型,方法如下所示:
圖中的矩陣尺寸為?。
7.4 正則化的邏輯回歸模型
參考視頻: 7 - 4 - Regularized Logistic Regression (9 min).mkv
針對邏輯回歸問題,我們在之前的課程已經學習過兩種優化算法:我們首先學習了使用梯度下降法來優化代價函數,接下來學習了更高級的優化算法,這些高級優化算法需要你自己設計代價函數。
自己計算導數同樣對于邏輯回歸,我們也給代價函數增加一個正則化的表達式,得到代價函數:
Python代碼:
import numpy as npdef costReg(theta, X, y, learningRate):theta = np.matrix(theta)X = np.matrix(X)y = np.matrix(y)first = np.multiply(-y, np.log(sigmoid(X*theta.T)))second = np.multiply((1 - y), np.log(1 - sigmoid(X*theta.T)))reg = (learningRate / (2 * len(X))* np.sum(np.power(theta[:,1:theta.shape[1]],2))return np.sum(first - second) / (len(X)) + reg要最小化該代價函數,通過求導,得出梯度下降算法為:
??{
?
?
??
}
注:看上去同線性回歸一樣,但是知道?,所以與線性回歸不同。Octave 中,我們依舊可以用 fminuc 函數來求解代價函數最小化的參數,值得注意的是參數的更新規則與其他情況不同。注意:
雖然正則化的邏輯回歸中的梯度下降和正則化的線性回歸中的表達式看起來一樣,但由于兩者的不同所以還是有很大差別。
不參與其中的任何一個正則化。
目前大家對機器學習算法可能還只是略懂,但是一旦你精通了線性回歸、高級優化算法和正則化技術,坦率地說,你對機器學習的理解可能已經比許多工程師深入了。現在,你已經有了豐富的機器學習知識,目測比那些硅谷工程師還厲害,或者用機器學習算法來做產品。
接下來的課程中,我們將學習一個非常強大的非線性分類器,無論是線性回歸問題,還是邏輯回歸問題,都可以構造多項式來解決。你將逐漸發現還有更強大的非線性分類器,可以用來解決多項式回歸問題。我們接下來將將學會,比現在解決問題的方法強大 N 倍的學習算法。
代碼部分
機器學習練習 2 - 邏輯回歸
這個筆記包含了以 Python 為編程語言的 Coursera 上機器學習的第二次編程練習。請參考?作業文件[1]?詳細描述和方程。在這一次練習中,我們將要實現邏輯回歸并且應用到一個分類任務。我們還將通過將正則化加入訓練算法,來提高算法的魯棒性,并用更復雜的情形來測試它。
代碼修改并注釋:黃海廣,haiguang2000@qq.com
邏輯回歸
在訓練的初始階段,我們將要構建一個邏輯回歸模型來預測,某個學生是否被大學錄取。設想你是大學相關部分的管理者,想通過申請學生兩次測試的評分,來決定他們是否被錄取。現在你擁有之前申請學生的可以用于訓練邏輯回歸的訓練樣本集。對于每一個訓練樣本,你有他們兩次測試的評分和最后是被錄取的結果。為了完成這個預測任務,我們準備構建一個可以基于兩次測試評分來評估錄取可能性的分類模型。
讓我們從檢查數據開始。
import numpy as np import pandas as pd import matplotlib.pyplot as plt path = 'ex2data1.txt' data = pd.read_csv(path, header=None, names=['Exam 1', 'Exam 2', 'Admitted']) data.head()| 34.623660 | 78.024693 | 0 |
| 30.286711 | 43.894998 | 0 |
| 35.847409 | 72.902198 | 0 |
| 60.182599 | 86.308552 | 1 |
| 79.032736 | 75.344376 | 1 |
讓我們創建兩個分數的散點圖,并使用顏色編碼來可視化,如果樣本是正的(被接納)或負的(未被接納)。
positive = data[data['Admitted'].isin([1])] negative = data[data['Admitted'].isin([0])]fig, ax = plt.subplots(figsize=(12,8)) ax.scatter(positive['Exam 1'], positive['Exam 2'], s=50, c='b', marker='o', label='Admitted') ax.scatter(negative['Exam 1'], negative['Exam 2'], s=50, c='r', marker='x', label='Not Admitted') ax.legend() ax.set_xlabel('Exam 1 Score') ax.set_ylabel('Exam 2 Score') plt.show() 看起來在兩類間,有一個清晰的決策邊界。現在我們需要實現邏輯回歸,那樣就可以訓練一個模型來預測結果。方程實現在下面的代碼示例在"exercises" 文件夾的 "ex2.pdf" 中。sigmoid 函數
合起來,我們得到邏輯回歸模型的假設函數:讓我們做一個快速的檢查,來確保它可以工作。
nums = np.arange(-10, 10, step=1)fig, ax = plt.subplots(figsize=(12,8)) ax.plot(nums, sigmoid(nums), 'r') plt.show()棒極了!現在,我們需要編寫代價函數來評估結果。代價函數:?
def cost(theta, X, y):theta = np.matrix(theta)X = np.matrix(X)y = np.matrix(y)first = np.multiply(-y, np.log(sigmoid(X * theta.T)))second = np.multiply((1 - y), np.log(1 - sigmoid(X * theta.T)))return np.sum(first - second) / (len(X))現在,我們要做一些設置,和我們在練習 1 在線性回歸的練習很相似。
# add a ones column - this makes the matrix multiplication work out easier data.insert(0, 'Ones', 1)# set X (training data) and y (target variable) cols = data.shape[1] X = data.iloc[:,0:cols-1] y = data.iloc[:,cols-1:cols]# convert to numpy arrays and initalize the parameter array theta X = np.array(X.values) y = np.array(y.values) theta = np.zeros(3)讓我們來檢查矩陣的維度來確保一切良好。
theta array([ 0., 0., 0.]) X.shape, theta.shape, y.shape ((100, 3), (3,), (100, 1))讓我們計算初始化參數的代價函數(theta 為 0)。
cost(theta, X, y) 0.69314718055994529看起來不錯,接下來,我們需要一個函數來計算我們的訓練數據、標簽和一些參數 thata 的梯度。
gradient descent(梯度下降)
這是批量梯度下降(batch gradient descent)
轉化為向量化計算:
注意,我們實際上沒有在這個函數中執行梯度下降,我們僅僅在計算一個梯度步長。在練習中,一個稱為“fminunc”的 Octave 函數是用來優化函數來計算成本和梯度參數。由于我們使用 Python,我們可以用 SciPy 的“optimize”命名空間來做同樣的事情。
我們看看用我們的數據和初始參數為 0 的梯度下降法的結果。
gradient(theta, X, y) array([ -0.1 , -12.00921659, -11.26284221])現在可以用 SciPy's truncated newton(TNC)實現尋找最優參數。
import scipy.optimize as opt result = opt.fmin_tnc(func=cost, x0=theta, fprime=gradient, args=(X, y)) result (array([-25.1613186 , 0.20623159, 0.20147149]), 36, 0)讓我們看看在這個結論下代價函數計算結果是什么個樣子~
cost(result[0], X, y) 0.20349770158947464接下來,我們需要編寫一個函數,用我們所學的參數 theta 來為數據集 X 輸出預測。然后,我們可以使用這個函數來給我們的分類器的訓練精度打分。邏輯回歸模型的假設函數:
當大于等于 0.5 時,預測 y=1
當小于 0.5 時,預測 y=0 。
def predict(theta, X):probability = sigmoid(X * theta.T)return [1 if x >= 0.5 else 0 for x in probability] theta_min = np.matrix(result[0]) predictions = predict(theta_min, X) correct = [1 if ((a == 1 and b == 1) or (a == 0 and b == 0)) else 0 for (a, b) in zip(predictions, y)] accuracy = (sum(map(int, correct)) % len(correct)) print ('accuracy = {0}%'.format(accuracy)) accuracy = 89%我們的邏輯回歸分類器預測正確,如果一個學生被錄取或沒有錄取,達到 89%的精確度。不壞!記住,這是訓練集的準確性。我們沒有保持住了設置或使用交叉驗證得到的真實逼近,所以這個數字有可能高于其真實值(這個話題將在以后說明)。
正則化邏輯回歸
在訓練的第二部分,我們將要通過加入正則項提升邏輯回歸算法。如果你對正則化有點眼生,或者喜歡這一節的方程的背景,請參考在"exercises"文件夾中的"ex2.pdf"。簡而言之,正則化是成本函數中的一個術語,它使算法更傾向于“更簡單”的模型(在這種情況下,模型將更小的系數)。這個理論助于減少過擬合,提高模型的泛化能力。這樣,我們開始吧。
設想你是工廠的生產主管,你有一些芯片在兩次測試中的測試結果。對于這兩次測試,你想決定是否芯片要被接受或拋棄。為了幫助你做出艱難的決定,你擁有過去芯片的測試數據集,從其中你可以構建一個邏輯回歸模型。
和第一部分很像,從數據可視化開始吧!
path = 'ex2data2.txt' data2 = pd.read_csv(path, header=None, names=['Test 1', 'Test 2', 'Accepted']) data2.head()| 0.051267 | 0.69956 | 1 |
| -0.092742 | 0.68494 | 1 |
| -0.213710 | 0.69225 | 1 |
| -0.375000 | 0.50219 | 1 |
| -0.513250 | 0.46564 | 1 |
哇,這個數據看起來可比前一次的復雜得多。特別地,你會注意到其中沒有線性決策界限,來良好的分開兩類數據。一個方法是用像邏輯回歸這樣的線性技術來構造從原始特征的多項式中得到的特征。讓我們通過創建一組多項式特征入手吧。
degree = 5 x1 = data2['Test 1'] x2 = data2['Test 2']data2.insert(3, 'Ones', 1)for i in range(1, degree):for j in range(0, i):data2['F' + str(i) + str(j)] = np.power(x1, i-j) * np.power(x2, j)data2.drop('Test 1', axis=1, inplace=True) data2.drop('Test 2', axis=1, inplace=True)data2.head()| 1 | 1 | 0.051267 | 0.002628 | 0.035864 | 0.000135 | 0.001839 | 0.025089 | 0.000007 | 0.000094 | 0.001286 | 0.017551 |
| 1 | 1 | -0.092742 | 0.008601 | -0.063523 | -0.000798 | 0.005891 | -0.043509 | 0.000074 | -0.000546 | 0.004035 | -0.029801 |
| 1 | 1 | -0.213710 | 0.045672 | -0.147941 | -0.009761 | 0.031616 | -0.102412 | 0.002086 | -0.006757 | 0.021886 | -0.070895 |
| 1 | 1 | -0.375000 | 0.140625 | -0.188321 | -0.052734 | 0.070620 | -0.094573 | 0.019775 | -0.026483 | 0.035465 | -0.047494 |
| 1 | 1 | -0.513250 | 0.263426 | -0.238990 | -0.135203 | 0.122661 | -0.111283 | 0.069393 | -0.062956 | 0.057116 | -0.051818 |
現在,我們需要修改第 1 部分的成本和梯度函數,包括正則化項。首先是成本函數:
regularized cost(正則化代價函數)
def cost(theta, X, y, learningRate):theta = np.matrix(theta)X = np.matrix(X)y = np.matrix(y)first = np.multiply(-y, np.log(sigmoid(X * theta.T)))second = np.multiply((1 - y), np.log(1 - sigmoid(X * theta.T)))reg = (learningRate / (2 * len(X))) * np.sum(np.power(theta[:,1:theta.shape[1]], 2))return np.sum(first - second) / len(X) + reg請注意等式中的"reg" 項。還注意到另外的一個“學習率”參數。這是一種超參數,用來控制正則化項。現在我們需要添加正則化梯度函數:
如果我們要使用梯度下降法令這個代價函數最小化,因為我們未對?進行正則化,所以梯度下降算法將分兩種情形:
& Repeat\text{ }until\text{ }convergence\text{ }\!\!\{\!\!\text{ } \\ ?& \text{ ? ? }{{\theta }_{0}}:={{\theta }_{0}}-a\frac{1}{m}\sum\limits_{i=1}^{m}{[{{h}_{\theta }}\left( {{x}^{(i)}} \right)-{{y}^{(i)}}]x_{_{0}}^{(i)}} \\ ?& \text{ ? ? }{{\theta }_{j}}:={{\theta }_{j}}-a\frac{1}{m}\sum\limits_{i=1}^{m}{[{{h}_{\theta }}\left( {{x}^{(i)}} \right)-{{y}^{(i)}}]x_{j}^{(i)}}+\frac{\lambda }{m}{{\theta }_{j}} \\ ?& \text{ ? ? ? ? ?}\!\!\}\!\!\text{ } \\ ?& Repeat \\ \end{align}
對上面的算法中 j=1,2,...,n 時的更新式子進行調整可得:?
def gradientReg(theta, X, y, learningRate):theta = np.matrix(theta)X = np.matrix(X)y = np.matrix(y)parameters = int(theta.ravel().shape[1])grad = np.zeros(parameters)error = sigmoid(X * theta.T) - yfor i in range(parameters):term = np.multiply(error, X[:,i])if (i == 0):grad[i] = np.sum(term) / len(X)else:grad[i] = (np.sum(term) / len(X)) + ((learningRate / len(X)) * theta[:,i])return grad就像在第一部分中做的一樣,初始化變量。
# set X and y (remember from above that we moved the label to column 0) cols = data2.shape[1] X2 = data2.iloc[:,1:cols] y2 = data2.iloc[:,0:1]# convert to numpy arrays and initalize the parameter array theta X2 = np.array(X2.values) y2 = np.array(y2.values) theta2 = np.zeros(11)讓我們初始學習率到一個合理值。,果有必要的話(即如果懲罰太強或不夠強),我們可以之后再折騰這個。
learningRate = 1現在,讓我們嘗試調用新的默認為0的theta的正則化函數,以確保計算工作正常。
costReg(theta2, X2, y2, learningRate) 0.6931471805599454 gradientReg(theta2, X2, y2, learningRate) array([ 0.00847458, 0.01878809, 0.05034464, 0.01150133, 0.01835599,0.00732393, 0.00819244, 0.03934862, 0.00223924, 0.01286005,0.00309594])現在我們可以使用和第一部分相同的優化函數來計算優化后的結果。
result2 = opt.fmin_tnc(func=costReg, x0=theta2, fprime=gradientReg, args=(X2, y2, learningRate)) result2 (array([ 1.22702519e-04, 7.19894617e-05, -3.74156201e-04,-1.44256427e-04, 2.93165088e-05, -5.64160786e-05,-1.02826485e-04, -2.83150432e-04, 6.47297947e-07,-1.99697568e-04, -1.68479583e-05]), 96, 1)最后,我們可以使用第1部分中的預測函數來查看我們的方案在訓練數據上的準確度。
theta_min = np.matrix(result2[0]) predictions = predict(theta_min, X2) correct = [1 if ((a == 1 and b == 1) or (a == 0 and b == 0)) else 0 for (a, b) in zip(predictions, y2)] accuracy = (sum(map(int, correct)) % len(correct)) print ('accuracy = {0}%'.format(accuracy)) accuracy = 77%雖然我們實現了這些算法,值得注意的是,我們還可以使用高級Python庫像scikit-learn來解決這個問題。
from sklearn import linear_model#調用sklearn的線性回歸包 model = linear_model.LogisticRegression(penalty='l2', C=1.0) model.fit(X2, y2.ravel()) LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,penalty='l2', random_state=None, solver='liblinear', tol=0.0001,verbose=0, warm_start=False) model.score(X2, y2) 0.66101694915254239這個準確度和我們剛剛實現的差了好多,不過請記住這個結果可以使用默認參數下計算的結果。我們可能需要做一些參數的調整來獲得和我們之前結果相同的精確度。
參考資料
[1]?機器學習課程: https://www.coursera.org/course/ml
[2]?黃海廣: https://github.com/fengdu78
[3]?github: https://github.com/fengdu78/Coursera-ML-AndrewNg-Notes
[4]?作業代碼: https://github.com/fengdu78/Coursera-ML-AndrewNg-Notes/blob/master/code/ex2-logistic%20regression/ML-Exercise2.ipynb
[5]?markdown 文件: https://github.com/fengdu78/Coursera-ML-AndrewNg-Notes/blob/master/markdown/week3.md
[6]?pdf 文件: https://github.com/fengdu78/Coursera-ML-AndrewNg-Notes/blob/master/機器學習個人筆記完整版v5.4-A4打印版.pdf
關于本站
“機器學習初學者”公眾號由是黃海廣博士創建,黃博個人知乎粉絲23000+,github排名全球前110名(32000+)。本公眾號致力于人工智能方向的科普性文章,為初學者提供學習路線和基礎資料。原創作品有:吳恩達機器學習個人筆記、吳恩達深度學習筆記等。
往期精彩回顧
那些年做的學術公益-你不是一個人在戰斗
適合初學者入門人工智能的路線及資料下載
吳恩達機器學習課程筆記及資源(github標星12000+,提供百度云鏡像)
吳恩達深度學習筆記及視頻等資源(github標星8500+,提供百度云鏡像)
《統計學習方法》的python代碼實現(github標星7200+)
備注:加入本站微信群或者qq群,請回復“加群”
加入知識星球(4300+用戶,ID:92416895),請回復“知識星球”
總結
以上是生活随笔為你收集整理的收藏!!如何 Get 机器学习必备的算法技能? | 逻辑回归的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在线阅读!!机器学习数学精华:线性代数
- 下一篇: 经典算法解读:一文看懂支持向量机以及推导