讀古今文學網 > 機器學習實戰 > 9.6 示例:樹回歸與標準回歸的比較 >

9.6 示例:樹回歸與標準回歸的比較

前面介紹了模型樹、回歸樹和一般的回歸方法,下面測試一下哪個模型最好。本節首先給出一些函數,它們可以在樹構建好的情況下對給定的輸入進行預測,之後利用這些函數來計算三種回歸模型的測試誤差。這些模型將在某個數據上進行測試,該數據涉及人的智力水平和自行車的速度的關係。

這裡的數據是非線性的,不能簡單地使用第8章的全局線性模型建模。當然這裡也需要聲明一下,此數據純屬虛構。

下面先給出在給定輸入和樹結構情況下進行預測的幾個函數。打開regTrees.py並加入如下代碼。

程序清單9-5 用樹回歸進行預測的代碼

def regTreeEval(model, inDat):
    return float(model)

def modelTreeEval(model, inDat):
    n = shape(inDat)[1]
    X = mat(ones((1,n+1)))
    X[:,1:n+1]=inDat
    return float(X*model)

def treeForeCast(tree, inData, modelEval=regTreeEval):
    if not isTree(tree): return modelEval(tree, inData)
    if inData[tree[\'spInd\']] > tree[\'spVal\']:
        if isTree(tree[\'left\']):
            return treeForeCast(tree[\'left\'], inData , modelEval)
        else:
            return modelEval(tree[\'left\'], inData)
    else:
        if isTree(tree[\'right\']):
            return treeForeCast(tree[\'right\'], inData , modelEval)
        else:
            return modelEval(tree[\'right\'], inData)

def createForeCast(tree, testData, modelEval=regTreeEval):
    m=len(testData)
    yHat = mat(zeros((m,1)))
    for i in range(m):
        yHat[i,0] = treeForeCast(tree, mat(testData[i]), modelEval)
    return yHat  
  

對於輸入的單個數據點或者行向量,函數treeForeCast會返回一個浮點值。在給定樹結構的情況下,對於單個數據點,該函數會給出一個預測值。調用函數treeForeCast時需要指定樹的類型,以便在葉節點上能夠調用合適的模型 。參數modelEval是對葉節點數據進行預測的函數的引用。函數treeForeCast自頂向下遍歷整棵樹,直到命中葉節點為止。一旦到達葉節點,它就會在輸入數據上調用modelEval函數,而該函數的默認值是regTreeEval

要對回歸樹葉節點進行預測,就調用函數regTreeEval;要對模型樹節點進行預測時,就調用modelTreeEval函數。它們會對輸入數據進行格式化處理,在原數據矩陣上增加第0列,然後計算並返回預測值。為了與函數modelTreeEval保持一致, 儘管regTreeEval只使用一個輸入,但仍保留了兩個輸入參數。

最後一個函數是createForCast,它會多次調用treeForeCast函數。由於它能夠以向量形式返回的一組預測值,因此該函數在對整個測試集進行預測時非常有用。下面很快會看到這一點。

接下來考慮圖9-6所示的數據。該數據是我從多個騎自行車的人那裡收集得到的。圖中給出騎自行車的速度和人的智商之間的關係。下面將基於該數據集建立多個模型並在另一個測試集上進行測試。對應的訓練集數據保存在文件bikeSpeedVsIq_train.txt中,而測試集數據保存在文件bikeSpeedVsIq_test.txt中。

圖9-6 人們騎自行車的速度和他們智商之間的關係數據。該數據用於比較樹回歸模型和普通的線性回歸模型

下面將為圖9-6的數據構建三個模型。首先,將程序清單9-5中的代碼保存為regTrees.py,然後在Python提示符下輸入以下命令:

>>>reload(regTrees)
  

接下來,利用該數據創建一棵回歸樹:

>>> trainMat=mat(regTrees.loadDataSet(\'bikeSpeedVsIq_train.txt\'))
>>> testMat=mat(regTrees.loadDataSet(\'bikeSpeedVsIq_test.txt\'))
>>> myTree=regTrees.createTree(trainMat, ops=(1,20))
>>> yHat = regTrees.createForeCast(myTree, testMat[:,0])
>>> corrcoef(yHat, testMat[:,1],rowvar=0)[0,1]
0.96408523182221306
  

同樣地,再創建一棵模型樹:

>>> myTree=regTrees.createTree(trainMat, regTrees.modelLeaf,
    regTrees.modelErr,(1,20))
>>> yHat = regTrees.createForeCast(myTree, testMat[:,0],
    regTrees.modelTreeEval)
>>> corrcoef(yHat, testMat[:,1],rowvar=0)[0,1]
0.9760412191380623
  

我們知道,R2值越接近1.0越好,所以從上面的結果可以看出,這裡模型樹的結果比回歸樹好。下面再看看標準的線性回歸效果如何,這裡無須導入第8章的任何代碼,本章已實現過一個線性方程求解函數linearSolve

>>> ws,X,Y=regTrees.linearSolve(trainMat)
>>> ws
matrix([[ 37.58916794],
    [ 6.18978355]])  
 

為了得到測試集上所有的yHat預測值,在測試數據上循環執行:

>>> for i in range(shape(testMat)[0]):
...     yHat[i]=testMat[i,0]*ws[1,0]+ws[0,0]
... 
  

最後來看一下R2值:

>>> corrcoef(yHat, testMat[:,1],rowvar=0)[0,1]
0.94346842356747584 
  

可以看到,該方法在R2值上的表現上不如上面兩種樹回歸方法。所以,樹回歸方法在預測複雜數據時會比簡單的線性模型更有效,相信讀者對這個結論也不會感到意外。下面將展示如何對回歸模型進行定性的比較。

下面使用Python提供的框架來構建圖形用戶界面(GUI),讀者可以使用該GUI來探究不同的回歸工具。