監督學習中關於線性迴歸問題的系統討論

前言python

  本文將系統的介紹機器學習中監督學習的迴歸部分,系統的講解如何利用迴歸理論知識來預測出一個分類的連續值。算法

  顯然,與監督學習中的分類部分相比,它有很鮮明的特色:輸出爲連續值,而不只僅是標稱類型的分類結果。小程序

基本線性迴歸解決方案 - 最小二乘法app

  「給出一堆散點,求出其迴歸方程。" -> 對於這個問題,不少領域都碰到過,而其中最爲經典廣泛的作法一般是:機器學習

  1. 用式子表示出各個散點到迴歸線之間的距離之和:函數

  

  m 爲散點數量,yi 爲散點值,xi 爲散點座標,w 爲迴歸係數向量。學習

  2. 對上式以向量 w 求導,求出導數值爲 0 時的迴歸係數 (具體求導過程涉及到對向量求導的相關法則,略):測試

  

  這種方法就叫作最小二乘法。spa

最小二乘法的具體實現3d

  下面這個小程序從文本中讀取散點,而後擬合出迴歸直線,並使用 matplotlib 展現出來 (注: 爲了清楚直觀,特徵 0 沒展現出來):

 1 #!/usr/bin/env python
 2 # -*- coding:UTF-8 -*-
 3 
 4 '''
 5 Created on 2015-01-04
 6 
 7 @author: fangmeng
 8 '''
 9 
10 from numpy import *
11 
12 def loadDataSet(fileName):
13     '載入測試數據'
14     
15     numFeat = len(open(fileName).readline().split('\t')) - 1
16     dataMat = []; labelMat = []
17     fr = open(fileName)
18     for line in fr.readlines():
19         lineArr =[]
20         curLine = line.strip().split('\t')
21         for i in range(numFeat):
22             lineArr.append(float(curLine[i]))
23         dataMat.append(lineArr)
24         labelMat.append(float(curLine[-1]))
25     return dataMat,labelMat
26 
27 #===================================
28 # 輸入:
29 #        xArr: 特徵座標矩陣
30 #        yArr: 特徵值矩陣
31 # 輸出:
32 #        w: 迴歸係數向量
33 #===================================
34 def standRegres(xArr,yArr):
35     '採用最小二乘法求擬合係數'
36     
37     xMat = mat(xArr); 
38     yMat = mat(yArr).T
39     xTx = xMat.T*xMat
40     if linalg.det(xTx) == 0.0:
41         print "該矩陣沒法求逆"
42         return
43     ws = xTx.I * (xMat.T*yMat)
44     return ws
45 
46 def test():
47     '展現結果'
48     
49     # 採用最小二乘求出迴歸係數並預測出各特徵點對應的特徵值
50     xArr, yArr = loadDataSet('/home/fangmeng/ex0.txt')
51     ws = standRegres(xArr, yArr)
52     xMat = mat(xArr)
53     yMat = mat(yArr)
54     yHat = xMat * ws
55     
56     import matplotlib.pyplot as plt
57     
58     # 繪製全部樣本點
59     fig = plt.figure()
60     ax = fig.add_subplot(111)
61     ax.scatter(xMat[:,1].flatten().A[0], yMat.T[:, 0].flatten().A[0])
62     
63     # 繪製迴歸線
64     xCopy = xMat.copy()
65     xCopy.sort(0)
66     yHat = xCopy*ws
67     ax.plot(xCopy[:, 1], yHat)
68     plt.show()
69     
70 if __name__ == '__main__':
71     test()

  測試結果:

  

  觀察預測與真實的相關係數:

print corrcoef(yHat.T, yMat)

  測試結果:

  

  0.98+的相關係數,可見擬合的效果仍是不錯的。

局部加權線性迴歸

  基本的線性迴歸常常會碰到一些問題。

  好比因爲線性迴歸自己致使的欠擬合問題。以最基本的一個特徵的狀況爲例,若是散點圖自己呈現一個非線性化的輪廓,而強行的將它擬合成一條直線:

  

  顯然,兩端的擬合是很是不科學的,偏離的很遠。

  針對這個問題,局部加權線性迴歸應運而生。它可以獲得相似下圖這樣更爲科學的擬合線段:

  

  所謂局部,就是最大程度考慮待預測點附近的點,所謂加權,就是離待預測點越近,其參考系數(權重)就越大。

  所以,在原先的最小二乘法中加入一個用於衡量權重的對角矩陣W。這樣,迴歸係數的求解式就變爲:

  

  權重矩陣W又稱爲 "核",典型的高斯核的計算方法以下:

  

  下面是採用局部加權線性迴歸思想的迴歸係數求解函數:

 1 #===================================
 2 # 輸入:
 3 #        testPoint: 測試點
 4 #        xArr: 特徵座標矩陣
 5 #        yArr: 特徵值矩陣
 6 #        k: 高斯核權重衰減係數
 7 # 輸出:
 8 #        testPoint * ws: 測試點集對應的結果
 9 #===================================
