機(jī)器學(xué)習(xí)之局部加權(quán)線性回歸(Locally Weighted Linear Regression)
原文地址:blog.csdn.net/tianse12/article/details/70161591
算法背景:
現(xiàn)實(shí)生活中很多數(shù)據(jù)采用線性模型不能很好的描述,比如說房價(jià)預(yù)測的問題,直線不能很好的擬合所有的數(shù)據(jù)點(diǎn),甚至存在較大的誤差,我們可能采用一條類似于二次函數(shù)的曲線可以擬合的更好。但是為了解決在非線性模型里建立線性模組的問題,我們預(yù)測一點(diǎn)的值時(shí),選擇與這個(gè)點(diǎn)相近的點(diǎn)而不是所有的點(diǎn)做線性回歸。基于此,產(chǎn)生了局部加權(quán)回歸算法。
算法思想:
局部加權(quán)回歸是基于非參數(shù)學(xué)習(xí)算法的思想,使得特征的選擇更好。賦予預(yù)測點(diǎn)附近每一個(gè)點(diǎn)以一定的權(quán)值,在這上面基于波長函數(shù)來進(jìn)行普通的線性回歸.可以實(shí)現(xiàn)對(duì)臨近點(diǎn)的精確擬合同時(shí)忽略那些距離較遠(yuǎn)的點(diǎn)的貢獻(xiàn),即近點(diǎn)的權(quán)值大,遠(yuǎn)點(diǎn)的權(quán)值小,k為波長參數(shù),控制了權(quán)值隨距離下降的速度,越大下降的越快。越小越精確并且太小可能出現(xiàn)過擬合的問題。
普通的線性回歸函數(shù)使用的最小二乘法,即cost函數(shù)是
要使得J(Θ)最小化,求得線性回歸參數(shù)
加入局部加權(quán)算法,cost函數(shù)變成了加權(quán)的cost函數(shù),如下面的形式
其中w(i)是權(quán)重
同樣可以求得線性回歸參數(shù)Θ為下面的形式
在使用這個(gè)算法訓(xùn)練數(shù)據(jù)時(shí),我們需要學(xué)習(xí)兩類參數(shù),線性回歸的參數(shù)以及波長參數(shù)。
算法的缺點(diǎn)主要在于對(duì)于每一個(gè)需要預(yù)測的點(diǎn),都要重新依據(jù)整個(gè)數(shù)據(jù)集模擬出一個(gè)線性回歸模型出來,使得算法的代價(jià)極高。
代碼實(shí)現(xiàn)Python:
#coding=utf-8
#LocallyWeightedLinearRegression.py
#局部加權(quán)線性回歸算法的實(shí)現(xiàn)
#其中線性回歸使用的最小二乘法,因此回歸系數(shù)是 theta = (X.T* W * X).I * X.T *W * Y
from numpy import *
#加載數(shù)據(jù)
def load_data(fileName):
numFeat = len(open(fileName).readline().split(',')) - 1
dataMat = []; labelMat = []
fr = open(fileName)
for line in fr.readlines():
lineArr =[]
curLine = line.strip().split(',')
for i in range(numFeat):
lineArr.append(float(curLine[i]))
dataMat.append(lineArr) #實(shí)際數(shù)據(jù)集
labelMat.append(float(curLine[-1]))#實(shí)際數(shù)據(jù)標(biāo)簽值
return dataMat,labelMat
# 對(duì)某一點(diǎn)計(jì)算估計(jì)值
def lwlr(testPoint, xArr, yArr, k = 1.0):
xMat = mat(xArr); yMat = mat(yArr).T#矩陣化
m = shape(xMat)[0]#取得維度25
weights = mat(eye((m)))#eye生成對(duì)角矩陣,m*m
for i in range(m):
diffMat = testPoint - xMat[i, :]#計(jì)算測試點(diǎn)坐標(biāo)和所有數(shù)據(jù)坐標(biāo)的差值
#計(jì)算權(quán)值 w =exp((-(xi-X)^2)/(2*k*k))
weights[i, i] = exp(diffMat * diffMat.T/(-2.0 * k**2))? ? ? # 計(jì)算權(quán)重對(duì)角矩陣
xTx = xMat.T * (weights * xMat)? ? #對(duì)x值進(jìn)行加權(quán)計(jì)算? ? ? ? ? # 奇異矩陣不能計(jì)算
if linalg.det(xTx) == 0.0:
print('This Matrix is singular, cannot do inverse')
return
#theta = (X.T* W * X).I * X.T *W * Y
theta = xTx.I * (xMat.T * (weights * yMat))? ? ? ? ? ? ? ? ? ? # 計(jì)算回歸系數(shù) ,對(duì)y加權(quán)
return testPoint * theta
# 對(duì)所有點(diǎn)計(jì)算估計(jì)值
def lwlrTest(testArr, xArr, yArr, k = 1.0):
m = shape(testArr)[0]
yHat = zeros(m)#初始化預(yù)測值列表
for i in range(m):
yHat[i] = lwlr(testArr[i], xArr, yArr, k)
return yHat
#coding=utf-8
#測試局部加權(quán)線性回歸算法
import matplotlib.pyplot as plt
import LocallyWeightedLinearRegression as lwlr
from numpy import *
xArr, yArr = lwlr.load_data('ex2.txt')
yHat = lwlr.lwlrTest(xArr, xArr, yArr, 0.1)
xMat = mat(xArr)
strInd = xMat[:, 1].argsort(0)#返回?cái)?shù)據(jù)第二列從小到大的索引值
#xSort = xMat[strInd][:, 0, :]#返回第一列和第二列,根據(jù)上面索引順序取出
xSort = xMat[strInd][:]#返回第一列和第二列,根據(jù)上面索引順序取出,xSort為Xmat的另一個(gè)拷貝
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(xSort[:, 1], yHat[strInd])#畫出擬合的線
ax.scatter(xMat[:, 1].flatten().A[0], mat(yArr).T.flatten().A[0], s = 2, c = 'red')#畫出實(shí)際點(diǎn)
plt.show()
結(jié)果演示:
使用k=0.1,數(shù)據(jù)擬合的最好:
使用k=0.01,數(shù)據(jù)存在過擬合的問題:
使用k=1.0,數(shù)據(jù)出現(xiàn)欠擬合的問題: