Coursra-MachineLearning 第二次作業總結

Logistic Regression

1.1 Visualizing the data

我們的目標是根據ex2data1裏面的數據,把被接受入學的數據和被拒絕入學的數據都標註在一張座標圖上。
爲了表示區分,接受入學的樣本在圖上用“黑色小十字”來表示,而拒絕入學的樣本在圖上用“黃色小圓點”來表示。
如果要做這個事情,第一步就是要把混雜在一起的數據分成兩堆。y=1的爲一堆,y=0的爲一堆。

  • 難點1 find函數
    我能夠猜到 pos = find(y ==1) 是將y向量中等於1那些值所在的位置記錄下來放到一個向量中,這個向量就是pos。這裏主要是瞭解find這個函數的用法
    這裏寫圖片描述
    在document裏面有很多find函數,就是這個Find indices of nonzero elements.
    其中有一個 Elements Equal to Specific Values用法。

  • 難點2 矩陣切片的再認識
    X(pos,1)這個我也能猜出來是,它表示的是X這個矩陣中第一列中的行序數在pos向量中的那些值。我的疑問是,這個矩陣切片操作還可以這麼表示,一個變量用向量,另一個變量用常數。仔細想想其實之前也用過,比如X = data(:,[1,2])中逗號前的部分“:”其實就是一種向量的表示方法,也就是說作爲矩陣定位的變量是可以用向量來表示的;而逗號後面的部分“[1,2]”其實是第一列和第二列構成的矩陣,從這個表示方法來推測,其實1,2這些所謂的常數,其實應該是代表列位置的索引。總結一下,其實一個矩陣A的切片方式A(X,Y),X表示的行的部分,X可以由表示行的那些索引構成的向量,Y表示列的部分,可以由表示列的索引構成的向量。對於這個例子來說我還可以構造一個矩陣 s = data([1,15,25],[1,3])

搞清了這兩點,我們就可以畫圖了,參考第二週作業筆記中對於畫圖函數的理解。以在座標軸上標註出“被接受”的樣本爲例,最重要的是兩個向量,一個向量是被接受樣本的x座標向量,另一個是被接受樣本的y座標向量,x座標向量可以用X(pos,1)表示,y座標向量可以用y(pos,2),在加上一些圖形屬性的參數就是
plot(X(pos, 1), X(pos, 2), ‘k+’,’LineWidth’, 2, ‘MarkerSize’, 7);
同理“被拒絕”樣本的x,y座標軸向量爲X(neg, 1), X(neg, 2),繪圖函數爲:
plot(X(neg, 1), X(neg, 2), ‘ko’, ‘MarkerFaceColor’, ‘y’, ‘MarkerSize’, 7);

1.2 Implementation

1.2.1 sigmoid function

其實這個函數非常簡單,只是有兩點要注意
1. 指數函數的表示方法
如果是以e爲底的那麼就用 exp(x)來表示,如果是以其它自然數爲底的比如說2x ,那麼就用2^x來表示就可以了。
2. 向量形式的實現
這個sigmoid函數是以向量的形式來實現的,在用1除以1+e^z的時候要用“./”而不是普通除,這個如果不是看人家的代碼還真不容易發現。
所謂向量化可以這麼理解:我需要對向量中的每個元素進行同一種運算。
比如以sigmoid函數作爲例子,假設待計算的向量爲α=a1a2a3 ,那麼經過sigmoid函數的運算,得到的結果應該是sigmoid(α)=11+ea111+ea211+ea3 。感覺是不是有點像函數式編程的map函數。相當於一個向量經過函數的處理,向量中所有的元素都經過函數的映射成爲一個新的向量。
引入向量運算的理由是經常有大量的數據經常用同一個函數進行運算,按照一般程序的處理方法,就得用循環語句了。如果能把接受同樣過程處理的數據打包批量進行處理就好了,這個就是向量化的思想。
Matlab裏面大多數函數都已經實現了向量化,我們在實現函數的時候也要儘可能的實現向量化,具體來說就是如果可以用Matlab提供現有運算工具就能實現對向量(或者矩陣)中每個元素的處理就可以直接用先有工具的組合就行了。但是如果沒有,那就只能寫循環語句了。以這個sigmoid函數爲例,待處理數據初始的狀態爲α=a1a2a3 ,exp()運算已經支持向量化,1+exp(α) 向量加標量也是可以作用於向量所有的元素的,所以這個也不用怎麼修改,那麼現在中間運算的結果爲1+ea11+ea21+ea3 ,之後需要用1除以向量中的每個元素變成11+ea111+ea211+ea3 。正好Matlab裏面有這個運算工具就是“點運算”所以 1 ./ (1 + exp( alpha ))。
這裏面還涉及到一個知識點,就是矩陣和標量之間的運算,標量和矩陣之間的運算相當於標量和矩陣中的每一個元素進行運算,對於除法來說,標量在左邊和在右邊是完全不一樣的,你可以做一個實驗,構造一個矩陣A,之後用2除以A和A除以2,結果是不同的,這點很容易知道,但是如果是2除以A要用 “2 ./ A” A除以2用“A ./ 2”或者“A / 2 ”都可以。其它的乘法以及加減法加點或者不加點運算效果都是一樣的。只有除法要注意。

