Linear Regression 實戰(zhàn)

本節(jié)主要介紹回歸的代碼實現(xiàn),包括線性回歸,局部加權(quán)線性回歸,嶺回歸和逐步線性回歸。

一、線性回歸

“回歸”一詞的來歷:由達爾文的表型第Galton發(fā)明。他注意到,如果雙親的高度比平均高度高,他的子女也傾向于比平均高度高,但尚不及雙親。孩子的高度向著平均高度回退(回歸)。Galton在多項研究上都注意到這個現(xiàn)象,所以盡管這個英文單詞跟數(shù)值預(yù)測沒有任何關(guān)系,但是這種研究方法仍被稱作回歸。

1、回歸系數(shù)w是怎么求得的?

本節(jié)求得回歸系數(shù)w的方法,即對(yi-xiw)2,其中的X是代表數(shù)據(jù)的矩陣,于是對回歸系數(shù)w求導(dǎo)之后令導(dǎo)數(shù)為零,得到

一定要注意的是,此處的XTX的逆矩陣一定要存在。所以必須要在代碼中對矩陣是否存在逆做出判斷。

2、標(biāo)準(zhǔn)回歸函數(shù)和數(shù)據(jù)導(dǎo)入函數(shù)代碼

(剛?cè)腴T,可能我覺得好的地方對別人來說很low,管他呢)
這個代碼分為兩段,一個是數(shù)據(jù)導(dǎo)入函數(shù)一個是標(biāo)準(zhǔn)回歸函數(shù)。
其中判斷矩陣是否可逆用行列式是否為零來判斷,numpy提供一個線性代數(shù)的庫linalg,其中包含很多有用的函數(shù)。

def loadDataSet(fileName):      
    #得到特征值的個數(shù)!把一行的個數(shù)減去標(biāo)簽數(shù)之后,就是一個數(shù)據(jù)的特征個數(shù)。方便下面的循環(huán)賦值
    numFeat = len(open(fileName).readline().split('\t')) - 1 
    dataMat = []; labelMat = []
    fr = open(fileName)
    for line in fr.readlines():
        lineArr =[]
        curLine = line.strip().split('\t')
        #將特征賦值,并且不會把標(biāo)簽添加進去
        for i in range(numFeat):
            lineArr.append(float(curLine[i]))
        dataMat.append(lineArr)
        labelMat.append(float(curLine[-1]))
    return dataMat,labelMat

def ridgeRegres(xMat,yMat,lam=0.2):
    xTx = xMat.T*xMat
    denom = xTx + eye(shape(xMat)[1])*lam
    #矩陣不可逆,也就是該矩陣行列式不等于0。
    if linalg.det(denom) == 0.0:
        print ("This matrix is singular, cannot do inverse")
        return
    ws = denom.I * (xMat.T*yMat)
    return ws

二、局部加權(quán)線性回歸

1、為什么采用局部加權(quán)線性回歸?

線性回歸有一個比較嚴(yán)重的問題,就是有可能出現(xiàn)欠擬合現(xiàn)象,因為它求的是具有最小均方誤差的無偏估計。
比較形象的說,就是用一條滿足最小均方誤差直線,去擬合所有的數(shù)據(jù),誤差是比較大的。
于是,比較好的方法,就是用部分的數(shù)據(jù),去擬合你需要預(yù)測的點,這樣的話,誤差就不是很大。
局部加權(quán)線性回歸和KNN類似,該模型認(rèn)為樣本點距離越近,越可能符合同一個線性模型。

2、局部加權(quán)線性回歸的w和W

小w還是回歸系數(shù)。
W代表的是一個只含有對角元素的權(quán)重矩陣。二者關(guān)系如下

由公式可見,直接效果就是所有的樣本點數(shù)據(jù)都會有一個權(quán)值。
LWLR使用“核”來調(diào)節(jié)樣本點的權(quán)重,使得距離需要預(yù)測的點越近得到樣本點權(quán)重更大。核的類型可以自由選擇,最常用就是高斯核(高斯分布中的exp),其對應(yīng)的權(quán)重如下:


上述公式的目的,就是使得**預(yù)測點x與樣本點x(i)越近,權(quán)值w(i,i)就會越大。

