線性迴歸最小二乘法和梯度下降法

問題描述

首先我們定義問題,線性迴歸要解決的問題就是根據給出的數據學習出一個線性模型。
例如我們最常說的身高和體重的關係,以及房屋面積和房價的關係,這裏給出一個瑞典汽車保險數據集
數據集 可以直接複製出來用
兩列分別表示
索賠要求數量
對所有索賠的總賠付,以千瑞典克朗計
數據前五行

108 392,5
19  46,2
13  15,7
124 422,2
40  119,4

我們按照這個數據集作出圖如下
汽車保險索賠要求和總賠付

大概觀察一下可以用線性模型去定義,現在的問題是根據現有的這個數據集合,我們要學習出一個模型,然後給出索賠要求數量我們能夠預測總賠付。
下面給出兩種解決方法,並分析這兩種方法區別。

最小二乘法

上面這個問題就是最簡單的一元線性模型,首先看幾個定義
分類問題 監督學習中,如果預測的變量是離散的,我們稱其爲分類(如決策樹,支持向量機等)
迴歸問題如果預測的變量是連續的,我們稱其爲迴歸
一元線性迴歸分析中,如果只包括一個自變量和一個因變量,且二者的關係可用一條直線近似表示,這種迴歸分析稱爲一元線性迴歸分析。
多元線性如果迴歸分析中包括兩個或兩個以上的自變量,且因變量和自變量之間是線性關係,則稱爲多元線性迴歸分析。
對於二維空間線性是一條直線;對於三維空間線性是一個平面,對於多維空間線性是一個超平面

對於上面的數據集,我們可以用多條直線去擬合,那麼怎麼定義那一條直線是最優呢?

首先定義模型:
其中ei爲樣本誤差
這裏寫圖片描述

定義損失函數:
這裏寫圖片描述

上面是損失函數,我們現在目的使得損失函數儘可能的小,就是求如上Q的最小值,函數求極值問題,這裏就用到了導數,導數的意義是導數大於0的x處函數遞增,導數小於0處x的函數遞減,導數爲0既爲函數的極值點
這裏寫圖片描述

上面x和y都是已知的數據集,β是我們要求的結果,兩個函數兩個未知數,就可以解方程了。
這裏寫圖片描述

證明也很簡單,這裏給個證明的鏈接,剩下就是幾次求和的事兒了。

多元線性迴歸

首先我們假設模型:
這裏寫圖片描述

而對於數據集合中n個個體,每個模型有:
這裏寫圖片描述
表示成矩陣形式:
這裏寫圖片描述

跟一元的一樣,首先我們損失函數:
這裏寫圖片描述

同樣通過求偏導數爲0解方程可以得到結果:
這裏寫圖片描述

梯度下降法

我們要求解的問題和上面一樣,同樣定義的模型和損失函數都一樣,模型爲線性模型,損失函數爲平方差值和最小,同樣這裏要求解的是線性方程的參數。

首先我們給每個參數賦值一個隨機數,然後按照下面公式進行迭代:
這裏寫圖片描述

按照最小二乘法,我們直接求出導數爲0的點,但是有時候很難解出方程,就考慮使用迭代的方法,首先取一個隨機數,然後每一次去想着目標結果逼近,而爲了效率最高,我們向着梯度下降最快的方向,既θ在偏導數上的取值。而α是學習速率,是個很重要的參數,設置過大會導致超過最小值,過小則學習的太慢。
對右邊的式子展開得到:
這裏寫圖片描述

則批量梯度下降迭代如下:
這裏寫圖片描述

隨機梯度下降

上面公式我們發現,每迭代一次我們都要遍歷所有的數據去求和,如果數據量大的話可能計算一次很耗時,於是就有了隨機梯度下降,這樣雖然解決了數據量大的問題,但是學習速度比較曲折,並且學習到的結果可能只是幾個局部最優解。如果數據量小建議用批量梯度下降:
這裏寫圖片描述

首先哦我們看按照批量梯度得到的結果
函數爲:y = 19.818 + 3.418 * x
做圖看一下,看圖的話效果還是很不錯的
這裏寫圖片描述
下面給出上面數據的兩種方法的代碼
批量梯度下降法:

#!/usr/bin/env python
#coding:utf-8

import json
import sys
import time
reload(sys)
sys.setdefaultencoding('utf-8')