1.2.2 Cost function and gradient

這塊還是要用向量的方式實現,可以用第二週發現的方法,我們用幾個小的觀察一下規律嘛(有點像高中學數列的時候)
1. 關於cost function的實現,我自己沒想出來向量形式的實現方式,只能用循環的方法實現(好Low啊),後來看了網友的答案得到啓發。我來推導一下這個是怎麼實現的。
首先還是用一個小數來把問題具體化,設m=3,n=2(三個樣本,兩個特徵)。
係數矩陣X111x1(1)x1(2)x1(3)x2(1)x2(2)x2(3)
參數向量爲θ=θ0θ1θ2
x(1) 表示的是第一組樣本,用向量的形式表示是x(1)=1x1(1)x2(1)
如果用樣本矩陣來表示係數矩陣就應該是X=111x1(1)x1(2)x1(3)x2(1)x2(2)x2(3)=x(1)x(2)x(3)
其實這個形式就跟CS229-notes1裏面page10的那個係數矩陣表達方法一樣的。我爲什麼要寫一遍係數矩陣,是因爲後面要劃歸爲向量形式要對這種形式比較熟悉。
接下來我們把J(θ) 式子展看看看能不能發現一些規律。當m=3的時候
J(θ)=13{y(1)log(hθ(x(1)))+(1y(1))log(1hθ(x(1)))+y(2)log(hθ(x(2)))+(1y(2))log(1hθ(x(2)))+y(3)log(hθ(x(3)))+(1y(3))log(1hθ(x(3))}
我們把y(i)log(hθ(x(i))) 的部分歸集在一起看,也就是下圖顯示的部分
這裏寫圖片描述
這部分就是y(1)log(hθ(x(1)))+y(2)log(hθ(x(2)))+y(3)log(hθ(x(3))) 看出來點什麼呢?
這部分其實就是向量y(1)y(2)y(3) 和 向量 log(hθ(x(1)))log(hθ(x(2)))log(hθ(x(3))) 的內積。
向量y(1)y(2)y(3) 就是向量y
log(hθ(x(1)))log(hθ(x(2)))log(hθ(x(3))) 這塊又怎麼理解呢?它其實看以看成向量x(1)x(2)x(3) 帶入公式log(hθ()) 的運算結果。但是x(1)x(2)x(3) 這個向量中的每一個元素也是一個列向量啊。貌似到這裏就有點卡殼了。怎麼辦呢?還是把這個形式具體到底。我們把式子展開,並且把向量帶入進去,觀察一下它的形式,看看能不能找到什麼規律
log(hθ()) 中的hθ(x) 是一個複合函數的簡寫形式,把它展開寫的形式是sigmoid(θTx(i)) ,注意這個內層函數我特意用的是θTx(i) 的方式來寫而不是θTx ,這是由於θTx 這種寫法是線性函數的一般寫法,這種一般的寫法其實對於變量x的數量是沒有限制的(甚至對於次數也是沒有限制的多項式的迴歸也是用這個形式,還可以x替換成其它各種奇怪的函數比如三角函數),而具體到某一個問題的時候,比如就是我們設計的這個例子,m = 3,n=2的情況。那麼f(x)=θ0+θ1x1+θ2x2 ,那麼我如果要往這個函數裏面賦值的話,就必須一次性把x1x2 這兩個都賦值。換句話說一旦當特徵的數量參數的數量固定下來了,f(x)=θTx(i) 是接受向量作爲參數的。
* 方法一:把log(hθ(x(1)))log(hθ(x(2)))log(hθ(x(3))) 徹底展開就是
log(11+e(θ0+θ1x(1)1+θ2x(1)2))log(11+e(θ0+θ1x(2)1+θ2x(2)2))log(11+e(θ0+θ1x(3)1+θ2x(3)2))log(sigmoid(θ0+θ1x(1)1+θ2x(1)2))log(sigmoid(θ0+θ1x(2)1+θ2x(2)2))log(sigmoid(θ0+θ1x(3)1+θ2x(3)2)))
其實這就看出來了,就是向量θ0+θ1x(1)1+θ2x(1)2θ0+θ1x(2)1+θ2x(2)2θ0+θ1x(3)1+θ2x(3)2 帶入公式log(sigmoid()) 的結果。
* 方法二:因此向量 log(hθ(x(1)))log(hθ(x(2)))log(hθ(x(3))) 又可以看成向量 x(1)x(2)x(3) 代入log(sigmoid(θTx(i))) 後運算的結果,也就是
log(hθ(x(1)))log(hθ(x(2)))log(hθ(x(3)))=log(sigmoid(θTx(1)))log(sigmoid(θTx(2)))log(sigmoid(θTx(3)))=log(sigmoid(θ0+θ1x(1)1+θ2x(1)2))log(sigmoid(θ0+θ1x(2)1+θ2x(2)2))log(sigmoid(θ0+θ1x(3)1+θ2x(3)2)))
也就相當於向量θ0+θ1x(1)1+θ2x(1)2θ0+θ1x(2)1+θ2x(2)2θ0+θ1x(3)1+θ2x(3)2 帶入公式log(sigmoid()) 的結果,
而向量θ0+θ1x(1)1+θ2x(1)2θ0+θ1x(2)1+θ2x(2)2θ0+θ1x(3)1+θ2x(3)2 其實就是Xθ
因此log(hθ(x(1)))log(hθ(x(2)))log(hθ(x(3))) 等價於log(sigmoid(Xθ))
由此我們可以得到y(1)log(hθ(x(1)))+y(2)log(hθ(x(2)))+y(3)log(hθ(x(3))) 可以寫爲向量y 與向量 log(sigmoid(Xθ)) 的內積,也可以用matlab的向量點乘運算。
同理(1y(1))log(1hθ(x(1)))+(1y(2))log(1hθ(x(2)))+(1y(3))log(1hθ(x(3)) 可以看成(1y) 這個向量(Matlab裏面向量和標量加減相當於向量中的每個元素和標量進行加減運算)和 向量 log(1sigmoid(Xθ)) 的內積。於是用代碼來表示可以是這樣

J = -1 / m * (dot(y,log(sigmoid(X * theta))) + dot((1 - y ),log(1 - sigmoid(X * theta))));

另外我還發現不知道是效率高咋滴,大家都不喜歡用向量內積的方式,而是先用點乘的方式之後在用sum把一個向量裏面的所有分量相加

J = -1 / m * sum (y .* log(sigmoid(X * theta)) + (1 - y ) .* log(1 - sigmoid(X * theta)));

2. 求梯度,其實梯度就是參數迭代公式中的偏導部分,爲啥這個叫做梯度,其實這個是斜率,參數要按照一個角度下降,控制這個角度多大的就是這個梯度的大小。
參數收斂公式:θj:=θjαJ(θ)θj
其實這個公式沒什麼牛逼的地方,思想很簡單就是把θ 一點一點的減小,減小的方式是沿着對應變量的導數方向一點一點下降。偏導數部分叫做“梯度”(gradient),查了一下牛津高階,梯度和坡度、斜率是一個詞。明白了這點我們專心求公式。
我們依然用小數來具體化,設m = 3 ,n=2,j = 1,則
J(θ)θ1=13{(hθ(x(1))y(1))x1(1)+(hθ(x(2))y(2))x1(2)+(hθ(x(3))y(3))x1(3)}
這種多個乘積相加的形式應該本能的反映出這是向量點積於是,可以分成
hθ(x(1))y(1)hθ(x(2))y(2)hθ(x(3))y(3)x(1)1x(2)2x(3)3 的內積,
x(1)1x(2)2x(3)3 這個不就是向量x1 嗎?
hθ(x(1))y(1)hθ(x(2))y(2)hθ(x(3))y(3) 可以拆成兩個向量減法hθ(x(1))hθ(x(2))hθ(x(3))y(1)y(2)y(3) ,而y(1)y(2)y(3) 這就是y啊,而hθ(x(1))hθ(x(2))hθ(x(3)) 根據上一點就是sigmoid(Xθ)
所以J(θ)θ1 的偏導就等於13(sigmoid(Xθ)y)x1
於是全部參數的梯度一次性求出就是 1m((sigmoid(xθ)y)X)
看了一下答案,發現(sigmoid(Xθ)y)X 的位置搞反了,你想嘛,(sigmoid(Xθ)y) 是一個1 x 3 的列向量,X是一個 3 x 3的矩陣,首先就沒法乘,所以位置調過來就對了犯這樣的錯誤主要是推導的時候想當然了
θ0=13(sigmoid(Xθ)y)x0
θ1=13(sigmoid(Xθ)y)x1
θ2=13(sigmoid(Xθ)y)x2
所以

θ=1m((sigmoid(xθ)y)X)
但是其實不是,之所以弄錯還是因爲(sigmoid(xθ)y) 太不直觀,看起像1/3那樣可以直接提到外面去,其實不是。(sigmoid(xθ)y) 是一個向量,好吧那麼我把這個再具體一下設(sigmoid(xθ)y)S=s1s2s3 於是
θ=x0TSx1TSx2TS=Sx0TSx1TSx2T=s1x(1)0+s2x(2)0+s3x(3)0s1x(1)1+s2x(2)1+s3x(3)1s1x(1)2+s2x(2)2+s3x(3)2=x(1)0x(1)1x(1)2x(2)0x(2)1x(2)2x(3)0x(3)1x(3)2s1s2s3

x(1)0x(1)1x(1)2x(2)0x(2)1x(2)2x(3)0x(3)1x(3)2 就是XT ,所以θ=XTSθ=XT(sigmoid(Xθ)y)
(PS:這裏爲了方便把1/3略去了)
所以這個推導還不是很容易的。
grad = 1 / m * (X' * (sigmoid(X * theta)-y));

這兩行代碼用了兩天,平均一天一行代碼(囧)

1.2.3 Learning parameters using fminunc

這個不需要我們自己實現,需要注意的是,這個使用的套路是,我們實現一個函數,這個函數再作爲參數傳遞給優化的函數

1.2.3.1 plotDecisionBoundary.m

1.2.3.1.1 contour函數的使用方法

這個分成兩種情況,第一種情況是係數矩陣的列小於3,也就是特徵只有兩個的情況,特徵如果只有兩個的情況下,決策邊界就是平面圖形上的一條直線,畫圖的方法比較容易直接看程序吧。
當係數矩陣的列大於3的時候,畫圖利用的是輪廓圖的方法。爲了便於直觀的思考,我們這裏只考慮特徵值有三個的情況,也就是決策邊界圖形是一個平面(x+y+z=0是一個平面)

要搞清contour()這個函數是怎麼用的,就要首先搞清在Matlab裏面三維圖形是怎麼畫的
假設Matlab裏面有一個三維繪製函數draw3D,那麼根據二維圖像的繪製方式這個函數只要接受三個參數就可以了,draw3D(x,y,z),第一個參數x是座標在x軸方向上的分量構成的向量,第二個參數是座標在y軸上的分量構成的向量,第三個參數z是座標在z軸上的分量構成的向量。因爲三維空間上的一個點就是(x,y,z),如果這三個分量都確定了,這個點就確認了,如果函數的參數是這樣設置的,那麼函數使用起來就特別直觀,而實際上Matlab裏面的3D繪圖函數上是接收矩陣作爲參數的,不知道爲啥弄得那麼複雜。在Matlab裏最基礎的繪製3D圖形的函數叫做mesh,不叫draw3D。
以mesh()爲例,它的參數有這樣三種情況
1. 如果x,y,z是同型的二維矩陣,那麼這三個矩陣中處於相同位置的值,構成了一個座標點,比如x(1,1),y(1,1),z(1,1)構成了屬於圖形上的一個點,但是如果x(1,1),y(1,1),z(1,2),這三個值構成的座標點雖然是一個點,但是這個點不在圖形上。
2. 如果只接受一個參數,即mesh(z),那麼z必須是一個二維的矩陣,那麼在這種情況下,這個矩陣如何映射到圖上的點呢?從直覺上我們能感覺x,y的座標可能會跟矩陣的行方向索引以及列方向所以相關,最自然的感覺是對於Z矩陣中的某一個元素Z(i,j),Z(i,j)的值作爲z軸方向的分量,行方向上的索引i作爲x軸方向上的分量,列方向上的索引j作爲y軸方向上的分量,即(i,j,Z(i,j))是圖形上的一個點。實際情況是,z(i,j)作爲z軸方向上的分量沒問題,而x,y其實正好和想象中的相反,我們設Z是一個m x n 的矩陣,首先X方向的範圍是 1-n,Y方向的範圍是1-m ,而且對於矩陣Z中的任意一個元素z(i,j),行方向的索引i是座標點在y軸方向上的分量,而列方向上的索引j是x軸方向上的索引,即(j,i,Z(i,j))是圖形上的一個點。這種感覺用這張圖表示比較形象。這裏寫圖片描述
我們可以用這麼一個矩陣做一個測試
zz =

8    8    9
8    8    9
7    7    7
7    7    6

利用mesh(ZZ)得到的爲
這裏寫圖片描述
3. 如果x是一個向量,y也是一個向量,z是一個矩陣,那麼這兩個向量和一個矩陣通過何種方式組合成一個圖像上的點呢,如果理解了上一點,也就是隻接受一個矩陣作爲參數的情況,那麼這中情況也比較好理解。在上一種情況中,咱們直接說結論吧,對於矩陣中的任意一個點Z(i,j)來說,它對應的座標爲(j , i , Z( i , j )),也就是拿矩陣的列方向索引爲x座標軸的分量,拿矩陣的行方向索引作爲y座標軸的分量。但是如果這裏增加了X和Y向量的話,矩陣的行列方向的索引就不能直接作爲座標的分量了,而應該作爲X向量和Y向量的索引,根據這個索引得到向量中的某一個值,這個值作爲座標裏的一個分量。也就是多了一層映射。具體來說就是Z(i,j),用列方向索引j,在X向量找第j個分量(即X(j))作爲座標x軸方向上的分量;用行方向上的索引i在Y向量找第i個分量(即Y(i))作爲座標在y軸方向的的分量。總結一下,如果給了三個參數X向量,Y向量,Z矩陣,那麼對於矩陣中的任何一個點Z(i,j),( X(j) , Y(i) , Z( i , j ) )是圖形上的一個點。注意正是由於這種關係,那麼X向量的長度要和Z的列的數量一樣,Y向量的長度要和Z的行的數量一樣。
這個 x,y,z上存在這樣的映射關係,length(x)=n,length(y)=m,z是一個m x n的二維矩陣(即 [m,n]=size(z)),那麼(x[j],y[i],z[i,j])構成的點在圖形上
這裏寫圖片描述
mesh是以網格的方式來作圖,surf就在網格上鋪了一層表面。
瞭解了三維作圖的方法,等高線就容易理解了,等高線的圖形你可以理解爲做出三維的圖形之後,系統自動的給你截取等高線,所以contour和mesh使用參數的方法一樣。
爲什麼這裏用到contour函數,這是因爲,對於多特徵(超過2個)的分類問題,決策邊界不再是一個直線而是一個立體,或者超維的立體,這個時候我們想在二維的平面上表現出決策邊界只能在Z=0所在的平面上截出這個超維圖像的邊界。

1.2.3.1.2 meshgrid函數的使用方法

在實際的繪圖過程中,我們一般按照什麼步驟去繪圖呢,類似於二維的圖像繪製,最方便的方法是構造X矩陣,Y矩陣,之後將X、Y帶入到Z = f(X,Y)的式子中去得到Z矩陣(注意這個式子一定要是向量兼容的形式)。之後把X,Y,Z帶入到mesh(X,Y,Z)就可以了。
而構造X,Y矩陣最方便的方法是用meshgrid函數。meshgrid,有兩種用法,第一種是[X,Y] = meshgrid(gv),第二種是[X,Y] = meshgrid(xgv,ygv)。
1. 先說第一種,[X,Y] = meshgrid(gv),它的作用是
* 把gv這個向量按行擴展成一個length(gv) x length(gv)的矩陣之後之後賦值給X
* 把X這個矩陣轉置賦值給Y。
2. 再說第二種,[X,Y] = meshgrid(xgv,ygv),它的構造的方法是:
* 設 xgv和ygv都是行向量,且m = length(xgv),n = length(xgv)
* 生成的矩陣無論是X還是Y,都是 n x m型的矩陣
* if m>n : a 按行擴展到n行構成一個矩陣賦給X,b先轉置成列向量按列擴展到m列構成一個矩陣賦值給Y
* if m

1.2.3.1.3 如果不用meshgrid函數,也就是採用mesh(xgv,ygv,ZZ)的方法

在這兩次作業中的代碼中(ex1.m以及plotDecisionBoundary.m),沒有采用meshgrid的方法,而是採用這樣的方法:
1. 分別生成兩個X,Y向量,之後再生成一個length(X) x length(Y)的全零矩陣Z
2. 填充Z矩陣,填充的方法是:從順序上是Z的第一行開始從左到右一行一行的填充,填充的內容對於Z(i,j)來說是用x(i),y(j)帶入Z(x,y)來得到。用代碼上來表示就是

for i = 1 : length(X)
for j = 1 : length(Y)
Z(i,j) = f(X(i) , Y(j))

3. 將Z矩陣轉置(這步還是挺聰明的)
4. 講X,Y,Z代入mesh(X,Y,Z)

第3步還是相當的聰明的

1.2.3.2 mapFeature.m

雖然繪圖裏用到這個函數,但是這個步驟還沒用到,正則化部分裏會用到,所以在下面展開說

1.2.4 Evaluating logistic regression

這部分的主要任務是完成predict.m這個程序,這個程序沒有什麼太多難的。
主要要注意的還是find的用法,比如調用sigmoid函數的結果向量爲S,那麼在S中找到值大於等於0.5的那些分量所在的位置,把它記錄下來並且保存在一個向量中,pos = find(S>=0.5)
之後將P這個零向量中相應的位置賦值爲1 p(pos) =1。我一開始驚訝於,原來還可以這麼用,其實pos = find(S>=0.5),p(pos) =1 也是向量的運算,S>=0.5其實是對S中的每一個分量都執行這個操作。p(pos) = 1可以看成pos中的每一個分量i取出來帶到p向量裏面p(i) =1

Regularized logistic regression

2.1 Visualizing the data

這個沒有要實現的,直接執行就行

2.2 Feature mapping

  1. 爲什麼要引入featuremapping這個函數,主要目的是由於決策邊界不能由直線來表示,於是我們可以通過在現有的特徵基礎上進行組合的方法生成一些新的特徵的方法來使我們的擬合曲線變成比較複雜的形態。具體來說就是兩個特徵x1,x2,我們可以通過對其多次的重複乘得到一個新的feature。比如我要構造一個6次方的特徵,可以有x16,x15x2,x14x22,x13x23,x12x24,x1x25,x26 這7個組合,其實x16 可以看成6個x1 相乘,x15x2 可以看成5個x1 和一個x2 相乘,到底有幾種組合,這是一個排列組合的問題,這個不太擅長就先跳過去啦,有誰比較擅長可以教教我。如果從0次開始一直到6次的所有組合都加起來一共有28個。也就是如果我們有兩個features,如果我們要映射到6次的時候,一共會構造出28個features。這個就是mapfeature的思想。
  2. 再說一下代碼中技巧
    在代碼中有一個end+1的用法,如果我們對一個矩陣A進行操作的時候,end代表A最後一行的索引數。
    可以參考這個文檔

  3. 由於mapfeature構造了28個特徵,那麼theta 也得相應的增加,也得有28個。

2.3 Cost function and gradient

總的來說如果是搞定了costFunction.m的內容的這個並不是很難,但是我也踏了一些坑,我先說一下自己的思路:
1. 計算cost
目標是寫出公式J(θ)=1mmi=1[y(i)log(hθ(x(i)))(1y(i))log(1hθ(x(i)))]+λmj=1nθj2
在計算J(θ) 的時候,分成兩塊,前一部分和costFunction.m裏面的J一樣,直接拿過來用,主要是計算後面的λ 的部分。由於這裏參與計算的是θ1θn 的部分,matlab表示就是從theta(2)到theta(n)的部分。於是我就把theta(2)到theta(n)的部分拿出來變成一個新的向量,這裏也用到向量切片的技巧。我用的方法是:

t = theta(2:size(theta,1));

其實有更加優雅的方法

t = theta(2:end)

於是後面的部分用代碼表示就是:

lambda / ( 2 * m ) * sum(t .* t)

其實還有更優雅的表達方法

lambda / ( 2 * m ) * t' * t

這裏我還踩了一個坑,因爲θ 要計算平方嘛,一開始我想的是不是有公式,我猜這個公式是不是pow這類的後來在系統的提示下還真找到一個pow2()的函數,我也沒驗證就直接用了,結果就怎麼都算不對,後來一點一點定位,先定位到J不對,在定位到這個後面的小項不對,正常來說應該這項在第一次計算爲0的,結果我計算出值來後來才發現這個問題。
ps:pow2()不是計算平方的公式是計算以2爲底的指數的公式
2. 計算偏導數
這塊我就是按照題目裏的提示分成兩部分做的,先計算θ0 保存在一個變量g1裏面。之後在計算剩下的部分,還是利用之前costFunction.m裏面的推到的方法得到了向量的表達方法,將計算結果放到另一個向量g2裏面,之後再把這兩個向量合二爲一賦值給grad,也用到向量的一些小技巧

grad = [g1 ; g2]

注意因爲grad是列向量,所以g1和g2中間用得是分號。
3. 更加優雅的思路
這是我見過最聰明的方法了。因爲其實在正則化的過程中,其實θ0 其實不參與正則化,那麼直接把θ 向量中的θ0 變成0就可以了。
那麼偏導數這部分計算公式都可以不變
思路是這樣的
J(θ)=1mmi=1[y(i)log(hθ(x(i)))(1y(i))log(1hθ(x(i)))]+λmnj=1θj2
注意觀察這個公式,這個公式可以分成兩個部分,前一部分和普通的代價函數計算一樣,後一部分是參與正則化的參數。那麼我們可以建立兩個參數向量第一個參數向量包含從θ0θn 的全部參數,這個向量值參與公式前一部分的計算;第二個參數向量是在第一個參數向量的基礎上把θ0 賦值爲0後生成的向量,這個向量只參與公式後一部分的計算。
本質上,我們梯度下降的核心公式是這個:θj:=θjαJ(θ)θj
其中,

J(θ)θj={1mmi=1(hθ(x(i))y(i))xj(i),1mmi=1(hθ(x(i))y(i))xj(i)+λmθj,if j=0if j>=1

我們依然用一個小的數來具體化,設n=2,則參數有三個需要確定θ0,θ1,θ2
J(θ)θ0J(θ)θ1J(θ)θ2=1mmi=1(hθ(x(i))y(i))x0(i)1mmi=1(hθ(x(i))y(i))x1(i)+λmθ11mmi=1(hθ(x(i))y(i))x2(i)+λmθ2=1mmi=1(hθ(x(i))y(i))x0(i)1mmi=1(hθ(x(i))y(i))x1(i)1mmi=1(hθ(x(i))y(i))x2(i)+λm0θ1θ2
1mmi=1(hθ(x(i))y(i))x0(i)1mmi=1(hθ(x(i))y(i))x1(i)1mmi=1(hθ(x(i))y(i))x2(i) 這個就是沒有正則化條件下的結果,即XT(sigmoid(Xθ)y)0θ1θ2 就是向量θθ0 賦值爲0而形成的向量。因此我們只要生成一個新的向量t = [0;theta(2:end)],不更改原來的式子而僅僅在在原來非正則化式子的基礎上加上一個新的向量就可以了。

grad = ( X' * (sigmoid(X*theta) - y ) )/ m + lambda/m * theta_1 ;

我之前的思路就相當於把這個公式:
J(θ)θj={1mmi=1(hθ(x(i))y(i))xj(i),1mmi=1(hθ(x(i))y(i))xj(i)+λmθj,if j=0if j>=1

分開計算,在計算第一個公式的時候相當於用到了每個樣本的第一個分量x0 ,而計算第二個公式的時候相當於用到了每個樣本從x1xn 的分量,如果從向量化的角度來看,就相當把樣本矩陣分成兩部分。
而其實通過上面的推導步驟可以發現其實上面的條件公式也是可以整合成一個公式的,只要弄出兩個θ 向量即可,相當於把參數向量分成兩種來進行考慮,這種思路的代碼非常工整。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章