線性迴歸

1.引言:

看了Stanford的Andrew Ng老師的機器學習公開課中關於Logistic Regression的講解寫下此篇學習筆記總結一下。

 

2.原理:

按照我們老師的話說,做機器學習無非是三個重點:取模型,選代價函數,找極值

取模型:

找一個合適的預測函數(Andrew Ng的公開課中稱爲hypothesis),一般表示爲h函數,該函數就是我們選取的模型,它用來預測輸入數據的判斷結果。這個過程時非常關鍵的,需要對數據有一定的瞭解或分析,知道或者猜測預測函數的“大概”形式,比如是線性函數還是非線性函數。如果對於一組數據,我們找不到相應的模型來描述,那麼我們無法進行下去。

線性模型就是預測的y=\theta 1x1+\theta 2x2+\cdot \cdot \cdot +\theta nxn+c的形式,這種形式可以用矩陣表示,即Y=θX+C(其中θ,X都爲矩陣)

非線性模型就是出現了x的多次方

 

選代價函數:代價函數就是能表示樣本的預測值h和實際值y 差值得一個函數,

代價函數有cost函數和J函數兩種說法

J=\sum_{i=1}^{m}Cost()

cost函數主要是單個樣本的差值,J函數就是對所有樣本的Cost進行求和或取平均值

因爲我們說的代價是所有樣本的,所以J函數纔是我們的代價函數

 

找極值:顯然,J(θ)函數的值越小表示預測函數越準確(即h函數越準確),所以這一步需要做的是找到能使J(θ)函數的最小的θ值。我們選取的算法幾乎是梯度下降算法或者一些變換形式,可以說沒有梯度下降就沒有現在的深度學習,這是一個神奇的算法。但是缺陷在於只能找到極小值,這要求我們在J函數的選取是要注意J函數只有一個極小值(即要求J函數能收斂)

 

 

3.具體實現過程:

找預測函數:

假設我們來預測房價和麪積的關係:

我們可以畫出一條綠色的直線來描述這個關係,這臺直線的函數式即爲{\color{Red} y=\theta1x1+\theta0 },這個即爲我們的假設函數h,爲了區別於實際的房價值,我們把我們通過h函數預測出來的y值稱爲h。

 

取代價函數:(m是樣本數)

我們肯定希望找到的那條線,距離每個點都很近,最好所有的點上都在這條線上,但是一條直線去擬合所有的點都在這條直線上肯定不現實,所以我們希望這些點儘量離這條直線近一點。

所以我們會想到垂直距離,但是垂直距離的公式比較複雜,所謂我們選取了(h-y)^{^{2}}作爲我們的cost函數,這在圖形上的意義即是豎直距離,當cost函數越小時,這條直線離這個點越近,當cost=0時,點就在直線上。

然後我們再取所有樣本的平均值(再除以2的原因是求導抵消了,這個就相當於常數c,),

那麼我們的總誤差即J函數爲:J=(1/2m)\sum_{i=1}^{m}cost=(1/2m)\sum_{i=1}^{m}(h-y)^2

 

找極值:

首先我們要明確找的是什麼,我們要找的即使J函數最小的一組θ值,在這個問題中,即爲θ0,θ1.

所以我們的步驟爲:

1.隨機開始一組theta值,我們一般取0或1之類的

2.利用梯度下降算法改變theta的值直到一個合適的值(即迭代)

\theta 1=\theta 1-\alpha (\partial J(\theta1)/\partial(\theta1))

