1. 程式人生 > >線性迴歸數值型預測:預測鮑魚的年齡

線性迴歸數值型預測:預測鮑魚的年齡

線性迴歸數值型預測:預測鮑魚的年齡

一、實驗準備

1、實驗內容和目的

  • 根據訓練集中給出的鮑魚的各項生物特徵引數以及其年齡,進行處理和擬合。然後使用擬合出來的模型來預測測試集中鮑魚的年齡

  • 其中訓練集為檔案train.txt,測試集為檔案test.txt。訓練集中的每個樣本有8個特徵引數,最後的數字為其年齡;而測試集合中只存放每個樣本的8個特徵引數

2、實驗原理

  • 前面學習的KNN分類演算法和樸素貝葉斯分類演算法的目標變數是標稱型資料,而回歸則是對連續型的資料做出處理,迴歸的目的是預測數值型資料的目標值
2.1 關於迴歸的背景瞭解
  • 迴歸的目的是預測數值型的目標值。最直接的方法就是依據輸入寫出一個目標值的計算公式。比如要計算一輛車的馬力大小,可能會這麼計算:

    H o r s e

    P o w e r = 0.0015
    a n n u a l S a l a r y 0.99 h o u r s e L i s t e n i n g T o P u b l i c R a d i o HorsePower = 0.0015*annualSalary - 0.99*hourseListeningToPublicRadio

  • 這就是所謂的迴歸方程,其中的0.0015和-0.99稱作迴歸係數,求這些迴歸係數的過程就是迴歸。一旦有了這些迴歸係數,再給定輸入,做預測就非常容易了。具體的做法是用迴歸係數乘以輸入值,再將結果相加,就能得到預測值

2.2 用線性迴歸找到最佳擬合直線
  • 大致的原理已經知道了,那麼應當怎麼從一大堆資料裡求出迴歸方程呢?假定輸入資料在矩陣 x \mathbf{x} 中,而回歸係數存放在向量 w \mathbf{w} 中。那麼對於給定的資料 x 1 x_1 ,預測結果將會通過 Y 1 = x 1 T w Y_1=x_1^T\mathbf{w} 給出。現在的問題是,手裡有一些x和對應的y,怎樣才能好到 w \mathbf{w} 呢?一個常用的方法就是找出使誤差最小的 w \mathbf{w} 。這裡的誤差是指預測y值和真實y值之間的差值,使用該誤差的簡單累加會使得正差值和負差值相互抵消,所以採用平方誤差

  • 平方誤差可以寫為:

    i = 1 m ( y i x i T w ) 2 \sum_{i=1}^{m}(y_i-x_i^T\mathbf{w})^2

  • 用矩陣表示還可以寫做 ( y x w ) T ( y x w ) (y-x\mathbf{w})^T(y-x\mathbf{w}) 。如果對 w \mathbf{w} 求導,得到 x T ( y x w ) x^T(y-x\mathbf{w}) ,令其等於零,解得 w \mathbf{w} 如下:

    w ^ = ( X T X ) 1 X T y \hat{\mathbf{w}}=(X^TX)^{-1}X^Ty

  • 值得注意的是,上述的公式中包含 ( X T X ) 1 (X^TX)^{-1} ,也就是需要對矩陣求逆,因此這個方程只在逆矩陣存在的時候適應。然而,矩陣的逆有可能不存在,因此必須要在程式碼中對此作出判斷

2.3 區域性加權線性迴歸
  • 如果單純的使用上述線性迴歸的方法,會出現欠擬合的問題,因為它求的是具有最小均方誤差的無偏估計。顯而易見,如果模型欠擬合將不能取得最好的預測效果。所以在此次預測任務中採用了局部加權線性迴歸演算法

  • 在區域性加權線性迴歸演算法中,我們給待預測點附近的每個點賦予一定的權重;然後與2.1中的解法類似,在這個子集上基於最小均方差來進行普通的迴歸。該演算法解出迴歸係數 w \mathbf{w} 的形式如下:

    w ^ = ( X T W X ) 1 X T W y \hat{\mathbf{w}}=(X^TWX)^{-1}X^TWy

  • 其中 W W 是一個矩陣,用來給每個資料點賦予權重。區域性加權線性迴歸演算法使用“核”來對附近的點賦予更高的權重。核的型別可以自由選擇,最常用的核就是高斯核,高斯核對應的權重如下:

    w ( i , i ) = e x p ( x ( i ) x 2 k 2 ) w(i,i)=exp(\frac{\big|{x^{(i)}-x}\big|}{-2k^2})

二、進行實驗

1、演算法思路

  • 使用區域性加權迴歸演算法,對訓練資料進行擬合操作。其中,通過高斯核引數k的調整來提高擬合效果;同時,對比在縮減不同特徵項的情況下得到的擬合效果,取最優

2、演算法步驟

  • (1) 對訓練資料進行處理,提出每個訓練樣本的特徵引數集以及y值

  • (2) 對測試資料進行處理,提出每個測試樣本的特徵引數集

  • (3) 使用區域性加權迴歸演算法對訓練資料進行擬合,得到係數w

  • (4) 使用擬合得到的係數w,計算測試樣本對應的y值

