機器學習實戰之線性迴歸+局部加權線性迴歸

一、線性迴歸 
用線性迴歸找到最佳擬合直線

迴歸的目的是預測數值型數據,根據輸入寫出一個目標值的計算公式,這個公式就是迴歸方程(regression equation),變量前的係數(比如一元一次方程)稱爲迴歸係數(regression weights)。求這些迴歸係數的過程就是迴歸。

假設輸入數據存放在矩陣X中,迴歸係數存放在向量w中,那麼對於數據X1的預測結果可以用Y1=XT1w得出。我們需要找到使誤差最小的w,但是如果使用誤差之間的累加的話,那麼正負誤差將會抵消,起不到效果,所以採用平方誤差。如下:

i=1n(yixTiw)2
用矩陣表示:(YXw)T(YXw)。對W求導得到XT(YXw),令其等於零得到w的最佳估計:
w^=(XTX)1XTy
首先我們導入數據,代碼如下:

from numpy import *
def loadDataSet(fileName):
    numFeat = len(open(fileName).readline().split('\t'))-1
    dataMat = []; labelMat = []
    fr = open(fileName)
    for line in fr.readlines():
        lineArr = []
        curLine = line.strip().split('\t')
        for i in range(numFeat):
            lineArr.append(float(curLine[i]))
        dataMat.append(lineArr)
        labelMat.append(float(curLine[-1]))
    return dataMat, labelMat
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

這部分數據是由tap分隔,並且最後一個值是目標值。接下來計算迴歸係數:

def standRegres(xArr, yArr):
    xMat = mat(xArr); yMat = mat(yArr).T
    xTx = xMat.T*xMat
    if linalg.det(xTx) == 0.0:
        print "This matrix is singular, cannot do inverse"
        return
    ws = xTx.I * (xMat.T*yMat)
    return ws
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

該函數首先讀入xy數組,然後將它們轉換成矩陣,之後根據公式計算平方誤差,注意,需要對XTX求逆,此時需要判斷它的行列式是否爲0,行列式等於0的矩陣無法求逆,可以直接使用linalg.det() 來計算行列式。好了,我們來看看效果,首先讀入數據:

 xArr,yArr=loadDataSet('ex0.txt')
  • 1
  • 1

我們先看看前兩條數據:

print xArr[0:2]
[[1.0, 0.067732], [1.0, 0.42781]]
  • 1
  • 2
  • 1
  • 2

第一個值總是等於1.0,也就是x0,假定偏移量是一個常數,第二個值是x1。 
現在看看計算迴歸係數函數效果:

 ws = standRegres(xArr,yArr)
 print ws

[[ 3.00774324]
 [ 1.69532264]]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

現在得到了迴歸係數,那麼我們可以通過迴歸方程進行預測yHat:

xMat = mat(xArr)
yMat = mat(yArr)
yHat = xMat*ws
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

爲方便觀察,我們畫出數據集散點圖:

import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(xMat[:,1].flatten().A[0], yMat.T[:,0].flatten().A[0])
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

現在繪製最佳擬合直線,那麼需要畫出預測值yHat,如果直線上數據點次序混亂,繪圖時將會出現問題,所以要將點按照升序排序:

xCopy = xMat.copy()
xCopy.sort(0)
yHat=xCopy*ws
ax.plot(xCopy[:,1], yHat)
plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

我們來看看效果: 
這裏寫圖片描述 
最佳擬合直線方法將數據視爲直線進行建模,但圖中的數據集似乎還有更好的擬合方式。


二、局部線性迴歸

主要看k的選擇,因爲每個k值下算出的迴歸係數值已滿足最小均方誤差了。

線性迴歸可能出現欠擬合的現象,如上圖所示,因爲它求的是具有最小均方誤差的無偏差估計。所以有些方法允許在估計中引入一些偏差,從而降低預測的均方誤差。其中一個方法就是使用局部加權線性迴歸(Locally Weighted Linear Regression,LWLR),我們給待測點附近的每個點賦予一定的權重,是用此方法解出的迴歸係數如下:


theta

=(XTWX)1XTWy
W是一個矩陣,用來給每個數據點賦予權重。

