線性回歸的局限性
線性回歸是利用已有觀測(cè)樣本的自變量和因變量之間的線性關(guān)系,建立回歸方程。
通常采用最小二乘法求解,。
公式中包含,也就是需要對(duì)矩陣求逆,因此這個(gè)方程只在逆矩陣存在時(shí)適用。
如果特征比樣本點(diǎn)還多(),也就是說(shuō)輸入數(shù)據(jù)的矩陣不是滿秩矩陣。非滿秩矩陣求逆時(shí)會(huì)出現(xiàn)問(wèn)題。
為了解決這個(gè)問(wèn)題,統(tǒng)計(jì)學(xué)家引入了嶺回歸(ridge regression)的概念,本文將介紹的第一種縮減方法。
嶺回歸
簡(jiǎn)單來(lái)說(shuō),嶺回歸就是在矩陣上加一個(gè)
,從而使得矩陣非奇異(矩陣可逆),其中矩陣
是一個(gè)mxm的單位矩陣,對(duì)角線上元素全為1,其它元素全為0?;貧w系數(shù)的計(jì)算公式將變成:
通過(guò)引入懲罰項(xiàng),能夠減少不重要的參數(shù),這個(gè)技術(shù)在統(tǒng)計(jì)學(xué)中也叫做縮減(shrinkage)。
import numpy as np
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
# 計(jì)算回歸系數(shù)
def ridgeRegres(xMat, yMat, lam = 0.2):
xTx = xMat.T * xMat
demon = xTx + np.eye(xMat.shape[1]) * lam
if np.linalg.det(demon) == 0:
print('矩陣無(wú)法求逆')
return
ws = demon.I * (xMat.T * yMat)
return ws
def ridgeTest(xArr, yArr):
xMat = np.mat(xArr)
yMat = np.mat(yArr).T
# 數(shù)據(jù)標(biāo)準(zhǔn)化
ymean = np.mean(yMat, 0)
yMat = yMat - ymean
xMean = np.mean(xMat, 0)
xVar = np.var(xMat, 0)
xMat = (xMat - xMean)/xVar
numTest = 30
wMat = np.zeros((numTest, xMat.shape[1]))
for i in range(numTest):
ws = ridgeRegres(xMat, yMat, np.exp(i-10))
wMat[i,:] = ws.T
return wMat
ridgeRegres()函數(shù)用于計(jì)算回歸系數(shù),ridgeTest()函數(shù)在一組上測(cè)試結(jié)果。
abX, abY = loadDataSet('abalone.txt')
ridgeWeights = ridgeTest(abX, abY)
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(ridgeWeights)
plt.xlabel('log(lambda)')
plt.show()

上圖繪出了回歸系數(shù)與的關(guān)系。在
較小時(shí),可以得到所有系數(shù)的原始值;而在最右邊,
達(dá)到一個(gè)很大的值,所有系數(shù)縮減為0。在中間部分的某值將可以取得最好的預(yù)測(cè)效果。需要進(jìn)行交叉驗(yàn)證來(lái)找到最佳參數(shù)值。
還有一些其他縮減方法,如lasso、LAR、PCA回歸以及子集選擇等。
前向逐步回歸
前向逐步回歸算法,屬于一種貪心算法,即每一步都盡可能減少誤差。算法偽代碼如下。
數(shù)據(jù)標(biāo)準(zhǔn)化,使其分布滿足0均值和單位方差
每次迭代:
設(shè)置當(dāng)前最小誤差lowestError為正無(wú)窮
對(duì)每個(gè)特征:
增大或縮小:
改變一個(gè)系數(shù)得到一個(gè)新的W
計(jì)算新W下的誤差
如果誤差Error小于lowestError:
設(shè)置WBest等于當(dāng)前W
將W設(shè)置為新的WBest
實(shí)際代碼如下。
# 計(jì)算殘差平方和
def rssError(yArr,yHatArr):
return ((yArr-yHatArr)**2).sum()
# 標(biāo)準(zhǔn)化數(shù)據(jù)
def regularize(xMat, axis = 0):
inMat = xMat.copy()
inMeans = np.mean(inMat, axis)
inVar = np.var(inMat, axis)
inMat = (inMat - inMeans)/inVar
return inMat
# 前向逐步回歸
def stageWise(xArr, yArr, eps = 0.01, maxIter = 100):
'''
xArr:輸入數(shù)據(jù)
yArr預(yù)測(cè)變量
eps:需要調(diào)整的步長(zhǎng)
maxIter:最大迭代次數(shù)
'''
xMat = np.mat(xArr)
yMat = np.mat(yArr).T
yMean = np.mean(yMat, 0)
yMat = yMat - yMean
xMat = regularize(xMat)
m,n = xMat.shape
returnMat = np.zeros((maxIter, n))
ws = np.zeros((n, 1))
wsTest = ws.copy()
wsMax = ws.copy()
for i in range(maxIter):
lowestError = np.inf
for j in range(n):
for sign in [-1, 1]:
wsTest = ws.copy()
wsTest[j] += eps*sign
yTest = xMat * wsTest
rssE = rssError(yMat.A, yTest.A)
if rssE < lowestError:
lowestError = rssE
wsMax = wsTest
ws = wsMax.copy()
returnMat[i, :] = ws.T
return returnMat
下面看下實(shí)際效果。
ws = stageWise(abX, abY, 0.005, 1000)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(ws)
plt.show()

逐步線性回歸算法可以找出重要的特征,這樣就可能及時(shí)停止對(duì)那些不重要特征的收集。
當(dāng)應(yīng)用縮減方法(如逐步線性回歸或嶺回歸)時(shí),模型就增加了偏差(bias),與此同時(shí),減小了模型的方差。