本实验通过运用线性回归方法预测鲍鱼年龄。
通过本实验掌握并实现基于线性回归方法预测鲍鱼年龄。
代码部分
导入数据
计算回归系数
局部加权线性回归
测试函数
#导入实验需要的库numpy、matplotlib.pyplot
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from numpy import *
import matplotlib.pyplot as plt
from numpy import * 将 numpy 库中的所有内容导入到当前项目中,调用里面的函数xxx时候,是可以直接写xxx(),而import numpy as np前面要加np.xxx()
打开一个用tab键分隔的文本文件
parameters:
fileName -文件名
return:
dataMat -数据矩阵
labelMat -目标值向量
def loadDataSet(fileName):
#得到列数,不包括最后一列,默认最后一列值为目标值(标签label)
numFeat = len(open(fileName).readline().split('\t')) - 1
#定义初始数据集
dataMat = []; labelMat = []
#读取文件内容
fr = open(fileName)
#构造数据集
for line in fr.readlines():
lineArr =[]
curLine = line.strip().split('\t')
for i in range(numFeat):
lineArr.append(float(curLine[i]))
dataMat.append(lineArr)
labelMat.append(float(curLine[-1]))
return dataMat,labelMat
多元线性回归模型的普通最小二乘参数估计量为:
计算最佳拟合直线,通过给定的参数x、y。来计算最佳的w值,代码实现最小二乘法。
def standRegres(xArr,yArr):
xMat = np.mat(xArr); yMat = np.mat(yArr).T
xTx = xMat.T * xMat
if np.linalg.det(xTx) == 0.0:
print("矩阵为奇异矩阵,不能求逆")
return
ws = xTx.I * (xMat.T*yMat) #根据文中推导的公示计算回归系数
return ws
计算回归系数
parameters:
testPoint -待预测数据
xArr -给定输入值
yArr -给定输出值
k -高斯核的k值,决定对附近的点赋予多大的权重
return:
testPoint * ws -回归系数的估计值
为了避免线性回归出现欠拟合的现象,多元线性回归结果是一个高维的超平面,我们在预测时想要这个超平面有一些凹凸,来解决欠拟合的问题(类比一元,拟合结果是一条直直的线,我们想避免预测结果过于“一刀切”,让他局部弯曲一点),局部加权回归允许在估计中引入一 些偏差,从而降低预测的均方误差。
给定了高斯核k,利用它,我们给待预测点附近的每个点赋予一定的权重K。
此时的损失函数是:
写成矩阵形式就是:
求解回归系数矩阵:
高斯核函数,形式如下:
代码:
def lwlr(testPoint, xArr, yArr, k=1.0):
### Start Code Here ###
xMat = np.mat(xArr); yMat = np.mat(yArr).T
m = np.shape(xMat)[0]
weights = np.mat(np.eye((m))) #创建权重对角矩阵
for j in range(m): #遍历数据集计算每个样本的权重
diffMat = testPoint - xMat[j, :]
weights[j, j] = 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))
### End Code Here ###
return testPoint*ws
"""
测试函数
parameters:
testArr -测试数据集
xArr -给定输入值
yArr -给定输出值
k -高斯核的k值
return:
yHat -预测值
"""
def lwlrTest(testArr, xArr, yArr,k=1.0):
m = shape(xArr)[0]
yHat = zeros(m)
for i in range(m):
yHat[i] = lwlr(testArr[i],xArr,yArr,k)
return yHat
"""
计算预测误差的平方和
parameters:
yArr -给定y值
yHatArr -预测y值
return:
((yArr-yHatArr)**2).sum() -误差矩阵
"""
def rssError(yArr,yHatArr):
return ((yArr-yHatArr)**2).sum()
if __name__=='__main__':
abX,abY = loadDataSet('linear_regression_abalone/abalone.txt') #根据自己文件地址改
yHat01 = lwlrTest(abX[0:99],abX[0:99],abY[0:99],0.1)
yHat1 = lwlrTest(abX[0:99],abX[0:99],abY[0:99],1)
yHat10 = lwlrTest(abX[0:99],abX[0:99],abY[0:99],10)
print("使用局部加权线性回归预测误差:")
print("核为0.1时:",rssError(abY[0:99],yHat01.T))
print("核为1时:",rssError(abY[0:99],yHat1.T))
print("核为10时:",rssError(abY[0:99],yHat10.T))
yHat01 = lwlrTest(abX[100:199],abX[0:99],abY[0:99],0.1)
yHat1 = lwlrTest(abX[100:199],abX[0:99],abY[0:99],1)
yHat10 = lwlrTest(abX[100:199],abX[0:99],abY[0:99],10)
print("使用局部加权线性回归预测误差在新数据上的表现:")
print("核为0.1时:",rssError(abY[100:199],yHat01.T))
print("核为1时:",rssError(abY[100:199],yHat1.T))
print("核为10时:",rssError(abY[100:199],yHat10.T))
ws = standRegres(abX[0:99],abY[0:99])
yHat = mat(abX[100:199])*ws
print("使用标准线性回归预测误差为:",rssError(abY[100:199],yHat.T.A))
使用局部加权线性回归预测误差: 核为0.1时: 56.78868743048742 核为1时: 429.8905618704059 核为10时: 549.1181708828803 使用局部加权线性回归预测误差在新数据上的表现: 核为0.1时: 57913.51550155909 核为1时: 573.5261441894984 核为10时: 517.5711905381573 使用标准线性回归预测误差为: 518.6363153245542
可以看到,当k=0.1时,训练集误差小,但是应用于新的数据集之后,误差反而变大了。这就是经常说道的过拟合现象。我们训练的模型,我们要保证测试集准确率高,这样训练出的模型才可以应用于新的数据,也就是要加强模型的普适性。可以看到,当k=1时,局部加权线性回归和简单的线性回归得到的效果差不多。这也表明一点,必须在未知数据上比较效果才能选取到最佳模型。那么最佳的核大小是10吗?或许是,但如果想得到更好的效果,应该用10个不同的样本集做10次测试来比较结果。
本次实验展示了如何使用局部加权线性回归来构建模型,可以得到比普通线性回归更好的效果。局部加权线性回归的问题在于,每次必须在整个数据集上运行。也就是说为了做出预测,必须保存所有的训练数据。
参考:
本校cg平台提示代码与下文链接极其相似Python3《机器学习实战》学习笔记(十一):线性回归基础篇之预测鲍鱼年龄_线性回归 jack 崔_Jack-Cui的博客-CSDN博客
尚在学习,如有新理解将会更新。