3、程式碼實現

  • 注:程式碼中的所有函式功能已註釋在函式頭部

  • (1) 處理訓練資料和測試資料。因為訓練資料中的每個樣本包含y值而測試資料中的樣本不包含,因此使用兩個不同的功能函式分別進行處理

def loadTrainData(filename):
    """
    函式說明:
        載入訓練資料
    :param filename:
        檔名
    :return:
        xArray - x資料集,即為每個訓練樣本的特徵引數
        yArray - y資料集,即為每個訓練樣本的年齡
    """
    featNum = len(open(filename).readline().split(',')) - 2 # 特徵引數的個數,其中舍掉了第一個性別特徵

    file = open(filename)
    xArray = []
    yArray = []
    for line in file.readlines():
        tempLine = line.strip().split(',')
        '''
        if tempLine[0] == 'M':
            tempLine[0] = '1'
        elif tempLine[0] == 'F':
            tempLine[0] = '-1'
        else:
            tempLine[0] = '0'
        '''
        del(tempLine[0])

        xArr = []
        for i in range(featNum):
            xArr.append(float(tempLine[i]))
        xArray.append(xArr)
        yArray.append(float(tempLine[-1]))

    return xArray, yArray
def loadTestData(filename):
    """
    函式說明:
        載入測試資料
    :param filename:
        檔名
    :return:
        xArray - x資料集,即為每個測試樣本的特徵引數
    """
    featNum = len(open(filename).readline().split(',')) - 1 # 特徵引數的個數,其中舍掉了第一個性別特徵

    file = open(filename)
    xArray = []
    for line in file.readlines():
        tempLine = line.strip().split(',')
        '''
        if tempLine[0] == 'M':
            tempLine[0] = '1'
        elif tempLine[0] == 'F':
            tempLine[0] = '-1'
        else:
            tempLine[0] = '0'
        '''
        del(tempLine[0])

        xArr = []
        for i in range(featNum):
            xArr.append(float(tempLine[i]))
        xArray.append(xArr)

    return xArray
  • (2) 使用區域性加權迴歸演算法對訓練資料進行擬合,得到係數w
def lwlRegression(testPoint, xArr, yArr, k=1.0):
    """
    函式說明:
        使用區域性加權線性迴歸計算迴歸係數w
    :param testPoint:
        測試樣本
    :param xArr:
        x訓練資料集
    :param yArr:
        y訓練資料集
    :param k:
        高斯核的k值,預設為1.0,可自定義
    :return:
        testPoint * ws - 計算得到的係數w對測試樣本的預測值
    """
    xMat = np.mat(xArr)
    yMat = np.mat(yArr).T
    m = np.shape(xMat)[0]
    weights = np.mat(np.eye((m)))
    for i in range(m):
        diffMat = testPoint - xMat[i, :]
        weights[i, i] = np.exp(diffMat * diffMat.T / (-2.0 * k ** 2))
    xTx = xMat.T * (weights * xMat)
    if np.linalg.det(xTx) == 0.0:
        print("不能求逆!")
        return

    ws = xTx.I * (xMat.T * (weights * yMat))
    return testPoint * ws
  • (3) 使用擬合得到的係數w,計算測試樣本對應的y值
def RegressionTest(testArr, xArr, yArr, k=1.0):
    """
    函式說明:
        區域性加權線性迴歸測試
    :param testArr:
        測試資料集
    :param xArr:
        x訓練資料集
    :param yArr:
        y訓練資料集
    :param k:
        高斯核的k值,預設為1.0,可自定義
    :return:
        yHat - 測試集合的所有預測值
    """
    m = np.shape(testArr)[0]
    yHat = np.zeros(m)
    for i in range(m):
        yHat[i] = lwlRegression(testArr[i], xArr, yArr, k)
    return yHat

4、總結

  • 使用區域性加權線性迴歸演算法得到的效果會優於最小二乘法;同時,進行不同特徵項的縮減比較,發現舍掉第一個性別特徵的情況下擬合效果會更好(已在程式碼中體現)

  • 大致總結了線性迴歸的優缺點:

    • 優點:結果易於理解,計算上不復雜

    • 缺點:對非線性的資料擬合效果不好

三、完整程式碼

#!/usr/bin/python
# -*- coding utf-8 -*-
# Project: Regression
# Author: jiangnan 
# Mail: [email protected]
# Date: 2018/10/13

import numpy as np

def loadTrainData(filename):
    """
    函式說明:
        載入訓練資料
    :param filename:
        檔名
    :return:
        xArray - x資料集,即為每個訓練樣本的特徵引數
        yArray - y資料集,即為每個訓練樣本的年齡
    """
    featNum = len(open(filename).readline().split(',')) - 2 # 特徵引數的個數,其中舍掉了第一個性別特徵

    file = open(filename)
    xArray = []
    yArray = []
    for line in file.readlines():
        tempLine = line.strip().split(',')
        '''
        if tempLine[0] == 'M':
            tempLine[0] = '1'
        elif tempLine[0] == 'F':
            tempLine[0] = '-1'
        else:
            tempLine[0] = '0'
        '''
        del(tempLine[0])

        xArr = []
        for i in range(featNum):
            xArr.append(float(tempLine[i]))
        xArray.append(xArr)
        yArray.append(float(tempLine[-1]))

    return xArray