該公式包含了一個 參數(shù)k它決定了對附近的點賦予多大的權(quán)重,也是LWLR唯一需要考慮的參數(shù)。k越小,權(quán)值就衰減的越快,則被用上的局部點就越少,但是相對的也可能會考慮太多的噪聲,導(dǎo)致過擬合現(xiàn)象。

k=1,k=0.01,k=0.003

如上圖,平滑參數(shù)k分別是1,0.01和0.003時的情況。可以看到,k=1時模型效果跟最小二乘法差不多,k=0.01時該模型可以挖掘數(shù)據(jù)的潛在規(guī)律,而k=0.003時,考慮了太多的噪聲,導(dǎo)致了過擬合。

3、代碼實現(xiàn)

此模型的代碼,和標(biāo)準(zhǔn)線性回歸模型的代碼相比,只是增加了一個W矩陣。因此,需要先給W賦初值(對角矩陣)以后,再計算矩陣中元素,再按照,模型計算即可。

#只對一個點進行測試
def lwlr(testPoint,xArr,yArr,k=1.0):
    xMat = mat(xArr); yMat = mat(yArr).T
    #用此方法計算出樣本數(shù)量
    m = shape(xMat)[0]
    #先給w矩陣賦初值,先弄明白矩陣w的shape
    weights = mat(eye((m)))
    #對每個樣本點計算一次權(quán)重
    for j in range(m):                    
        diffMat = testPoint - xMat[j,:]     
        weights[j,j] = exp(diffMat*diffMat.T/(-2.0*k**2))
    xTx = xMat.T * (weights * xMat)
    if linalg.det(xTx) == 0.0:
        print "This matrix is singular, cannot do inverse"
        return
    ws = xTx.I * (xMat.T * (weights * yMat))
    return testPoint * ws

#將所有需要測試的點,用testArr傳入,再用上面函數(shù)挨個測試,返回所有預(yù)測的值

def lwlrTest(testArr,xArr,yArr,k=1.0): 
    #得到所有預(yù)測點的總數(shù)以后再構(gòu)造一個相同數(shù)目的列表
    m = shape(testArr)[0]
    yHat = zeros(m)
    for i in range(m):
        yHat[i] = lwlr(testArr[i],xArr,yArr,k)
    return yHat

上面代碼,比較好的是,整體的思想。一個功能就是一個函數(shù),只需要把數(shù)據(jù)整體傳入,得到整體需要預(yù)測的數(shù)據(jù)。

但是,局部加權(quán)線性回歸也存在一個問題:增加了計算量,因為它對每個點做預(yù)測時都必須使用整個數(shù)據(jù)集。然而,大多數(shù)據(jù)點的權(quán)重都接近與零,所以,如果避免這些計算,將可以減少程序運行時間,緩解計算量。

三、嶺回歸

首先需要注意的是,嶺回歸和局部加權(quán)線性回歸沒有聯(lián)系。二者都是和標(biāo)準(zhǔn)線性回歸進行比較的。
局部加權(quán)線性回歸是通過設(shè)置權(quán)值來利用局部樣本點預(yù)測的。
嶺回歸是用在數(shù)據(jù)的特征比樣本點還多的情況,通過增加正則項,縮減不必要的特征參數(shù),使得我們可以挖掘大量數(shù)據(jù)的內(nèi)在規(guī)律。

優(yōu)點:

比如,經(jīng)過嶺回歸訓(xùn)練之后,返回回歸系數(shù),會發(fā)現(xiàn)有的特征比別的特征大很多倍。(書中最后測試,第4項特征比第2項系數(shù)大5倍,比第1項大57倍,所以如果只能選擇一個特征進行預(yù)測,我們應(yīng)該選擇第4個特征。)
再如,當(dāng)數(shù)據(jù)由100個以上的特征的時候,嶺回歸就會十分有效:它可以指出哪些特征是關(guān)鍵的,哪些特征是不重要的。

1、嶺回歸中的嶺是什么?

嶺回歸中是用單位矩陣乘以 常量lambda,其中的單位矩陣I,值1貫穿整個對角線,其余元素全是0,在0構(gòu)成的平面上有一條1組成的“嶺”,這就是嶺回歸中的“嶺”的由來。

2、怎么理解嶺回歸(最小二乘后面加上正則項)?

2.1 理論

