摘要:本文分別介紹了線性回歸、局部加權回歸和嶺回歸,並使用python進行了簡單實現。
在這之前,已經學習過了Logistic回歸,今天繼續看回歸。首先說一下回歸的由來:回歸是由達爾文的表兄弟Francis Galton發明的。Galton於1877年完成了第一次回歸預測,目的是根據上一代豌豆的種子(雙親)的尺寸來預測下一代豌豆種子(孩子)的尺寸(身高)。Galton在大量對象上應用了回歸分析,甚至包括人的身高。他得到的結論是:如果雙親的高度比平均高度高,他們的子女也傾向於平均身高但尚不及雙親,這里就可以表述為:孩子的身高向着平均身高回歸。Galton在多項研究上都注意到了這一點,並將此研究方法稱為回歸,接下來就上文提到的三種回歸一一介紹:
一 線性回歸(Linear Regression)
1. 線性回歸概述
回歸的目的是預測數值型數據的目標值,最直接的方法就是根據輸入寫出一個求出目標值的計算公式,也就是所謂的回歸方程,例如y = ax1+bx2,其中求回歸系數的過程就是回歸。那么回歸是如何預測的呢?當有了這些回歸系數,給定輸入,具體的做法就是將回歸系數與輸入相乘,再將結果加起來就是最終的預測值。說到回歸,一般指的都是線性回歸,當然也存在非線性回歸,在此不做討論。
假定輸入數據存在矩陣x中,而回歸系數存放在向量w中。那么對於給定的數據x1,預測結果可以通過y1 = x1Tw給出,那么問題就是來尋找回歸系數。一個最常用的方法就是尋找誤差最小的w,誤差可以用預測的y值和真實的y值的差值表示,由於正負差值的差異,可以選用平方誤差,也就是對預測的y值和真實的y值的平方求和,用矩陣可表示為:(y - xw)T(y - xw),現在問題就轉換為尋找使得上述矩陣值最小的w,對w求導為:xT(y - xw),令其為0,解得:w = (xTx)-1xTy,這就是采用此方法估計出來的
2.python實現
結合上述的分析,采用python實現,首先,導入數據:
#導入數據 def loadData(fileName): numFeat = len(open(fileName).readline().split('\t')) - 1 dataMat = [] labelMat = [] fr = open(fileName) for line in fr.readlines(): linArr = [] curline = line.strip().split('\t')#得到每行,並以tab作為間隔 for i in range(numFeat): linArr.append(float(curline[i])) dataMat.append(linArr) labelMat.append(float(curline[-1])) return dataMat,labelMat
之后,求解回歸系數:
#計算回歸系數
from numpy import * def standRegres(x,y): xMat = mat(x) yMat = mat(y).T xTx = xMat.T*xMat #采用numpy中的線性代數庫linalg,其中linalg.det直接可以計算行列式 if linalg.det(xTx) == 0.0: print "這個行列式是錯誤的的,不能求逆" return #求回歸系數 w = xTx.I * (xMat.T * yMat) return w
求得了回歸系數,結合輸入就可以得到回歸方程,為了直觀的表示,采用Matplotlib繪圖:
x,y = loadData("ex0.txt") w = standRegres(x,y) xMat = mat(x) yMat = mat(y) #繪制原數據點 fig = plt.figure() ax = fig.add_subplot(111) ax.scatter(xMat[:,1].flatten().A[0],yMat.T[:,0].flatten().A[0]) #<matplotlib.collections.CircleCollectin object at 0x04ED9D30> #plt.show() #在之前的圖像上繪制出擬合直線 xCopy = xMat.copy() xCopy.sort(0) yHat = xCopy*w ax.plot(xCopy[:,1],yHat) plt.show()
結果如下圖:

至此擬合就結束了,那么如何評判擬合的好壞?numpy庫提供了相關系數的計算方法,通過命令corrcoef()可以來計算預測值和真實值的相關性。
yHat = xMat * w print corrcoef(yHat.T,yMat)
分析結果我們可以看出線性回歸得到的相關性還是挺理想的,但是從圖像中明顯可以看出線性回歸未能捕獲到一些數據點,沒能很好的表示數據的變化趨勢,在某種情況下存在欠擬合的情況,這是線性回歸的一個缺點。在此想要說明的一點是,要只是簡單的實現擬合的話,不妨采用MATLAB中的cftool的工具,簡單高效直觀。
二 局部加權線性回歸
(Locally Weighted Linear Regression,LWLR)
1.概述
針對於線性回歸存在的欠擬合現象,可以引入一些偏差得到局部加權線性回歸對算法進行優化。在該算法中,給待測點附近的每個點賦予一定的權重,進而在所建立的子集上進行給予最小均方差來進行普通的回歸,分析可得回歸系數w可表示為:
w = (xTWx)-1xTWy,其中W為每個數據點賦予的權重,那么怎樣求權重呢,核函數可以看成是求解點與點之間的相似度,在此可以采用核函數,相應的根據預測點與附近點之間的相似程度賦予一定的權重,在此選用最常用的高斯核,則權重可以表示為:w(i,i) = exp(|x(i) - x| / -2k2),其中K為寬度參數,至於此參數的取值,目前仍沒有一個確切的標准,只有一個范圍的描述,所以在算法的應用中,可以采用不同的取值分別調試,進而選取最好的結果。
2.python實現
結合上述的分析,采用python編程實現,代碼如下:
def lwlr(testPoint,xArr,yArr,k): xMat = mat(xArr) yMat = mat(yArr).T m = shape(xMat)[0] weights = mat(eye((m))) for i in range(m): weights[i,i] = exp((testPoint - xMat[i,:])*(testPoint - xMat[i,:]).T / (-2.0*k**2)) xTx = xMat.T * (weights * xMat) if linalg.det(xTx) == 0: print "輸入有誤" return ws = xTx.I * xMat.T * weights * yMat return testPoint * ws #為數據點中的每個數據調用lwlr def lwlrTest(testArr,xArr,yArr,k): m = shape(testArr)[0] yHat = zeros(m) for i in range(m): yHat[i] = lwlr(testArr[i],xArr,yArr,k) return yHat
結合上述分析,我們可以選取不同的k值分別求得結果,進而采用Matplotlib繪圖直觀的表示,在此,分別選取k = 1,0.01,0.002,代碼如下:
#test x,y = loadData("ex0.txt") a = lwlr(x[0],x,y,0.002) b = lwlrTest(x,x,y,0.002) #采用matplotlib繪制圖像 xMat = mat(x) srtInd = xMat[:,1].argsort(0)#按升序排序,返回下標 xSort = xMat[srtInd][:,0,:]#將xMat按照升序排列 fig = plt.figure() ax = fig.add_subplot(111) ax.plot(xSort[:,1],b[srtInd]) ax.scatter(xMat[:,1].flatten().A[0],mat(y).T.flatten().A[0],s = 2,c = 'red') plt.show()
最終結果分別如下,依次為k = 1,0.01,0.002對應的結果:



