第二部分 利用回歸預測數值型數據
第 8 章 預測數值型數據:回歸
[TOC]
本章內容
- 線性回歸
- 局部加權線性回歸
- 嶺回歸和逐步線性回歸
- 預測鮑魚年齡和玩具售價
1. 用線性回歸找到最佳擬合直線
線性回歸:
- 優點:結果易于理解,計算熵不復雜。
- 缺點:對非線性的數據擬合不好。
- 適用數類型:數值型和標稱型數據。
回歸的目的是預測數值型的目標值。最直接的辦法是依據輸入寫成一個目標值的計算公式。
這就是回歸方程,其中的 a1 和 a2 稱作回歸系數(regression weights),求這些回歸系數的過程就是回歸。一旦有了這些回歸系數,再給定輸入,做預測就非常容易了,具體的做法是用回歸系數乘以輸入值,再將結果全部加在一起,就得到了預測值。(這里的回歸都是指線性回歸(linear regression)。
回歸的一般方法:
- 收集數據:采用任意方法收集數據。
- 準備數據:回歸需要數值型數據,標稱型數據將被轉成二值型數據。
- 分析數據:繪制出數據的可視化二維圖將有助于對數據做出理解和分析,在采用縮減法求得新回歸系數之后,可以將新擬合線繪制在圖上作為對比。
- 訓練算法:找到回歸系數。
- 測試算法:使用 R2 或者預測值和數據的擬合度,來分析模型的效果。
- 使用算法:使用回歸,可以在給定輸入的時候預測出一個數值,這是對分類方法的提升,因為這樣可以預測連續型數值而不僅僅是離散的類別標簽。
應當怎樣從一大堆數據里求出回歸方程呢?假定輸入數據存放在矩陣 X 中,而回歸系數存放在向量 W 中,那么對于給定的數據 x1,預測結果將會通過
給出。現在的問題是,有一些 x 個對應的 Y,怎樣才能找到 w 呢?一個常用的方法就是找出誤差最小的 w。這里的誤差是指預測 y 值和真實 y 值之間的差值,使用該差值的簡單累加將使得正差值和發差值相互抵消,所以使用平方誤差公式:
用矩陣表示為:
如果對 w 求導,得到
令其等于零,解出 w 如下:
w 上方的小標記表示,這是當前可以估計出的 w 的最優解。
值得注意的是,上述公式中包含
,也就是需要對矩陣求逆,因此這個方程只在逆矩陣存在的時候適用(代碼中可以用偽逆矩陣)。上述的最佳 w 求解的統計學中的常見問題,除了矩陣方法外還有其他方法可以解決。該方法也稱為 OLS,即普通最小二乘法(ordinary least squares)。
對于圖8-1的散點圖,下面來介紹如何給出該數據的最佳擬合直線。
添加 loadDataSet() 函數:
def loadDataSet(fileName):
"""
讀取文本文件
:param fileName:
:return:
"""
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
添加 standRegres 函數:
def standRegres(xArr, yArr):
"""計算最佳擬合直線"""
xMat = np.mat(xArr)
yMat = np.transpose(np.mat(yArr))
xTx = np.transpose(xMat) * xMat
if np.linalg.det(xTx) == 0.0: # 計算 xTx 的行列式,為零則不能計算逆矩陣
print("this matrix is singular,cannot do inverse")
return
ws = xTx.I * (xMat.T * yMat)
# ws = np.linalg.solve(xTx, xMat.T * yMat) # 偽逆矩陣,可以不判斷行列式是否為零
return ws
測試:
xArr,yArr = loadDataSet('ex0.txt')
ws = standRegres(xArr,yArr) # 回歸系數
# print(ws) # [[ 3.00774324] [ 1.69532264]]
xMat = np.mat(xArr)
yMat = np.mat(yArr)
yHat = xMat * ws # 預測的 y 值: y=ws[0]+ws[1]*X1
print(np.cov(yHat.T, yMat)) # 協方差 [[ 0.24664409 0.24664409] [ 0.24664409 0.25345439]]
print(np.corrcoef(yHat.T, yMat)) # 相關系數 [[ 1. 0.98647356] [ 0.98647356 1. ]]
# 繪制數據集散點圖和最佳擬合直線圖
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(xMat[:,-1].flatten().A[0], yMat.T[:,0].flatten().A[0])
xCopy = xMat.copy()
xCopy.sort(0)
yHat = xCopy*ws
ax.plot(xCopy[:,-1],yHat)
plt.show()
幾乎任一數據集都可以用上述方法建立模型,那么,如何判斷這些模型的好壞呢?比較一下圖8-3 的兩個子圖,如果在兩個數據集上分別作線性回歸,將得到完全一樣的模型(擬合直線)。顯然兩個數據是不一樣的,那么模型分別在二者上的效果如何?我們當如何比較這些效果的好壞?有兩種方法可以計算預測值 yHat 序列和真實值 y 序列的匹配程度,那就是計算這兩個序列的相關系數。
在 numpy 中提供了 corrcoef 來計算預測值與真實值的相關性.
協方差:
相關系數:
其中,
表示 X、Y 的方差,并且 |r|<=1。
該矩陣包含所有兩兩組合的相關系數。可以看到,對角線上的數據是 1.0,因為 yMat 和自己的匹配是最完美的,而 yHat 和 yMat 的相關系數為 0.98.
2. 局部加權線性回歸
線性回歸的一個問題是有可能出現欠擬合現象,因為它求的是具有最小均方誤差的無偏估計。顯而易見,如果模型欠擬合將不能取得最好的預測效果,所以有些方法允許在估計中引入一些偏差,從而降低預測的均方誤差。
其中一個方法是局部加權線性回歸(Locally Weighted Linear Regression,LWLR)。在該算法中,我們給待預測點附近的每個點賦予一定的權重;然后與8.1節類似,在這個子集上基于最小均方差來進行普通的回歸。與 kNN 一樣,這種算法每次均需要事先取出對應的數據子集。該算法解出回歸系數 w 的形式如下:
其中 w 是一個矩陣,用來給每個數據點賦予權重。
LWLR 使用“核”來對附近的點賦予更高的權重。核的類型可以自由選擇,最常用的核就是高斯核,其對應的權重如下:
這樣就構建了一個只含對角元素的權重矩陣 w,并且點 x 與 x(i) 越近,w(i,i) 將會越大。上述公式包含一個需要用戶指定的參數 k,它決定了對附近的點賦予多大的權重,這也就是使用 LWLR 時唯一需要考慮的參數,在圖8-4中可以看到參數 k 與權重的關系:
添加 lwlr() 函數:
def lwlr(testPoint, xArr, yArr, k=1.0):
"""
局部加權線性回函數
:param testPoint:
:param xArr:
:param yArr:
:param k:用于控制衰減速度
:return:
"""
xMat = np.mat(xArr)
yMat = np.mat(yArr).T
m = np.shape(xMat)[0]
weights = np.mat(np.eye((m))) # 創建對角矩陣,階數等于樣本點個數
for j in range(m):
# 隨著樣本點與待預測點距離的遞增,權重值大小以指數級衰減
diffMat = testPoint - xMat[j,:]
weights[j,j] = np.exp(diffMat*diffMat.T/(-2.0*k**2)) # 參數 k,控制衰減的速度
xTx = xMat.T * (weights * xMat)
if np.linalg.det(xTx) == 0.0:
print('this matrix is singular, cannot do inverse')
ws = xTx.I * (xMat.T * (weights * yMat))
return testPoint * ws
添加 lwlrTest() 函數:
def lwlrTest(testArr, xArr, yArr, k=1.0):
"""
用于為數據集中每個點調用 lwlr(),這有助于求解 k 的大小
:param testArr:
:param xArr:
:param yArr:
:param k:
:return:
"""
m = np.shape(testArr)[0]
yHat = np.zeros(m)
for i in range(m):
yHat[i] = lwlr(testArr[i], xArr, yArr, k)
return yHat
測試:
xArr, yArr = loadDataSet('ex0.txt')
yHat = lwlrTest(xArr, xArr, yArr, 0.01) # k=1, 0.01, 0.003
xMat = np.mat(xArr)
srtInd = xMat[:,1].argsort(0)
xSort = xMat[srtInd][:,0,:]
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(xSort[:,1], yHat[srtInd])
ax.scatter(xMat[:,1].flatten().A[0], np.mat(yArr).T.flatten().A[0], s=2, c='red')
plt.show()
可以觀察到如圖8-5所示的效果。圖8-5 給出了 k 在不同取值下的結果圖。
局部加權線性回歸也存在一個問題,即增加了計算量,因為它對每個點做預測時都必須使用整個數據集。從圖8-5可以看出,k=0.01 時可以得到很好的估計,但是同時看到涂8-4中 k=0.01 的情況,就會發現大多數據點的權重都接近零。如果避免這些計算將可以減少程序運行時間,從而緩解因計算量增加帶來的問題。
3. 示例:預測鮑魚的年齡
在data目錄下有一份來自 UCI 數據集合的數據,記錄了鮑魚的年齡。鮑魚年齡可以從鮑魚殼的層數推算得到。
預測代碼:
abX, abY = loadDataSet('abalone.txt')
yHat01 = lwlrTest(abX[0:99], abX[0:99], abY[0:99], 0.1)
yHat1 = lwlrTest(abX[0:99], abX[0:99], abY[0:99], 1)
yHat10 = lwlrTest(abX[0:99], abX[0:99], abY[0:99], 10)
print(rssError(abY[0:99], yHat01.T)) # 56.7886874305
print(rssError(abY[0:99], yHat1.T)) # 429.89056187
print(rssError(abY[0:99], yHat10.T)) # 549.118170883
可以看到,使用較小的核將得到較低的誤差,那么,為什么不在所有數據集上都使用最小的核呢?這是因為 使用最小的核將造成過擬合,對新數據不一定能達到最好的預測效果。下面就來看看它們在新數據上的表現:
yHat01 = lwlrTest(abX[100:199], abX[0:99], abY[0:99], 0.1)
yHat1 = lwlrTest(abX[100:199], abX[0:99], abY[0:99], 1)
yHat10 = lwlrTest(abX[100:199], abX[0:99], abY[0:99], 10)
print(rssError(abY[100:199], yHat01.T)) # 57913.5155016
print(rssError(abY[100:199], yHat1.T)) # 573.52614419
print(rssError(abY[100:199], yHat10.T)) # 517.571190538
從上述結果可以看到,核大小等于 10 時的測試誤差最小,但它在訓練集上的誤差卻最大的。接下來和簡單的線性回歸做個比較:
ws = standRegres(abX[0:99], abY[0:99])
yHat = np.mat(abX[100:199]) * ws
print(rssError(abY[100:199], yHat.T.A)) # 518.636315325
簡單線性回歸達到了與局部加權線性回歸類似的結果,這也表明一點,必須在未知數據上比較效果才能選取到最佳模型。
4. 縮減系數來“理解”數據
如果數據的特征比樣本點還多應該怎么辦?是否還可以使用線性回歸和之前的額方法來做預測?答案是否定的,即不能再使用前面介紹的方法。這是因為在計算
的時候會出錯。
如果特征比樣本點還多 (n>m) 也就是說輸入數據的矩陣 X 不是滿秩矩陣。非滿秩矩陣在求逆時會出問題。
這節介紹的三種方法就是來解決這個問題。
4.1 嶺回歸
嶺回歸(ridge regression)就是在矩陣 $$X^TX$$ 上加一個 $$\lambda I$$ 從而使得矩陣非奇異,進而能對 $$X^T X+\lambda I$$ 求逆。其中矩陣 I 是一個 m*m 的單位矩陣。而 lambda 是一個用戶定義數值,后面會做介紹。在這種情況下, 回歸系數的計算公式將變成:
嶺回歸最先用來處理特征多余樣本數的情況,現在也用于在估計中加入偏差,從而得到更好的估計。這里通過引入 lambda 來限制了所有 w 之和,通過引入該懲罰項,能夠減少不重要的參數,這個技術在統計學中也叫做縮減(shrinkage)。
添加 ridgeRegres() 函數:
def ridgeRegres(xMat, yMat, lam=0.2):
"""
計算回歸系數
:param xMat:
:param yMat:
:param lam:
:return:
"""
xTx = xMat.T * xMat
denom = xTx + np.eye(np.shape(xMat)[1]) * lam #
if np.linalg.det(denom) == 0.0:
print("this matrix is singular,cannot do inverse")
return
ws = denom.I * (xMat.T * yMat)
# ws = np.linalg.solve(xTx + np.eye(np.shape(xMat)[1]) * lam, xMat.T * yMat) # 用偽逆矩陣求解
return ws
添加 ridgeTest() 函數:
def ridgeTest(xArr, yArr):
"""
在一組lam上測試結果
:param xArr:
:param yArr:
:return:
"""
xMat = np.mat(xArr)
yMat = np.mat(yArr).T
yMean = np.mean(yMat, 0) # 求均值
yMat = yMat - yMean
xMeans = np.mean(xMat, 0) # 求均值
xVar = np.var() # 求方差
xMat = (xMat - xMeans)/xVar # 數據標準化:所有特征都減去各自的均值并除以方差
numTestPts = 30
wMat = np.zeros((numTestPts, np.shape(xMat)[1]))
for i in range(numTestPts):
ws = ridgeRegres(xMat, yMat, np.exp(i-10))
wMat[i,:] = ws.T
return wMat
下面看一下鮑魚數據集上的運行結果:
abX, abY = loadDataSet('abalone.txt')
ridgeWeights = ridgeTest(abX, abY)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(ridgeWeights)
plt.show()
這樣就得到了 30 個不同 lambda 所對應回歸系數。圖8-6是所見的額效果圖:
該圖繪制出了回歸系數與 log(lam) 的關系。在最左邊,即 lambda 最小時,可以得到所有系數的原始值(與線性回歸一致);而在右邊,系數全部縮減為 0;在中間部分的某值將可以取得最好的預測效果。為了定量地找到最佳參數值,還需要進行交叉驗證。另外,要判斷哪些變量對結果預測最具有影響力,在圖8-6 中觀察它們對應的系數大小就可以。
4.2 lasso
不難證明,在增加如下約束時,普通的最小二乘法回歸會得到與嶺回歸的一樣的公式:
上式限定了所有回歸系數的平方和不能大于 lambda。使用普通的最小二乘法回歸在當兩個或更多的特征相關時,可能會得出一個很大的正系數和一個很大的負系數。正式因為上述限制條件的存在,使用嶺回歸可以避免這個問題。
與嶺回歸類似,另一個縮減方法 lasso 也對回歸系數做了限定,對應的約束條件如下:
唯一的不同點在于,這個約束條件使用絕對值取代了平方和。在 lambda 足夠小時,一些系數會因此被迫縮減到 0,這個特性可以幫助我們更好的理解數據,這兩個約束條件在公式上看起來相差無幾,但細微的變化卻極大的增加了計算復雜度(為了在這個新的約束條件下解出回歸系數,需要使用二次規劃算法)。下面將介紹一個更為簡單的方法來得到結果,該方法叫做前向逐步回歸。
4.3 前向逐步回歸
前向逐步回歸算法可以得到與 lasso 差不多的效果,但更加簡單。它屬于一種貪心算法,即每一步都盡可能減少誤差。一開始,所有的權重都設為 1,然后每一步所做的決策時對某個權重增加或減少一個很小的值。
該算法的偽代碼如下:
數據標準化,使其分布滿足 0 均值和單位方差
在每輪迭代過程中:
設置當前最小誤差啊 lowestError 為正無窮
對每個特征:
增大或縮小:
改變一個系數得到一個新的 W
計算新 W 下的誤差
如果誤差 Error 小于當前最小誤差 lowestError:設置 Wbest 等于當前的 W
將 W 設置為新的 WBest
添加 regularize() 函數:
def regularize(xMat):
"""
把特征按照均值為0,方差為1進行標準化
:param xMat:
:return:
"""
inMat = xMat.copy()
inMeans = np.mean(inMat, 0)
inVar = np.var(inMat, 0)
inMat = (inMat - inMeans)/inVar
return inMat
添加 stageWise() 函數:
def stageWise(xArr, yArr, eps=0.01, numIt=100):
"""
逐步線性回歸算法
:param xArr:
:param yArr:
:param eps: 步長
:param numIt: 迭代次數
:return:
"""
xMat =np.mat(xArr)
yMat = np.mat(yArr).T
yMean = np.mean(yMat, 0)
yMat = yMat - yMean
xMat = regularize(xMat)
m,n = np.shape(xMat)
returnMat = np.zeros((numIt,n))
ws = np.zeros((n,1))
wsTest = ws.copy() # 為了實現貪心算法建立了ws的兩個副本
wsMax = ws.copy()
for i in range(numIt): # 迭代
print('ws.T:',ws.T)
lowestError = float('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
測試一下實際效果:
xArr, yArr = loadDataSet('abalone.txt')
# print(stageWise(xArr,yArr,0.01,200))
print(stageWise(xArr,yArr,0.001,5000))
與最小二乘法進行比較,發現在5000次迭代后,逐步線性回歸算法與常規的最小二乘法效果類似。使用 0.005 的 epsilon 值并經過 1000 次迭代后的結果參見圖8-7:
逐步線性回歸算法的實際好處并不在于能繪出圖8-7這樣漂亮的圖,主要的優點在于它可以幫助人們理解現有的模型并作出改進。當構建一個模型后,可以運行該算法找出重要的特征,這樣就有可能及時停止對那些不重要特征的收集。最后,如果用于測試,該算法每 100 次迭代后就可以構建出一個模型,可以使用類似于 10 折交叉驗證比較這些模型,最終選擇使誤差最小的模型。
當應用縮減方法(如逐步線性回歸或嶺回歸)時,模型也就增加了**偏差(bias),與此同時卻減小了模型的方差。
5. 權衡偏差與方差
圖8-8給出了訓練誤差和測試誤差的曲線圖,上面的曲線圖就是測試誤差,下面的曲線是訓練誤差。根據8.3節的實驗我們知道:如果降低核的大小,那么訓練誤差將變小。從圖8-8來看,從左到右就表示了核逐漸減小的過程。
一般認為,上述兩種誤差由三個部分組成:偏差、測量誤差和隨機噪聲。在8.2節和8.3節,我們通過引入了三個越來越小的核來不斷增大模型方差。
8.4節介紹了縮減法,可以將一些系數縮減成很小的值或直接縮減為0,這是一個增大模型偏差的例子。通過把一些特征的回歸系數縮減到 0 ,同時也就減少了模型的復雜度。例子中有8個特征,消除了其中兩個后不僅使模型更易理解,同時還降低了預測誤差。圖8-8左側是參數縮減過于嚴厲的結果,右側是無縮減的效果。
6. 示例:預測樂高玩具套裝的價格
一種樂高套裝基本上在幾年后就會停產,但樂高的收藏著之間仍會在停產后彼此交易,為了給樂高套裝估價,下面將用本章的回歸技術來建立一個預測模型。
示例:用回歸法預測樂高套裝的價格:
- 收集數據:用 google shopping 的 api 收集數據。
- 準備數據:從返回的 json 數據中抽取價格。
- 分析數據:可視化并觀察數據。
- 訓練算法:構建不同的模型,采用逐步線性回歸和直接的線性回歸模型。
- 測試算法:使用交叉驗證來測試不同的模型,分析哪個效果更好。
- 使用算法:這次練習的目的就是生成數據模型。
6.1 收集數據:使用 google 購物的 api
詳細 api 介紹可參見:http://code.google.com/apis/shopping/search/v1/gettting_started.html
添加 searchForSet() 函數:
from time import sleep
import json
import urllib
def searchForSet(retX, retY, setNum, yr, numPce, origPrc):
"""
調用google 購物 api 并保證數據抽取的正確性
:param retX:
:param retY:
:param setNum:
:param yr:
:param numPce:
:param origPrc:
:return:
"""
sleep(10) # 防止短時間內有過多的 api 調用
myAPIstr = 'get from code.google.com'
searchURL = 'http://www.googleapis.com/shopping/search/v1/public/products?key=%s&country=US&q=lego+%d&alt=json' % (myAPIstr,setNum)
pg = urllib.request.urlopen(searchURL)
retDict = json.loads(pg.read())
for i in range(len(retDict['items'])):
try:
currItem = retDict['items'][i]
if currItem['product']['condition'] == 'new': # 判斷是否新產品
newFlag = 1
else: newFlag = 0
listOfInv = currItem['product']['inventories']
for item in listOfInv:
sellingPrice = item['price']
if sellingPrice > origPrc * 0.5: # 如果一個套裝的價格比原始價格低一半以上就認為是不完整,過濾掉
print("%d\t%d\t%d\t%f\t%f" % (yr, numPce, newFlag, origPrc, sellingPrice))
retX.append([yr, numPce, newFlag, origPrc])
retY.append(sellingPrice)
except:
print('problem with item %d' % i)
測試(無法訪問google api):
def setDataCollect(retX, retY):
searchForSet(retX, retY, 8288, 2006, 800, 49.99)
searchForSet(retX, retY, 10030, 2002, 3096, 269.99)
searchForSet(retX, retY, 10179, 2007, 5195, 499.99)
searchForSet(retX, retY, 10181, 2007, 3428, 199.99)
searchForSet(retX, retY, 10189, 2008, 5922, 299.99)
searchForSet(retX, retY, 10196, 2009, 3263, 249.99)
lgX = []
lgY = []
setDataCollect(lgX, lgY)
6.2 訓練算法:建立模型
上一節從網上收集到了一些真實的數據,下面將為這些數據構建一個模型。構建的模型可以對售價作出預測,并幫助我們理解現有數據。
使用常規的線性回歸:
# print(np.shape(lgX)) # (58, 4)
lgX1 = np.mat(np.ones((58,5))) # 創建一個全 1 的矩陣
lgX1[:,1:5] = np.mat(lgX) # 將原數據矩陣 lgX 復制到新數據矩陣 lgX1 的第 1 到第 5 列
ws = standRegres(lgX1, lgY) # 回歸算法
print(lgX1[0]*ws)
print(lgX1[-1]*ws)
print(lgX1[43]*ws)
使用嶺回歸確定最佳回歸系數:
def crossValidation(xArr, yArr, numVal=10):
"""
交叉驗證測試嶺回歸
:param xArr:
:param yArr:
:param numVal: 交叉驗證的次數
:return:
"""
m = len(yArr)
indexList = range(m)
errorMat = np.zeros((numVal, 30))
for i in range(numVal): # 數據分為訓練集和測試集
trainX = []
trainY = []
testX = []
testY = []
np.random.shuffle(indexList) # 對數據混洗
for j in range(m):
if j < m*0.9:
trainX.append(xArr[indexList[j]])
trainY.append(yArr[indexList[j]])
else:
testX.append(xArr[indexList[j]])
testY.append(yArr[indexList[j]])
wMat = ridgeTest(trainX, trainY) # wMat 保存嶺回歸中的所有回歸系數
for k in range(30):
# 用訓練時的參數將測試數據標準化
matTestX = np.mat(testX)
matTrainX = np.mat(trainX)
meanTrain = np.mean(matTrainX, 0)
varTrain = np.var(matTrainX, 0)
matTestX = (matTestX - meanTrain)/varTrain
yEst = matTestX * np.mat(wMat[k,:]).T + np.mean(trainY)
errorMat[i,k] = rssError(yEst.T.A, np.array(testY))
meanErrors = np.mean(errorMat, 0)
minMean = float(min(meanErrors))
bestWeights = wMat[np.nonzero(meanErrors==minMean)]
xMat = np.mat(xArr);
yMat = np.mat(yArr).T
meanX = np.mean(xMat, 0)
varX = np.var(xMat, 0)
unReg = bestWeights/varX
print("the best model from Ridge regression is :\n", unReg) # 標準化后的數據還原
print("with constant term:",-1 * sum(np.multiply(meanX, unReg)) + np.mean(yMat))
運行:
crossValidation(lgX, lgY, 10)
我們本期望找到一個更易于理解的模型,顯然沒有達到預期結果。為了達到這一點,我們來看一下在縮減過程中回歸系數是如何變化的,輸入一下的命令:
print(ridgeTest(lgX, lgY))
這些系數是經過不同程度的縮減得到的。
這種分析方法似的我們可以挖掘大量數據的內在規律。在特征比較多的時候,可以指出哪些特征時關鍵的,而哪些特征時不重要的。
7. 本章小結
在回歸方程中,求得特征對應的最佳回歸系數的方法是最小化誤差的平方差。給定輸入矩陣 X,如果 $X^TX$ 的逆存在并可以求得的話,回歸法對可以直接使用。數據集上計算出的回歸方程并不一定意味著它是最佳,可以使用預測值 yHat 和原始值 y 的相關性來度量回歸方程的好壞。