局部加权线性回归Lowess
程序员文章站
2022-03-14 21:21:40
当要预测的样本序列不是明显的线性关系时,用线性回归会存在拟合不好的现象,即欠拟合。局部加权回归定义:以一个点 x为中心,向前后截取一段长度为frac的数据,对于该段数据用权值函数 w做一个加权的线性回归,记 ( x , y ^ )为该回归线的中心值,其中 y ^为x拟合后曲线对应值。对于所有的n个数据点则可以做出n条加权回归线,每条回归线的中心值y ^的连线则为这段数据的Lowess曲线(上述为单次回归,局部加权回归可多次迭代)。线性回归与局部加权回归的损失函数:可以发现:局部加权回归对局部特征能较...
当要预测的样本序列不是明显的线性关系时,用线性回归会存在拟合不好的现象,即欠拟合。
局部加权回归定义:
以一个点 x为中心,向前后截取一段长度为frac的数据,对于该段数据用权值函数 w做一个加权的线性回归,记 ( x , y ^ )为该回归线的中心值,其中 y ^为x拟合后曲线对应值。对于所有的n个数据点则可以做出n条加权回归线,每条回归线的中心值y ^的连线则为这段数据的Lowess曲线(上述为单次回归,局部加权回归可多次迭代)。
线性回归与局部加权回归的损失函数:
可以发现:局部加权回归对局部特征能较好拟合,但同时受噪声点影响。通过增大衰减因子τ,增加局部加权回归迭代次数可以减小其影响。
线性回归的Python代码实现:
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
class linear_regress(object):
def __init__(self):
self.W = None
self.b = None
def loss(self, X, y):
"""求样本点X,y(此处是某一个样本点)的损失值,参数w,b的微分项"""
num_feature = X.shape[1]
num_train = X.shape[0]
# h为样本预测值
h = X.dot(self.W) + self.b
loss = np.sum(np.square(h - y))
# 参数的微分
dW = X.T.dot((h - y)) / 0.5
db = np.sum((h - y)) / 0.5
return loss, dW, db
def train(self, X, y, learn_rate=0.001, iters=10000):
"""训练参数w,b"""
num_feature = X.shape[1] # 输入矩阵特征数目,对于时序预测,X是一维
num_train = X.shape[0]
self.W = np.zeros((num_feature, 1)) # 初始化参数矩阵 W, 对于时序预测,是一维
self.b = 0
# 定义loss_list列表,保存每次迭代的loss值
loss_list = []
for i in range(iters):
for j in range(num_train):
random_index = np.random.randint(num_train) # 随机选取一个点进行梯度下降
loss, dW, db = self.loss(X[random_index:random_index+1], y[random_index:random_index+1])
loss_list.append(loss)
# 梯度下降法更新参数w,b
self.W += -learn_rate * dW
self.b += -learn_rate * db
if i % 100 == 0:
print('iters = %d,loss = %f' % (i, loss))
return loss_list
def predict(self, X_test):
y_pred = X.dot(self.W) + self.b
return y_pred
"""线性拟合回归训练"""
classify = linear_regress()
loss_list = classify.train(X_train, y_train) # 损失量变化。输入X_train, y_train为矩阵形式,shape[0]为样本数量
print(classify.W, classify.b) # 返回模型训练参数值
局部加权回归的Python代码实现:
def lwlr(testPoint, xArr, yArr, tao=1.0):
"""
:param xArr: 训练集x矩阵,对于时序拟合问题,xArr即有序自然数列
:param yArr: 训练集输出y矩阵,对于时序拟合问题,yArr即时序数列
:param tao: 衰减因子,取值越小,周围样本权重随着距离增大而减得越快,即易过拟合,一般取值0.001-1
:return:返回模型权重矩阵w,和样本testPoint的输出testPoint * w
没有用到frac参数,单词迭代(未根据局部加权回归误差,对样本权重进行更新,进行下一次迭代)
"""
# 样本数量m
m = np.shape(xArr)[0]
# 初始化权重矩阵weights
weights = np.mat(np.eye((m)))
# 更新测试点testPoint 周围的样本权重矩阵weights
for j in range(m):
diffMat = testPoint - xArr[j, :]
weights[j, j] = np.exp(diffMat*diffMat.T / (-2.0 * tao ** 2))
xTx = xArr.T * (weights * xArr)
if np.linalg.det(xTx) == 0.0:
print("This matrix is singular, cannot do inverse")
return
#
w = xTx.I * (xArr.T * (weights * yArr)) # normal equation
return testPoint * w
def lwlrTest(testArr, xArr, yArr, tao=1.0):
"""
:param testArr: 测试集矩阵
:param xArr: 训练集矩阵
:param yArr: 训练集输出
:param tao: 衰减因子
:return: 测试集矩阵testArr的对应输出
"""
m = np.shape(testArr)[0]
yHat = np.zeros(m)
for i in range(m):
yHat[i] = lwlr(testArr[i], xArr, yArr, tao)
return yHat
调用statsmodels模块实现局部加权回归:
"""
调用lowess函数实现局部加权回归
frac:应该截取多长的作为局部处理, frac为原数据量的比例;
w:使用什么样的权值函数w合适,权值函数不可调
it:迭代次数,一般2-3次(求权值函数w,计算局部回归y^,求回归误差e,修正权值函数w,整个过程算一次迭代)
delta回归间隔:是否真的每个点都需要算一次局部加权回归,能否间隔delta距离算一次,间隔点用插值替换
"""
import statsmodels.api as sm
lowess = sm.nonparametric.lowess
result = lowess(y, X, frac=0.3, it=3, delta=0.0) # 输入的x,y是array数据形式;输出的result为mX2的两列数组
**
参考鲁棒局部加权回归文中的局部加权回归完整算法伪代码:
**
本文地址:https://blog.csdn.net/weixin_37598719/article/details/110249148