可以看出,當k = 1時,結果和線性回歸使用最小二乘法的結果相似,而k=0.001時噪聲太多,屬於過擬合的情況,相比之下,k = 0.01得到的結果更理想。雖然LWLR得到了較為理想的結果,但是此種方法的缺點是在對每個點進行預測時都必須遍歷整個數據集,這樣無疑是增加了工作量,並且該方法中的的寬度參數的取值對於結果的影響也是蠻大的。同時,當數據的特征比樣本點還多當然是用線性回歸和之前的方法是不能實現的,當特征比樣本點還多時,表明輸入的矩陣X不是一個滿秩矩陣,在計算(XTX)-1時會出錯。
三 嶺回歸
1.概述
為了解決上述問題,統計學家引入了“嶺回歸”的概念。簡單說來,嶺回歸就是在矩陣XTX上加上一個λr,從而使得矩陣非奇異,從而能對XTX + λx求逆。其中矩陣r為一個m*m的單位矩陣,對角線上的元素全為1,其他元素全為0,而λ是一個用戶定義的數值,這種情況下,回歸系數的計算公式將變為:w = (xTx+λI)-1xTy,其中I是一個單位矩陣。
嶺回歸就是用了單位矩陣乘以常量λ,因為只I貫穿了整個對角線,其余元素為0,形象的就是在0構成的平面上有一條1組成的“嶺”,這就是嶺回歸中嶺的由來。
嶺回歸最先是用來處理特征數多與樣本數的情況,現在也用於在估計中加入偏差,從而得到更好的估計。這里引入λ限制了所有w的和,通過引入該懲罰項,能夠減少不重要的參數,這個技術在統計學上也叫做縮減。縮減方法可以去掉不重要的參數,因此能更好的理解數據。在此,選取不同的λ進行測試,最后得到一個使得誤差最小的λ。
2.python實現
結合上述的分析,同樣采用python實現,代碼如下:
def ridgeRegress(xMat,yMat,lam = 0.2):#在沒給定lam的時候,默認為0.2 xTx = xMat.T*xMat denom = xTx + eye(shape(xMat)[1])*lam if linalg.det(denom) == 0.0: print "這個矩陣是錯誤的,不能求逆" return ws = denom.I * (xMat.T * yMat) return ws #對數據進行標准化之后,調用30個不同的lam進行計算 def ridgeTest(xArr,yArr): xMat = mat(xArr) yMat = mat(yArr).T yMean = mean(yMat,0) yMat = yMat - yMean xMeans = mean(xMat,0) xVar = var(xMat,0) xMat = (xMat - xMeans)/xVar numTestPts = 30 wMat = zeros((numTestPts,shape(xMat)[1])) for i in range(numTestPts): ws = ridgeRegress(xMat,yMat,exp(i-10)) wMat[i,:]=ws.T return wMat
進而采用matplotlib繪圖得到在30個不同的lam下回歸系數的變化情況,如下圖:

由該圖可以看出,lam很小時,系數和普通回歸一樣,而當lam非常大時,所有的回歸系數縮減為0,可以看出在中間某處可以找到使得預測結果最好的lam值。 為了選取最優的lam值,可以采取交叉驗證法。
總結:與分類一樣,回歸是預測目標值的過程。回歸與分類的不同在於回歸預測的是連續型變量,而分類預測的是離散型的變量。回歸是統計學中最有力的工具之一。如果給定輸入矩陣x,xTx的逆如果存在的話回歸法可以直接使用,回歸方程中的求得特征對應的最佳回歸系數的方法是最小化誤差的平方和,判斷回歸結果的好壞可以利用預測值和真實值之間的相關性判斷。當數據樣本總個數少於特征總數時,矩陣x,xTx的逆不能直接計算,這時可以考慮嶺回歸。