10 def lwlr(testPoint,xArr,yArr,k=1.0):
11     '對指定點進行局部加權線性迴歸'
12     
13     xMat = mat(xArr); 
14     yMat = mat(yArr).T
15     m = shape(xMat)[0]
16     
17     # 採用向量方式計算高斯核
18     weights = mat(eye((m)))
19     for j in range(m):
20         diffMat = testPoint - xMat[j,:]
21         weights[j,j] = exp(diffMat*diffMat.T/(-2.0*k**2))
22         
23     xTx = xMat.T * (weights * xMat)
24     if linalg.det(xTx) == 0.0:
25         print "錯誤: 係數矩陣沒法求逆"
26         return
27     
28     ws = xTx.I * (xMat.T * (weights * yMat))
29     return testPoint * ws
30 
31 #===================================
32 # 輸入:
33 #        testArr: 測試點集
34 #        xArr: 特徵座標矩陣
35 #        yArr: 特徵值矩陣
36 # 輸出:
37 #        yHat: 測試點集對應的結果集
38 #===================================
39 def lwlrTest(testArr,xArr,yArr,k=1.0):
40     '對指定點集進行局部加權迴歸'
41     
42     m = shape(testArr)[0]
43     yHat = zeros(m)
44     
45     # 求出全部測試點集的
46     for i in range(m):
47         yHat[i] = lwlr(testArr[i],xArr,yArr,k)
48     return yHat

  以下代碼展現迴歸結果:

 1 def test():
 2     '展現結果'
 3     
 4     # 載入數據
 5     xArr, yArr = loadDataSet('/home/fangmeng/ex0.txt')
 6 
 7     # 獲取全部樣本點的局部加權迴歸的預測值
 8     yHat = lwlrTest(xArr, xArr, yArr, 0.01)
 9     
10     xMat = mat(xArr)
11     srtInd = xMat[:,1].argsort(0)
12     xSort = xMat[srtInd][:,0,:]
13     #print xMat[srtInd][:,0,:]
14     
15     # 顯示全部樣本點和局部加權擬合線段
16     import matplotlib.pyplot as plt
17     fig = plt.figure()
18     ax = fig.add_subplot(111)
19     ax.plot(xSort[:,1], yHat[srtInd])
20     ax.scatter(xMat[:,1].flatten().A[0], mat(yArr).T.flatten().A[0], s=2, c='red')
21     plt.show()

  當k(衰減係數) = 1時,測試結果:

  

  k(衰減係數) = 0.003時,測試結果:

  

  k(衰減係數) = 0.01時,測試結果:

  

  觀察能夠發現,k = 1就是和基本線性迴歸同樣了 - 欠擬合;而 k = 0.003 則是過擬合了;k = 0.01 恰好,是最優的選擇。

嶺迴歸

  假如碰到了這樣的狀況:散點個數小於特徵數了。

  這種狀況有啥問題呢 ---- (xTx)-1 必然會求解失敗!解決辦法能夠採用嶺迴歸技術。

  所謂嶺迴歸,就是在迴歸係數求解式中的 xTx 以後加上 λI 使求逆部分可順利求解,更改後的求解式以下:

  

  其中,I 是單位對角矩陣,看起來有點像山嶺。這也是爲何這種迴歸方式叫作嶺迴歸,哈哈!

  具體的實現代碼本文就不具體給出了,可是有兩個地方要特別注意一下:

  1. 須要對全部的數據進行標準化

  2. 根據不一樣的 λ 取到不一樣組的迴歸係數以後,還須要對不一樣組的權重進行擇優。比較經常使用的有 lasso 方法(和嶺迴歸的區別在於 w 和 λ 的約束關係)。

具體方案的制定

  提到了這麼多種的迴歸方案,那麼具體應該採用哪一種好呢?

  首先,得根據問題的特性選擇合適的方案。而後,使用同一組測試集測試每組方案的相關係數狀況。

  另外,實踐代表在一樣適用的狀況下,"誤差與方差折中" 是一條很重要的經驗法則。

  

  紅點位置對應的方案即是最佳方案。

小結

  迴歸和分類同樣,針對不一樣問題不一樣領域都有着不一樣算法。關鍵是要把握其總體思路,根據須要去進行選擇。

  然而,本文所講解的都是線性迴歸。線性迴歸始終有其弊端,由於不少實際問題自己是非線性的。

  即便是本文中介紹過的局部加權線性迴歸,想到每次測試都要擬合一次,也是挺蛋疼的。

  所以在下篇文章中,將會專門詳細地介紹一種高級的非線性迴歸法 - 樹迴歸。

相關文章
相關標籤/搜索