一、简介
局部加权线性回归(Locally Weighted Linear Regression,LWLR)是一种非参数化算法,它在预测时给予待预测点附近的数据点更高的权重。这种算法在处理非线性数据分布时特别有用,因为它可以根据数据的局部特性进行拟合,而不是像标准线性回归那样试图找到一个全局的线性模型。
在LWLR中,每个数据点的权重由一个核函数(如高斯核)决定,这个核函数会根据数据点与待预测点的距离来赋予权重。权重通常随着距离的增加而指数级减少,这意味着距离待预测点近的数据点对回归结果的影响更大。
LWLR在数据科学和机器学习领域有广泛的应用,特别是在需要捕捉数据局部特征的场景中。然而,由于其计算成本较高,有时可能会选择其他更高效的算法,如岭回归或支持向量机。
(1)进行线性数据回归分析经常需要用到波动上升的随机数据,本文给出了使用python构建的由线性数据+随机数据+正弦数据的波动上升数据并绘制散点图的代码和效果展示。
(2)该数据共5段100个可用于进行线性回归数据分析。
(3)数据构建好后使用机器学习算法中的局部加权线性回归算法求解斜率和截距并进行绘图展示。
二、效果展示
1、生成的excel表格效果展示
2、散点图和局部加强回归曲线效果展示
三、代码展示
# -*- coding: utf-8 -*-
#导入第三方库
import random
import pandas as pd
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.backends.backend_tkagg
import openpyxl
from openpyxl import Workbook
from sklearn.linear_model import LinearRegression
from pylab import *
#构造用于线性回归分析使用的波动上升随机数据并进行局部加权回归分析
#构造正弦函数(数量20个、幅值0.6)点
m = np.linspace(0, 2*np.pi, 20)
n = 0.6 * np.sin(m)
#构建1-20序号
numbers_x1 = list(range(1, 21))
#生成20个[(序号/20)+(±0.2)+正弦函数点]的随机数据
numbers_y1 = np.add(np.add([item / 20 for item in numbers_x1],np.random.uniform(-0.2, 0.2, 20).tolist()),n)
#构建21-40序号
numbers_x2 = list(range(21, 41))
#生成20个[(序号/20)+(±0.2)+正弦函数点]的随机数据
numbers_y2 = np.add(np.add([item / 20 for item in numbers_x2],np.random.uniform(-0.2, 0.2, 20).tolist()),n)
#构建41-60序号
numbers_x3 = list(range(41, 61))
#生成20个[(序号/20)+(±0.2)+正弦函数点]的随机数据
numbers_y3 = np.add(np.add([item / 20 for item in numbers_x3],np.random.uniform(-0.2, 0.2, 20).tolist()),n)
#构建61-80序号
numbers_x4 = list(range(61, 81))
#生成20个[(序号/20)+(±0.2)+正弦函数点]的随机数据
numbers_y4 = np.add(np.add([item / 20 for item in numbers_x4],np.random.uniform(-0.2, 0.2, 20).tolist()),n)
#构建81-100序号
numbers_x5 = list(range(81, 101))
#生成20个[(序号/20)+(±0.2)+正弦函数点]的随机数据
numbers_y5 = np.add(np.add([item / 20 for item in numbers_x5],np.random.uniform(-0.2, 0.2, 20).tolist()),n)
#创建excel文件
wb = Workbook()
#选择当前工作表
ws = wb.active
#工作表命名
ws.title = "线性回归数据"
#新建工作表并命名
ws2 = wb.create_sheet("原始数据")
#表格A1写入x
ws['A1'] = 'x'
#表格B1写入y
ws['B1'] = 'y'
#将20个x值写入A列
for i, x1 in enumerate(numbers_x1, start=2):
cell = 'A{}'.format(i)
ws[cell] = x1
#将50个y值写入B列
for i, y1 in enumerate(numbers_y1, start=2):
cell = 'B{}'.format(i)
ws[cell] = y1
#将20个x值写入A列
for i, x2 in enumerate(numbers_x2, start=22):
cell = 'A{}'.format(i)
ws[cell] = x2
#将50个y值写入B列
for i, y2 in enumerate(numbers_y2, start=22):
cell = 'B{}'.format(i)
ws[cell] = y2
#将20个x值写入A列
for i, x3 in enumerate(numbers_x3, start=42):
cell = 'A{}'.format(i)
ws[cell] = x3
#将50个y值写入B列
for i, y3 in enumerate(numbers_y3, start=42):
cell = 'B{}'.format(i)
ws[cell] = y3
#将20个x值写入A列
for i, x4 in enumerate(numbers_x4, start=62):
cell = 'A{}'.format(i)
ws[cell] = x4
#将50个y值写入B列
for i, y4 in enumerate(numbers_y4, start=62):
cell = 'B{}'.format(i)
ws[cell] = y4
#将20个x值写入A列
for i, x5 in enumerate(numbers_x5, start=82):
cell = 'A{}'.format(i)
ws[cell] = x5
#将50个y值写入B列
for i, y5 in enumerate(numbers_y5, start=82):
cell = 'B{}'.format(i)
ws[cell] = y5
#保存excel
wb.save('线性回归数据.xlsx')
#定义局部加权线性回归函数
def lwlr(testPoint,xArr,yArr,k=1.0):
'''
Description:
局部加权线性回归,在待预测点附近的每个点赋予一定的权重,在子集上基于最小均方差来进行普通的回归。
Args:
testPoint:样本点
xArr:样本的特征数据,即 feature
yArr:每个样本对应的类别标签,即目标变量
k:关于赋予权重矩阵的核的一个参数,与权重的衰减速率有关
Returns:
testPoint * ws:数据点与具有权重的系数相乘得到的预测点
Notes:
这其中会用到计算权重的公式,w = e^((x^((i))-x) / -2k^2)
理解:x为某个预测点,x^((i))为样本点,样本点距离预测点越近,贡献的误差越大(权值越大),越远则贡献
的误差越小(权值越小)。关于预测点的选取,在我的代码中取的是样本点。其中k是带宽参数,控制w(钟形函
数)的宽窄程度,类似于高斯函数的标准差。算法思路:假设预测点取样本点中的第i个样本点(共m个样本点),
遍历1到m个样本点(含第i个),算出每一个样本点与预测点的距离,也就可以计算出每个样本贡献误差的权值,
可以看出w是一个有m个元素的向量(写成对角阵形式)。
'''
#将array数据转换为矩阵对象
xMat = mat(xArr)
#将array数据转换为矩阵对象并进行转置
yMat = mat(yArr).T
#获取xMat矩阵的行数
m = shape(xMat)[0]
'''
创建权重矩阵,eye()函数用于创建一个二维数组,
这个数组在主对角线上的元素为1,其余元素为0
'''
weights = mat(eye((m)))
#衰减控制函数
for j in range(m):
#计算testPoint与输入样本点之间的距离,用于计算每个样本贡献误差的权重
diffMat = testPoint - xMat[j,:]
#利用k控制衰减的速度
weights[j,j] = exp(diffMat*diffMat.T/(-2.0*k**2))
#根据矩阵乘法计算xTx,检查矩阵为奇异矩阵
xTx = xMat.T * (weights * xMat)
#检查行列式是否为0,即xTx是否为奇异矩阵,输出:矩阵是奇异的,不能求逆
if linalg.det(xTx) == 0.0:
print ("This matrix is singular, cannot do inverse")
return
# 计算出回归系数的一个估计
ws = xTx.I * (xMat.T * (weights * yMat))
return testPoint * ws
#测试局部加权线性回归函数
def lwlrTest(testArr,xArr,yArr,k=1.0):
'''
Description:
测试局部加权线性回归,对数据集中每个点调用 lwlr() 函数
Args:
testArr:测试所用的所有样本点
xArr:样本的特征数据,即 feature
yArr:每个样本对应的类别标签,即目标变量
k:控制核函数的衰减速率
Returns:
yHat:预测点的估计值
'''
# 得到样本点的总数
m = shape(testArr)[0]
# 构建一个全部都是 0 的 1 * m 的矩阵
yHat = zeros(m)
# 循环所有的数据点,并将lwlr运用于所有的数据点
for i in range(m):
yHat[i] = lwlr(testArr[i],xArr,yArr,k)
# 返回估计值
return yHat
#局部加权函数绘图验证
#读取Excel文件
data = pd.read_excel('线性回归数据.xlsx',sheet_name='线性回归数据')
#读取名称为x的列
x = list(data['x'])
new_element= 1
#列表x每个元素增加一个常数1变为2个元素
xArr = [ [new_element] + [sub_element] for sub_element in x ]
#读取名称为y的列
yArr = list(data['y'])
#将array数据转换为矩阵对象
xMat = mat(xArr)
#将array数据转换为矩阵对象
yMat = mat(yArr)
#K赋值
k = [10.0,1.0,0.2]
#针对不同的k值分别进行局部加权回归并绘图
for i in range(3):
#调用函数计算预测值yHat
yHat = lwlrTest(xArr, xArr, yArr,k[i])
##argsort()函数是将x中的元素从小到大排列,提取其对应的index(索引),然后输出
srtInd = xMat[:, 1].argsort(0)
#x赋值
xSort=xMat[srtInd][:,0,:]
#绘图
fig = plt.figure(i+1)
#连续绘制3副图
ax = fig.add_subplot(111)
#绘制预测值
ax.plot(xSort[:,1], yHat[srtInd])
#散点图绘制,x是xMat中的第二列,y是yMat的第一列,flatten将多维数组转换为一维数组
ax.scatter(xMat[:,1].flatten().A[0], yMat.T[:, 0].flatten().A[0] , s=2, c='red')
#绘制标题
plt.title("k=%g" % k[i])
plt.show()