如果數(shù)據(jù)的特征比樣本點還多怎么辦?此時X不是滿秩矩陣,求逆就會出現(xiàn)錯誤。比如shape(X)=(3,10),那么shape(XTX)=(10,10)。于是出現(xiàn)了一種方法:嶺回歸。

從最優(yōu)化理論上理解嶺回歸的作用,一般三個方面:矩陣滿秩,正則項,過擬合。
知乎上guosc的回答容易理解:guosc[嶺回歸與最小二乘的區(qū)別]

直觀上來說訓(xùn)練數(shù)據(jù)較少時容易發(fā)生過擬合,過擬合曲線會盡可能擬合所有數(shù)據(jù)點,包括噪音點,此時由于函數(shù)的導(dǎo)數(shù)較大,因此系數(shù)較大,為了避免過擬合需要減小系數(shù),正則化就是通過對系數(shù)進行懲罰以減小系數(shù)。這樣得到的會是一條光滑的曲線,會有較好的泛化性能。

以上說明了嶺回歸中加上正則項的作用:不會過擬合。

2.2 縮減系數(shù)可視化

和最優(yōu)化問題中連接起來,嶺回歸就是在最小二乘后面加上懲罰項,當(dāng)后面的lambda越大時,前面的回歸系數(shù)就會變小(用書中的話來說就是 縮減),達到縮減不必要的參數(shù)的目的。

從上圖可以看出,隨著lambda的不斷增大,各個特征值的回歸系數(shù)會不斷縮小,我們可以在中間的某處(15-20)找的使得預(yù)測結(jié)果最好的lambda值。或者說,此時我們可以看出哪個特征是重要的(比如藍線比較重要),哪個是不重要的(接近零的線)。從而判斷出“不必要的參數(shù)”,提取出重要的特征。

2.3 公式

在最小二乘后面加上二范數(shù)的正則項以后,同標(biāo)準(zhǔn)線性回歸一樣,用矩陣求解的方法,可以得到此時的回歸系數(shù):

3、嶺回歸的代碼實現(xiàn)(縮減系數(shù)可視化)

3.1、代碼敘述
  • 1、嶺回歸中的權(quán)值w代碼,按照上面公式推算就行,其中對角矩陣的shape要通過數(shù)據(jù)矩陣xMat得到,行數(shù)為shape(xMat)[1]。即數(shù)據(jù)的特征個數(shù)。對角矩陣用eye()得到。
  • 2 因為每個特征的屬性不一樣,為了使用嶺回歸和縮減技術(shù),首先需要對特征做標(biāo)準(zhǔn)化處理,是每維特征具有相同的重要性。個人覺得是嶺回歸中w的求解公式中加上了lambda對角陣,為了使lambda對每個特征的影響都相同,所以需要標(biāo)準(zhǔn)化每個特征。

下面代碼中數(shù)據(jù)標(biāo)準(zhǔn)化的過程,是所有特征都減去各自的均值并除以方差。(代碼中有的方法和書中所述有些出入)

3.2 代碼
def ridgeRegres(xMat,yMat,lam=0.2):
    xTx = xMat.T*xMat
    denom = xTx + eye(shape(xMat)[1])*lam
    #仍然需要檢查行列式是否為零,因為如果lambda設(shè)定為0的時候,也會產(chǎn)生錯誤
    if linalg.det(denom) == 0.0:
        print ("This matrix is singular, cannot do inverse")
        return
    ws = denom.I * (xMat.T*yMat)
    return ws

#在30個不同的lambda下調(diào)用ridgeRegres函數(shù),返回一個回歸系數(shù)構(gòu)成的矩陣
def ridgeTest(xArr,yArr):
    xMat = mat(xArr); yMat=mat(yArr).T
    yMean = mean(yMat,0)
    yMat = yMat - yMean     #to eliminate X0 take mean off of Y
    #regularize X's
    xMeans = mean(xMat,0)   #calc mean then subtract it off
    xVar = var(xMat,0)      #calc variance of Xi then divide by it
    xMat = (xMat - xMeans)/xVar
    #第一步,給矩陣賦初值
    numTestPts = 30
    wMat = zeros((numTestPts,shape(xMat)[1]))
    for i in range(numTestPts):
        ws = ridgeRegres(xMat,yMat,exp(i-10))
        #第二步,給矩陣的每一行,賦值。ws返回的是一個列向量,所以需要轉(zhuǎn)置
        wMat[i,:]=ws.T
    return wMat

