Python中的局部加权回归实例
一、什么是局部加权回归
局部加权回归(Locally weighted regression,简称LWR)是一种非参数回归方法,相对于传统的全局线性回归方法,LWR更适合在非线性回归问题中使用。它的基本思想是:对于给定的查询点,通过给样本点赋予权重的方式对回归直线进行局部逼近,以提高拟合效果。
与其他回归方法相比,LWR的优点在于可以通过调整带宽参数来控制模型趋势的平滑度和灵敏度,从而使得LWR能够在不同的数据集上取得更好的拟合效果。同时,LWR也可以用于预测和异常检测等应用领域。
二、局部加权回归的理论基础
2.1 引入核函数
为了讲解LWR的理论基础,首先需要介绍一下核函数。核函数是指一个已知的非负实值函数,满足以下两个条件:
对于任意一个实数x,$\phi(x)$的值非负;
对于任意x,积分$\int_{-\infty}^{+\infty}\phi(x)dx=1$。
常用的核函数有高斯核函数、均匀核函数等。
2.2 引入局部权重的概念
对于样本点$(x_i, y_i)$和查询点$x_0$,我们可以通过以下式子计算权重:
$$w_i=\phi(\frac{x_0-x_i}{\tau})$$
在这里,$\tau$称为带宽(bandwidth),控制了样本点权重的大小。一般来说,$\tau$越小,那么查询点x0就只会受到那些距离它比较近的样本点的影响,而与其他样本点的距离则会被忽略。
基于此,我们可以通过以下式子计算出查询点x0的预测值:
$$\hat{y}_0=\frac{\sum_{i=1}^{N}w_i(x_0)y_i}{\sum_{i=1}^{N}w_i(x_0)}$$
上述式子中的权重w_i越大,则对应样本点y_i产生的影响就越大,反之则越小。
三、Python实现局部加权回归
3.1 环境准备
实现LWR需要用到Numpy和Matplotlib库。可以在Python环境中使用以下命令进行安装:
!pip install numpy matplotlib
3.2 生成样本数据
这里我们使用多项式函数生成一些样本数据。以下代码将生成100个样本点,并对它们加上一些噪声:
import numpy as np
# 生成多项式函数
def generate_function(x):
y = 2 * x ** 3 - 4 * x ** 2 + 3 * x + 2
return y
# 生成样本
def generate_samples(num_samples, noise=0.1):
x_min, x_max = -5, 5
x = np.random.uniform(x_min, x_max, size=num_samples)
y = generate_function(x) + np.random.normal(scale=noise, size=num_samples)
return x, y
# 生成样本集
x, y = generate_samples(num_samples=100, noise=0.1)
我们可以使用Matplotlib库来可视化样本点情况,以及真实的多项式函数:
import matplotlib.pyplot as plt
# 可视化样本和真实函数
def plot_samples(x, y):
plt.figure(figsize=(7, 5))
plt.plot(x, y, 'o', markersize=5, label='samples')
x_true = np.linspace(-5, 5, num=100)
y_true = generate_function(x_true)
plt.plot(x_true, y_true, '-', linewidth=2, label='true function')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.show()
plot_samples(x, y)
通过可视化图像,我们可以清楚地看到样本点大致符合多项式函数的趋势,但也存在一些离散点。
3.3 使用LWR进行回归
为了使用LWR拟合这些样本点,我们需要实现一个LWR类,用于计算各个样本点的权重以及最终预测结果。以下代码展示了这个类的实现:
class LWR:
def __init__(self, x, y, tau=1.0):
self.x = x
self.y = y
self.tau = tau
def predict(self, x_new):
w = np.exp(-(self.x-x_new)**2 / (2*self.tau**2))
X = np.column_stack([np.ones_like(self.x), self.x])
W = np.diag(w)
theta = np.linalg.inv(X.T @ W @ X) @ X.T @ W @ self.y
return np.array([1, x_new]) @ theta
def predict_all(self, X_new):
y_pred = []
for x_new in X_new:
y_pred.append(self.predict(x_new))
return np.array(y_pred)
在上述代码中,我们通过predict函数计算出了给定查询点x_new的预测值。具体来说,该函数首先计算样本点与查询点之间的距离,然后利用高斯核函数计算出各样本点的权重w_i,并利用这些权重计算线性回归的参数theta,最终返回预测值。
除此之外,predict_all函数则可以计算多个查询点的预测值,并以np.array的形式返回。
3.4 使用LWR进行拟合
我们可以使用之前的代码生成实例并进行拟合,以下是完整的拟合代码:
# 实例化LWR并计算预测值
lwr = LWR(x, y, tau=0.7)
X_new = np.linspace(-5, 5, num=100)
y_pred = lwr.predict_all(X_new)
# 可视化LWR拟合结果
def plot_prediction_lwr(x, y, X_new, y_new):
plt.figure(figsize=(7, 5))
plt.plot(x, y, 'o', markersize=5, label='samples')
plt.plot(X_new, y_new, 'r-', linewidth=2, label='LWR prediction')
x_true = np.linspace(-5, 5, num=100)
y_true = generate_function(x_true)
plt.plot(x_true, y_true, '-', linewidth=2, label='true function')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.show()
plot_prediction_lwr(x, y, X_new, y_pred)
通过以上代码,我们可以得到LWR对样本点的拟合结果,并将其可视化呈现出来。通过图像可以看出,LWR的拟合结果相对于全局线性回归,更加接近于真实的多项式函数。
四、总结
局部加权回归是一种相对简单而又常用的非参数回归方法,它适用于大多数回归问题,尤其是在数据集呈现非线性趋势时效果更好。通过调整带宽参数,我们可以控制模型的平滑程度和对噪声的敏感度,从而得到更好的拟合效果。
本文通过一个Python实例来介绍了局部加权回归,通过相关的代码实现来说明LWR的理论基础和具体实现方式,希望对大家了解和使用这一回归方法有所帮助。