樹回歸演算法之通俗講解

2021-10-24 08:59:23 字數 4017 閱讀 7384

本章也是**數值型資料,非分類演算法。

前面介紹了線性回歸**數值型資料,但是有不足:

(1)需要擬合所有的樣本點(區域性加權線性回歸除外)

(2)當資料擁有眾多特徵且特徵之間關係十分複雜時,構建全域性模型的想法就顯得很難了,也略顯笨拙。

(3)實際生活中很多問題都是非線性的,不可能使用全域性線性模型來擬合任何資料。

所以就用到了樹回歸,樹結構和回歸法結合。

樹回歸是通過構建樹,來對連續性數值型(回歸)資料進行**。所以首先構建樹,將構建兩種樹:回歸樹和模型樹,然後分別使用者回歸。

(1)回歸樹(regression tree),其每個葉節點包含單個值。

(2)模型樹(model tree),其每個葉節點包含乙個線性方程。

cart(classification and regression trees,分類回歸樹)是一種樹構建演算法。該演算法既可以用於分類還可以用於回歸。cart演算法採用二元切分來處理連續型變數,對cart稍作修改就可以處理回歸問題。

前面講到過決策樹,用的是id3演算法構建樹,非二元切分,而是按照特徵的所有可能取值類切分。

回歸樹與分類樹的思路類似,但是節點的資料型別不是離散型,而是連續型。

為了適用於後面的兩種樹回歸的構建,cart演算法中包含兩個可選引數,決定了樹的型別:leaftype給出建立葉節點(常數或線性方程)的函式;errtype代表誤差計算函式(回歸樹和模型樹就計算誤差不同)。

葉節點:回歸樹的葉節點是乙個常數值(平均值)。

誤差:決策樹進行分類時,判斷資料集是否充分切分的度量方法是計算資料的混亂度,用到了資訊熵。那麼如何計算連續型數值的混亂度呢?回歸樹用到的方法是計算總方差。首先計算所有資料的均值,然後計算每條資料的值到均值的差值,為了對正負差值同等看待,一般使用絕對值或平方值來代替上述差值,類似統計學中的方差計算,不同之處在於方差是平方誤差的均值(均方差),這裡用到的是平方誤差的總值(總方差)。總方差可以通過均方差乘以資料集中樣本點的個數來得到。

停止條件:回歸樹的停止條件有三種情況,不會再切分,而是直接建立葉節點。

(1)不同剩餘特徵值的數目如果為1,則說明就乙個不同大小的值了,不需要繼續切分了。

(2)切分資料集後效果提公升不夠大,小於自定義誤差引數值,就不應該進行切分操作而直接建立葉節點。

(3)切分後的子集大小如果小於使用者定義的引數,也不應該切分了。

三、回歸樹避免過擬合

一棵樹如果節點過多,表明該模型可能對資料進行了「過擬合」。通過降低樹的複雜度來避免過擬合的過程稱為剪枝(pruning)。剪枝分為預剪枝(prepruning)和後剪枝(postpruning)。

預剪枝使用引數進行調整以提前終止條件(第三節的切分停止條件即為預剪枝對引數的調整),預剪枝的缺點是需要不斷修改停止條件(即引數值)來得到合理的結果,但事實上,我們常常甚至不確定到底需要尋找什麼樣的結果。後剪枝需要使用測試集和訓練集進行調整,利用測試集來對樹進行剪枝,由於不需要使用者指定引數,後剪枝是乙個更理想化的剪枝方法。

後剪枝因為用到了遞迴,每次到樹到遞迴就一下子看程式看不太懂,所以就每步詳細分析,分析結果加以介紹。

後剪枝需要將資料集分成訓練集和測試集,使用訓練集構建一棵樹,樹足夠大,足夠複雜,便於剪枝。然後利用測試集資料對樹進行剪枝,從上而下找到葉節點,用測試集來判斷將這些葉節點合併是否能降低測試誤差,如果能就合併。

剪枝函式prune()的偽**如下:       

基於已有的樹切分測試資料:

如果存在任一子集是一棵樹,則在該子集遞迴剪枝過程

計算將當前兩個葉節點合併後的誤差

計算不合併的誤差

如果合併會降低誤差的話,就將葉節點合併

基於已有的樹切分測試資料:

如果存在任一子集是一棵樹,則在該子集遞迴剪枝過程

計算將當前兩個葉節點合併後的誤差

