線性迴歸數值型預測:預測鮑魚的年齡
線性迴歸數值型預測:預測鮑魚的年齡
一、實驗準備
1、實驗內容和目的
-
根據訓練集中給出的鮑魚的各項生物特徵引數以及其年齡,進行處理和擬合。然後使用擬合出來的模型來預測測試集中鮑魚的年齡
-
其中訓練集為檔案train.txt,測試集為檔案test.txt。訓練集中的每個樣本有8個特徵引數,最後的數字為其年齡;而測試集合中只存放每個樣本的8個特徵引數
2、實驗原理
- 前面學習的KNN分類演算法和樸素貝葉斯分類演算法的目標變數是標稱型資料,而回歸則是對連續型的資料做出處理,迴歸的目的是預測數值型資料的目標值
2.1 關於迴歸的背景瞭解
-
迴歸的目的是預測數值型的目標值。最直接的方法就是依據輸入寫出一個目標值的計算公式。比如要計算一輛車的馬力大小,可能會這麼計算:
-
這就是所謂的迴歸方程,其中的0.0015和-0.99稱作迴歸係數,求這些迴歸係數的過程就是迴歸。一旦有了這些迴歸係數,再給定輸入,做預測就非常容易了。具體的做法是用迴歸係數乘以輸入值,再將結果相加,就能得到預測值
2.2 用線性迴歸找到最佳擬合直線
-
大致的原理已經知道了,那麼應當怎麼從一大堆資料裡求出迴歸方程呢?假定輸入資料在矩陣 中,而回歸係數存放在向量 中。那麼對於給定的資料 ,預測結果將會通過 給出。現在的問題是,手裡有一些x和對應的y,怎樣才能好到 呢?一個常用的方法就是找出使誤差最小的 。這裡的誤差是指預測y值和真實y值之間的差值,使用該誤差的簡單累加會使得正差值和負差值相互抵消,所以採用平方誤差
-
平方誤差可以寫為:
-
用矩陣表示還可以寫做 。如果對 求導,得到 ,令其等於零,解得 如下:
-
值得注意的是,上述的公式中包含 ,也就是需要對矩陣求逆,因此這個方程只在逆矩陣存在的時候適應。然而,矩陣的逆有可能不存在,因此必須要在程式碼中對此作出判斷
2.3 區域性加權線性迴歸
-
如果單純的使用上述線性迴歸的方法,會出現欠擬合的問題,因為它求的是具有最小均方誤差的無偏估計。顯而易見,如果模型欠擬合將不能取得最好的預測效果。所以在此次預測任務中採用了局部加權線性迴歸演算法
-
在區域性加權線性迴歸演算法中,我們給待預測點附近的每個點賦予一定的權重;然後與2.1中的解法類似,在這個子集上基於最小均方差來進行普通的迴歸。該演算法解出迴歸係數 的形式如下:
-
其中 是一個矩陣,用來給每個資料點賦予權重。區域性加權線性迴歸演算法使用“核”來對附近的點賦予更高的權重。核的型別可以自由選擇,最常用的核就是高斯核,高斯核對應的權重如下:
二、進行實驗
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