@dongxi
2017-07-28T15:00:58.000000Z
字数 4454
阅读 2201
机器学习
CS229
本文主要参考自加权最小二乘法与局部加权线性回归 ,对其中的内容进行了一致性的修改并且填补了没有说明的数学知识。
在之前的线性回归中,我们采用了不止一种方法(以后遇到有意思的方法还会加到其中),其中有一种方法是最小二乘回归,在统计学上,那篇文章中的最小二乘法回归称为普通最小二乘法(OLS),这是一种有约束条件的线性回归,本篇文章我们将通过介绍局部加权线性回归来讲这些内容都一并讲述一遍。
如同前面的文章一样,我们定义 为随机误差,那么我们可以得到:
其实这里还有一些事情我们并没有注意到,在计算残差平方和的时候在本质上我们采用的并不是欧氏距离之差,而是马氏距离之差,只不过是因为欧氏距离是马氏距离的特殊情况(关于马氏距离的内容参见后续文章),所以才在 的推导公式中表现为欧氏距离,实际上 的推导公式应该如下:
如果不能够满足高斯-马尔科夫假设,那么我们上述所有的推导很研究都是存在问题的。我们适当放宽假设条件,考虑这样一个模型:
加权最小二乘法则是广义最小二乘法的特殊情况,广义最小二乘法中的 太自由了,我们对其增加一些限制,我们认为它取对角矩阵,这个对角矩阵的对角元都是权重 的倒数,如下:
终于到我们的正题了,局部加权线性回归是一种经典的机器学习算法,在一定程度上解决了普通的线性回归方程所存在的欠拟合和过拟合的现象。与普通线性回归不同,普通线性回归是一种参数方法,在计算出 后,只要将新的数据带入即可进行预测,我们并不需要保留数据集。然而局部加权线性回归则是一种非参数方法,每次计算都需要重新学习一个参数 ,所以需要保留数据集。那么它是怎么运作的呢?
实际上,局部加权线性回归其实就是把每个点根据与待测的距离,赋予一定的权重,也就是增加一个核函数矩阵 。那么我们需要最小化的目标函数大概为:
为了方便起见我们就采用比较简单的一元线性回归,其中 ,同时我们认为偏差服从高斯分布,那么我们可以根据以下代码生成一个简单的实例:
from math import *
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import scipy.stats as stats
mpl.style.use('ggplot')
plt.figure(figsize=(12, 6))
# x取值1~100 y表示非线性函数
x = np.arange(1, 101)
x = np.array([floor(i) for i in x])
y = x + [10 * sin(0.3 * i) for i in x] + stats.norm.rvs(size=100, loc=0, scale=1.5)
plt.scatter(x, y)
plt.show()
为了让大家能有一个对这个函数能有一个更清楚的认识,我们将图像绘制如下:
其实很明显,这是一个非线性关系(研究 是否是广义线性关系?)的样本数据,我们先采用普通最小二乘法来拟合这一问题:
# 调用scipy.stats中自带的线性回归函数
slope, intercept, r_value, p_value, std_err = stats.linregress(x, y)
yHatLinear = intercept + slope * x
plt.plot(x, yHatLinear, 'r', color='blue')
我们可以预想到效果并不会很理想,事实也确实如此:
而对于局部加权线性回归则不会出现这种现象,只要我们合理调节就可以得到较好的拟合(这一部分代码利用了加权最小二乘法向普通最小二乘法转换的小技巧,同时numpy、statsmodels这两个包我还不是特别熟练,所以只是理解了代码并未进行改写):
def get_sqrtW(x0, k):
w = np.zeros(len(x))
for i in range(len(x)):
w[i] = exp(-(x[i] - x0) ** 2 / (2 * k * k))
w = np.array([sqrt(i) for i in w])
return w
def get_yHat2(k):
yHat2 = np.zeros(len(x))
for i in range(len(x)):
w = get_sqrtW(x[i], k)
x2 = w * x
x2 = x2[x2 > 0]
y2 = w * y
y2 = y2[y2 > 0]
X = np.zeros((1, len(x2)))
X[0] = x2
X = X.T
X = sm.add_constant(X, has_constant='skip')
X[:, 0] = w[w > 0]
Y = y2
model = sm.OLS(Y, X)
results = model.fit()
a = results.params[0]
b = results.params[1]
yHat2[i] = a + b * x[i]
return yHat2
yHat2 = get_yHat2(100000) # k取100000
plt.figure(figsize=(12, 6))
plt.plot(x, yHat2, 'r')
plt.scatter(x, y)
plt.show()
当 分别为10000、10、1以及0.1时,拟合效果如下四图所示:
效果跟我们之前预料的完全相同,在 取值过小时,会发生过拟合现象,过大则会出现欠拟合。所以 的取值对我们的回归效果起到了决定性的作用。
这篇文章真的远远比我想象的费时间,因为前文中提到了博客将我的整个计划都打乱了,看了好多额外的内容,反复修改了三四次,尤其是在广义线性回归那部分真的研究了好久,最后还是通过阅读Wiki的内容基本完成了对这一部分的理解。总的来看,这篇文章不是很满意,等有时间一定要好好梳理下。
Ordinary least squares
Residual sum of squares
加权最小二乘法与局部加权线性回归