if __name__ == "__main__":
    x = [108.0 , 19.0 , 13.0 , 124.0 , 40.0 , 57.0 , 23.0 , 14.0 , 45.0 , 10.0 , 5.0 , 48.0 , 11.0 , 23.0 , 7.0 , 2.0 , 24.0 , 6.0 , 3.0 , 23.0 , 6.0 , 9.0 , 9.0 , 3.0 , 29.0 , 7.0 , 4.0 , 20.0 , 7.0 , 4.0 , 0.0 , 25.0 , 6.0 , 5.0 , 22.0 , 11.0 , 61.0 , 12.0 , 4.0 , 16.0 , 13.0 , 60.0 , 41.0 , 37.0 , 55.0 , 41.0 , 11.0 , 27.0 , 8.0 , 3.0 , 17.0 , 13.0 , 13.0 , 15.0 , 8.0 , 29.0 , 30.0 , 24.0 , 9.0 , 31.0 , 14.0 , 53.0 , 26.0 ]
    y = [392.5 , 46.2 , 15.7 , 422.2 , 119.4 , 170.9 , 56.9 , 77.5 , 214.0 , 65.3 , 20.9 , 248.1 , 23.5 , 39.6 , 48.8 , 6.6 , 134.9 , 50.9 , 4.4 , 113.0 , 14.8 , 48.7 , 52.1 , 13.2 , 103.9 , 77.5 , 11.8 , 98.1 , 27.9 , 38.1 , 0.0 , 69.2 , 14.6 , 40.3 , 161.5 , 57.2 , 217.6 , 58.1 , 12.6 , 59.6 , 89.9 , 202.4 , 181.3 , 152.8 , 162.8 , 73.4 , 21.3 , 92.6 , 76.1 , 39.9 , 142.1 , 93.0 , 31.9 , 32.1 , 55.6 , 133.3 , 194.5 , 137.9 , 87.4 , 209.8 , 95.5 , 244.6 , 187.5]
    print len(x),len(y)
    epsilon = 0.0001  #迭代伐值

    cnt = 0
    alpha = 0.001
    theta0 = 0
    theta1 = 0

    error1 = 0
    error0 = 0
    while True:
        sum0 = 0 
        sum1 = 0
        cnt = cnt + 1
        for i in range(0, len(x)):
            diff =y[i] - (theta0 + theta1 * x[i])

            sum0 = sum0 + diff
            sum1 = sum1 + diff * x[i]

        theta0 = theta0 + alpha * sum0 / len(x)
        theta1 = theta1 + alpha * sum1 / len(x)

        error1 = 0
        for i in range(0, len(x)):
            error1 = error1 + (y[i] - (theta0 + theta1 * x[i] )) ** 2

        if abs(error1 - error0) < epsilon:
            break
        else:
            error0 = error1

        print 'thata0 : %f, thata1 :%f error1 : %f' % (theta0, theta1, error1)

這一份數據用隨機梯度搞不定,學習不出比較好的結果,考慮是不是對數據做一些預處理
隨機梯度下降法:

#!/usr/bin/env python
#coding:utf-8

import json
import sys
import time
reload(sys)
sys.setdefaultencoding('utf-8')

if __name__ == "__main__":
    x = [108.0 , 19.0 , 13.0 , 124.0 , 40.0 , 57.0 , 23.0 , 14.0 , 45.0 , 10.0 , 5.0 , 48.0 , 11.0 , 23.0 , 7.0 , 2.0 , 24.0 , 6.0 , 3.0 , 23.0 , 6.0 , 9.0 , 9.0 , 3.0 , 29.0 , 7.0 , 4.0 , 20.0 , 7.0 , 4.0 , 0.0 , 25.0 , 6.0 , 5.0 , 22.0 , 11.0 , 61.0 , 12.0 , 4.0 , 16.0 , 13.0 , 60.0 , 41.0 , 37.0 , 55.0 , 41.0 , 11.0 , 27.0 , 8.0 , 3.0 , 17.0 , 13.0 , 13.0 , 15.0 , 8.0 , 29.0 , 30.0 , 24.0 , 9.0 , 31.0 , 14.0 , 53.0 , 26.0 ]
    y = [392.5 , 46.2 , 15.7 , 422.2 , 119.4 , 170.9 , 56.9 , 77.5 , 214.0 , 65.3 , 20.9 , 248.1 , 23.5 , 39.6 , 48.8 , 6.6 , 134.9 , 50.9 , 4.4 , 113.0 , 14.8 , 48.7 , 52.1 , 13.2 , 103.9 , 77.5 , 11.8 , 98.1 , 27.9 , 38.1 , 0.0 , 69.2 , 14.6 , 40.3 , 161.5 , 57.2 , 217.6 , 58.1 , 12.6 , 59.6 , 89.9 , 202.4 , 181.3 , 152.8 , 162.8 , 73.4 , 21.3 , 92.6 , 76.1 , 39.9 , 142.1 , 93.0 , 31.9 , 32.1 , 55.6 , 133.3 , 194.5 , 137.9 , 87.4 , 209.8 , 95.5 , 244.6 , 187.5]
    print len(x),len(y)
    epsilon = 0.0001  #迭代伐值

    cnt = 0
    alpha = 0.01
    theta0 = 0
    theta1 = 0

    error1 = 0
    error0 = 0
    while True:
        cnt = cnt + 1
        for i in range(0, len(x)):
            diff =y[i] - (theta0 + theta1 * x[i])

            theta0 = theta0 + alpha * diff 
            theta1 = theta1 + alpha * diff * x[i]

            error1 = 0
            for i in range(0, len(x)):
                error1 = error1 + (y[i] - (theta0 + theta1 * x[i] )) ** 2

            if abs(error1 - error0) < epsilon:
                break
            else:
                error0 = error1

            print 'thata0 : %f, thata1 :%f error1 : %f' % (theta0, theta1, error1)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章