四、前向逐步回歸

1、算法簡介

前向逐步回歸屬于一種貪心算法==> 每一步都盡可能減少誤差
大致實現(xiàn)就是,每次增大或減小當(dāng)前的某一個特征,得到一個新的W,計算新W下的誤差,如果新W得到的誤差小于舊的W所得的誤差,那么就用新的W替換舊的W。不斷循環(huán),直至收斂。

2 、代碼實現(xiàn)

下面是代碼實現(xiàn)。其中需要注意的是,在替換W的步驟中,為了不原地改變列表,用了copy的方法。

def stageWise(xArr,yArr,eps=0.01,numIt=100):
    xMat = mat(xArr); yMat=mat(yArr).T
    yMean = mean(yMat,0)
    #這地方并沒有進行標(biāo)準(zhǔn)化,右邊有解釋
    yMat = yMat - yMean     #can also regularize ys but will get smaller coef
    xMat = regularize(xMat)
    m,n=shape(xMat)
    #returnMat = zeros((numIt,n)) #testing code remove
    ws = zeros((n,1)); wsTest = ws.copy(); wsMax = ws.copy()
    for i in range(numIt):
        print (ws.T)
        lowestError = inf;  #設(shè)置誤差初始值為無窮
        for j in range(n):
            for sign in [-1,1]:
                wsTest = ws.copy()
                wsTest[j] += eps*sign   #每次增加或減少第j個特征的eps倍
                yTest = xMat*wsTest
                rssE = rssError(yMat.A,yTest.A)
                #如果新的誤差小于舊的誤差,就替換誤差和W
                if rssE < lowestError:
                    lowestError = rssE
                    wsMax = wsTest
        ws = wsMax.copy()
        returnMat[i,:]=ws.T
    return returnMat

3、算法優(yōu)點

逐步線性回歸算法的主要優(yōu)點,在于它可以幫助人們理解現(xiàn)有的模型并作出改進。當(dāng)構(gòu)建了一個模型后,可以運行該算法找出重要的特征。能夠及時停止對那些不重要特征的收集。(比如,原數(shù)據(jù)有6個特征,運行此算法之后發(fā)現(xiàn)w1和w6還是沒有變化,就說明這兩個特征不對目標(biāo)值造成任何影響,也就意味著這兩個特征很可能是不需要的。)

五、方差與偏差

1、定義

方差:指的是模型之間的差異。
偏差:指的是模型預(yù)測值和數(shù)據(jù)真實值之間的差異。

模型之間的差異:比如從數(shù)據(jù)中取一根隨機樣本集(隨機取100個數(shù)據(jù))并用線性模型擬合,將會得到一組回歸系數(shù)w1、再取出另一組隨機樣本集并擬合,得到另一組回歸系數(shù)w2。那么w1和w2之間的差異大小,就是模型方差大小的反映。

2、二者之間的權(quán)衡

方差低(一般來說兩組線性模型的擬合系數(shù)差異相對小些,比如標(biāo)準(zhǔn)線性回歸不同的隨機樣本集,回歸系數(shù)差別不大),也就是說,模型復(fù)雜度較低(可能該模型干脆就是線性模型),比較不容易擬合數(shù)據(jù),預(yù)測數(shù)據(jù)不是很準(zhǔn)確,于是偏差高

方差高(非線性模型的擬合系數(shù)差異相對比較大,比如局部加權(quán)線性回歸,不同數(shù)據(jù),系數(shù)差異肯定比較大),也就是說,模型復(fù)雜度高(比如特征含有x6的這種模型),容易擬合數(shù)據(jù),數(shù)據(jù)預(yù)測相對準(zhǔn)確。但也容易過擬合,換了數(shù)據(jù)集之后,也會出現(xiàn)偏差高的情況。

應(yīng)該在二者之間權(quán)衡,找到最適合的方差和偏差。
其實也就是,模型不能太復(fù)雜,不然容易過擬合,也不能太簡單,容易欠擬合。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,703評論 2 380

推薦閱讀更多精彩內(nèi)容