当要预测的样本序列不是明显的线性关系时,用线性回归会存在拟合不好的现象,即欠拟合。

局部加权回归定义

以一个点 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