前言
线性回归只能拟合线性曲面(广义曲面)。如果回归任务中的输出变量相对于特征向量不是线性的,那么如何更好地拟合?局部加权线性回归是一种方法。
1. 局部加权线性回归模型
当两个样本点的特征向量相近时,它们的输出变量通常相近,即具有相似的性质。现在我们有训练样本点构成训练集。那么当我们给一个特征向量的时候,我们需要根据训练集中的信息来预测它的输出变量,训练集中离越近的样本点越要注意。也就是说,我们需要给训练集中的每个样本点一个权重,越接近的样本点的权重应该越大。这是一个加权的原理,那么具体应该怎么做加权呢?
首先应该想一想,我们怎样衡量距离呢?欧氏距离(2范数)是一种常用的衡量方式,即:
我们使用以下公式为训练集中的第个样本点分配权重:
这里显得很突兀。不知道为什么,直接给了这样一个公式。我不知道为什么。该算法经常使用这样的函数来赋予权重。对于那些不想深入理论研究的人,我认为是形而上学。酒吧!当然,这绝对不是形而上学。这样做应该有一定的理论基础,但我暂时不明白。
对于一个给定的特征向量作为输入,我们想要预测它的输出变量,使用下面的加权损失函数:
这很自然,它是一个简单的加权求和。当最小化这样一个损失函数时,算法肯定会寻求使样本点的损失越接近,损失越小,也就是说,算法更关注那些距离越近的点,即也有利于更准确地预测。该函数使用矩阵编写为:
其中权重矩阵。
优化这个损失函数的过程就是算法的训练过程。在优化这个损失函数之后,参数可以用来预测输出变量使用。如果我们有个特征向量要预测,将这些特征向量记为,那么对于每个特征向量我们要计算一次权重矩阵,然后优化损失函数得到,然后预测输出变量。
2. 求解方法
梯度下降法是一种很常见的优化方法。当然这里也可以使用梯度下降法。主要目的是解决损失函数的梯度。求解梯度其实就是求导,求导:
这样,也可以使用梯度下降法。我不会在这里多说。只看正规方程的方法,令其导数为求解函数的极小点:
值得注意的是,局部加权线性回归的时间成本非常高,因为对于每一个需要预测的点,我们都需要对应的权重矩阵并单独训练。普通的线性回归算法只需要训练一次就可以预测所有的点。
局部加权线性回归的优点是它几乎可以拟合任何形状。只要选择合适的超参数,算法就能很好地拟合。在现实生活中,数据的输出变量和特征向量之间存在线性关系的情况并不多,因此纯线性回归模型可能不适合,但局部加权线性回归可以更好地拟合非线性数据分布。
3. 代码实现
写一个局部加权的线性回归函数。
import numpy as np
def calweight(a, b): # 求解权值的函数
sigma = 0.3
return np.exp(-np.linalg.norm(a-b)**2 / (2*sigma**2))
def LWLR(X_train, y_train, X_test): # 局部加权线性回归
X_train = np.insert(X_train,0,1,axis=1)
X_test = np.insert(X_test, 0, 1, axis = 1)
y_pred = np.empty(X_test.shape[0]) # 预测值
for k in range(X_test.shape[0]): # 对所有的需要预测的特征向量先训练再预测
# 求解权值矩阵
w = np.empty(X_train.shape[0])
for i in range(X_train.shape[0]):
w[i] = calweight(X_test[k], X_train[i])
W = np.diag(w) #权值矩阵
theta=np.dot(np.linalg.pinv(np.dot(np.dot(X_train.T,W),X_train)),np.dot(np.dot(X_train.T,W),y_train))
y_pred[k] = np.dot(theta,X_test[k]) # 预测
return y_pred
创建数据并使用此函数拟合回归曲线。
import matplotlib.pyplot as plt
def CreateData():
X = np.arange(0,10,0.1)
y = np.empty(X.shape[0])
for i in range(X.shape[0]):
y[i] = X[i]**3 - 10*X[i]**2 + X[i] + np.random.uniform(-10,10)
return X[:,np.newaxis], y
np.random.seed(0)
X, y = CreateData()
plt.scatter(X, y) # 可视化
X_test = np.arange(0.05,10,0.1) #测试集,目的是通过其画出拟合曲线
X_test = X_test[:,np.newaxis]
y_pred = LWLR(X, y, X_test)
plt.plot(X_test, y_pred, color='red') # 画出拟合曲线
plt.show()
拟合曲线如下:
、欠拟合
,感觉底部有点欠拟合
、贴合效果好
,有些过拟合
只要选择合适的超参数,很多情况下会有更好的拟合效果。
文章出处登录后可见!