LWLR使用“核”來對附近的點賦予更高的權重,核的類型可以自由選擇,最常用的核就是高斯核,高斯覈對應的權重如下:

w(i,i)=exp(|xix|2k2)

該函數稱爲指數衰減函數,比較像但不是正態分佈。其中x是要預測的點, xi 是第i個訓 練數據。 k 稱爲波長,控制權值隨矩陣下降的速率。越大,衰減的越慢,反之則越快
import numpy as np
import matplotlib.pyplot as plt

def loadDataSet(fileName):      #general function to parse tab -delimited floats
    numFeat = len(open(fileName).readline().split('\t')) - 1 #get number of fields 
    dataMat = []; labelMat = []
    fr = open(fileName)
    for line in fr.readlines():
        lineArr =[]
        curLine = line.strip().split('\t')
        for i in range(numFeat):
            lineArr.append(float(curLine[i]))
        dataMat.append(lineArr)#xij,i爲特徵,j爲樣本
        labelMat.append(float(curLine[-1]))
    return dataMat,labelMat

#局部加權迴歸
def lwlr(testPoint,xArr,yArr,k=1.0):#
    xMat = np.mat(xArr); yMat = np.mat(yArr).T
    m = np.shape(xMat)[0]
    weights = np.mat(np.eye((m)))#創建對角矩陣:eye()返回一個對角線元素爲1,其他元素爲0的二維數組。 以給每個數據點賦予權重
    for j in range(m):                      #next 2 lines create weights matrix
        diffMat =    testPoint - xMat[j,:]     #
        weights[j,j] = np.exp(diffMat*diffMat.T/(-2.0*k**2))
    xTx = xMat.T * (weights * xMat)
    if np.linalg.det(xTx) == 0.0:
        print("This matrix is singular, cannot do inverse")
        return
    ws = xTx.I * (xMat.T * (weights * yMat))
    return testPoint * ws

def lwlrTest(testArr,xArr,yArr,k=1.0):  #測試lwlr函數:loops over all the data points and applies lwlr to each one
    m = np.shape(testArr)[0]
    yHat = np.zeros(m)
    for i in range(m):
        yHat[i] = lwlr(testArr[i],xArr,yArr,k)
    return yHat

def lwlrTestPlot(xArr,yArr,k=1.0):  #same thing as lwlrTest except it sorts X first
    yHat = np.zeros(np.shape(yArr))       #easier for plotting
    xCopy = np.mat(xArr)
    xCopy.sort(0)
    for i in range(np.shape(xArr)[0]):
        yHat[i] = lwlr(xCopy[i],xArr,yArr,k)
    return yHat,xCopy

def rssError(yArr,yHatArr): #yArr and yHatArr both need to be arrays
    return ((yArr-yHatArr)**2).sum()


導入數據計算預測值並繪圖:

xArr,yArr=loadDataSet(r'C:\Users\qingmu\Desktop\數據組\收藏資料\machinelearninginaction\Ch08\新建文本文檔.txt')

yHat=lwlrTest(xArr,xArr,yArr,0.1)
xMat=np.mat(xArr)
rssError=
strInd=xMat[:,1].argsort(0)
xSort=xMat[strInd][:,0,:]

fig=plt.figure()
ax=fig.add_subplot(111)
ax.plot(xSort[:,1],yHat[strInd])
ax.scatter(xMat[:,1].flatten().A[0], np.mat(yArr).T.flatten().A[0], s = 2, c = 'red')
plt.show()

k=0.1


k=0.01



k=0.003



練習:

擬合交易指數和支付金額。

第一種情況:

xArr,yArr=loadDataSet(r'C:\Users\qingmu\Desktop\數據組\收藏資料\machinelearninginaction\Ch08\新建文本文檔.txt')

yHat=lwlrTest(xArr,xArr,yArr,0.1)
xMat=np.mat(xArr)
strInd=xMat[:,0].argsort(0)
xSort=xMat[strInd][:,0,:]

fig=plt.figure()
ax=fig.add_subplot(111)
ax.plot(xSort[:,0],yHat[strInd])
ax.scatter(xMat[:,0].flatten().A[0], np.mat(yArr).T.flatten().A[0], s = 2, c = 'red')
plt.show()
其餘代碼均相同。
k=0.1


k=0.01


k=0.003


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