展開即爲\theta 1=\theta 1-\alpha* \sum_{i=1}^{m}((1/m)*(h-y)*x))   


  首先來講一下梯度下降算法(有一些博客也叫梯度上升,因爲他們求導後把負號號移出去了):

    不管我們位於這個什麼位置,只要我們想走到極小點,就要往梯度方向(導數)的反方向走,假如我們一開始在左邊的圓點處,那我們一點一點往右邊滑下去唄,即爲\theta 1=\theta 1-\alpha (\partial J(\theta1)/\partial(\theta1)).

     α爲步長,這個控制我們每次移動的距離

      我們重複這個過程(\theta 1=\theta 1-\alpha (\partial J(\theta1)/\partial(\theta1)),就能夠到達極小點附近(而不是最小點)

 

大多數同學會有疑問,如果越過了最低點怎麼樣:即使越過了最低點,我們對該點求導,發現該店的導數爲正,減去即爲往左邊移動。而且一般α取得合理就不會越過,因爲越到下面導數越小,就像2-1-(1/2)-(1/4)-(1/8)-......-(1/2^n)一樣永遠大於0

 

    接下來講下α的作用和怎麼選取合適的α:

    如左圖所示,首先我們隨機選取了θ1爲靠近最小值的圓點,假如我們選取了一個較大的α,那麼我們減去了一個比較大的值,導致我們第一次移動到了最小值的右邊,我們求導發現該點的導數更大,這就導致了我們第二次移動到原來那個點的左邊,然後該點的導數更大,這就導致了每一次迭代不是想更小的移動,而是像更大的移動,這樣就到不了最小值了。

   當然α也不是越小越好,太小了,移動的太慢了,迭代500次可能還沒有算出來,一個合適的α迭代100後就很接近極小值了

   我們一般選取α爲0.01,但是對於不同的數據,不同的代價函數,這個值會不一樣,我們可以通過30倍的縮放來改變這個值

 

爲什麼梯度下降算法要求J函數只有一個極小值:

對於以上的J函數,假如我們選取不同的初始值θ0和θ1,那麼我們將會到達不同的極小值,最後我們怎麼確定哪個最小呢,有多少個最小的呢,所以我們在選取J函數的時候就要確保J函數只有一個極小值,即下面這樣的圖形

 

最後就直接上代碼:

import numpy as np
import pylab
import json

def compute_error(b,m,data):
    """計算代價函數"""
    cost=0
    x=data[0]
    y=data[1]
    x=np.array(x)
    y=np.array(y)
    num=float(len(data))
    cost=(m*x+b-y)**2
    cost=np.sum(cost,axis=0)
    cost=cost/(2*num)
    return cost

def optimizer(data,starting_b,starting_m,learning_rate,num_iter):
"""梯度下降算法"""
    b=starting_b
    m=starting_m

    for i in range(num_iter):
        b,m=compute_gradient(b,m,data,learning_rate)
        if i%100==0:
            print(str(i)+" error:"+str(compute_error(b,m,data)))
            plot_data(data,b,m)
   
    return [b,m]

def compute_gradient(b_current,m_current,data,learning_rate):
"""每一次的迭代"""
    b_gradient = 0
    m_gradient = 0
    num=float(len(data))

    # x=data[:,0]
    # y=data[:,1]
    x=data[0]
    y=data[1]
    x=np.array(x)
    y=np.array(y)

    b_gradient=(m_current*x+b_current-y)*(1/num)#先前無法收斂在於偏導b和m的偏導寫反了
    b_gradient=np.sum(b_gradient,axis=0)

    m_gradient=(m_current*x+b_current-y)*x*(1/num)
    m_gradient=np.sum(m_gradient,axis=0)

    m_new=m_current-(learning_rate*m_gradient)
    b_new=b_current-(learning_rate*b_gradient)

    return [b_new,m_new]

def plot_data(data,b,m):
""""畫曲線"""
    x=data[0]
    y=data[1]
    x=np.array(x)
    y=np.array(y)
    y_predict = m*x+b
    pylab.plot(x,y,'o')#原來的元素
    pylab.plot(x,y_predict,'k-')#預測的元素
    pylab.show()

def linear_regression():
    starting_b=0.0
    starting_m=0.0
    learning_rate=0.00001#學習步數太小擬合慢,太大就會不能convergence
    #數據的大小會決定α,這次數據擴大了100倍,使用α要縮小100倍,標準化也行
    num_iter=500
    x=[63.030301,25.60160963,84.07966543,33.21034955,80.36386821,83.07007084,73.82586473,91.57007003,10.92153202,84.7031311,24.39083948,61.10565706,56.9543926,87.40964666,71.43630822,66.23807235,12.34436146,93.93842171,14.53165794,78.2440026]
    y=[63.87392259,26.29752231,85.14718359,34.06340079,81.33633071,83.85031798,75.08598548,92.85616524,12.43963086,85.56767789,25.40299684,62.18816348,57.7284949,88.24736608,72.85552885,66.93011168,13.14443623,95.47745258,15.50435747,79.81954144]
    data=[x,y]
    print("first error:"+str(compute_error(starting_b,starting_m,data)))

    [b,m]=optimizer(data,starting_b,starting_m,learning_rate,num_iter)

    print("last error:"+str(compute_error(b,m,data)))
    print(str(m))
    print(str(b))
    plot_data(data,b,m)
linear_regression()

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章