計算不合併的誤差

如果合併會降低誤差的話,就將葉節點合併

程式清單:       

def istree(obj):

return (type(obj).__name__=='dict')

def getmean(tree):

if istree(tree['right']):

tree['right'] = getmean(tree['right'])

if istree(tree['left']):

tree['left'] = getmean(tree['left'])

return (tree['left'] + tree['right'])/2.0

def prune(tree, testdata):

if shape(testdata)[0] == 0:

return getmean(tree)

if (istree(tree['right']) or istree(tree['left'])):

lset, rset = binsplitdataset(testdata, tree['spind'], tree['spval'])

if istree(tree['left']):

tree['left'] = prune(tree['left'], lset)

if istree(tree['right']):

tree['right'] = prune(tree['right'], rset)

if not istree(tree['left']) and not istree(tree['right']):

lset, rset = binsplitdataset(testdata, tree['spind'], tree['spval'])

errornomerge = sum(power(lset[:, -1] - tree['left'], 2)) + sum(power(rset[:, -1] - tree['right', 2]))

treemean = (tree['left'] + tree['right'])/2.0

errormerge = sum(power(testdata[:, -1] - treemean, 2))

if errormerge < errornomerge:

print('merging')

return treemean

else:

print tree

else:

return tree

主函式prune()有兩個引數:待剪枝的樹與剪枝所需的測試資料testdata。首先需要確認測試集是否為空。一旦非空,則反覆遞迴呼叫函式prune()對測試資料進行切分。

接下來檢查某個分支到底是子樹還是節點。如果是子樹,就呼叫函式prune()來對該子樹進行剪枝,直到左右分支都為節點,遞迴結束,考慮是否可以合併(根據合併前和合併後的誤差計算)。不管是否合併,都會返回乙個值或樹,再依次向上遞迴,直到結束。**具體分析如下:

後剪枝可以把大量節點剪枝掉,但可能沒有像預期的那樣剪枝成兩部分,這說明後剪枝可能不如預剪枝有效。一般地,為了尋求最佳模型可以同時使用兩種剪枝技術。

四、模型樹

葉節點:模型樹的葉節點不是簡單的常數值,而是把葉節點設定為分段線性函式,分段線性是指模型由多個線性片段組成。模型樹將資料進行切分,每份切分資料都能很容易被線性模型(利用線性回歸函式計算回歸係數)所表示。

誤差:那麼怎麼找到最佳切分?還是以誤差最小。怎麼計算誤差?這裡不能用回歸樹的計算誤差方式,對於給定的資料集,應該先用線性的模型來對它進行擬合,然後計算真實目標值與模型**值間的差值,最後將這些差值的平方求和就得到了所需的誤差。

停止條件:跟回歸樹是一樣的,因為都用的cart通用演算法構建樹。

模型樹和回歸樹構建樹、**值得邏輯是一樣的,只是生成葉節點的模型不同,乙個是線性方程,乙個是浮點數。還有就是誤差計算方法不同。

通俗易懂 線性回歸演算法講解 演算法 案例

1.7python實現 github位址 加資料 我們首先用弄清楚什麼是線性,什麼是非線性。相信通過以上兩個概念大家已經很清楚了,其次我們經常說的回歸回歸到底是什麼意思呢。對大量的觀測資料進行處理,從而得到比較符合事物內部規律的數學表示式。也就是說尋找到資料與資料之間的規律所在,從而就可以模擬出結果...

通俗易懂 邏輯回歸演算法講解 演算法 案例

尋覓網際網路,少有機器學習通俗易懂之演算法講解 案例等,專案立於這一問題之上,整理乙份基本演算法講解 案例於文件,供大家學習之。通俗易懂之文章亦不可以面概全,但凡有不正確或爭議之處,望告知,自當不吝賜教!github位址 加資料 邏輯回歸是用來做分類演算法的,大家都熟悉線性回歸,一般形式是y ax ...

通俗易懂 線性回歸演算法講解 演算法 案例

github位址 加資料 我們首先用弄清楚什麼是線性,什麼是非線性。相信通過以上兩個概念大家已經很清楚了,其次我們經常說的回歸回歸到底是什麼意思呢。對大量的觀測資料進行處理,從而得到比較符合事物內部規律的數學表示式。也就是說尋找到資料與資料之間的規律所在,從而就可以模擬出結果,也就是對結果進行 解決...