0%

机器学习算法(一):线性回归

线性回归

  • 优点:结果易于理解,计算上不复杂。
  • 缺点:对非线性的数据拟合不好。
  • 适用数据类型:数值型和标称型数据。

比如预测汽车的功率,可能会这么计算:horse_power = 0.0015 * annual_salary - 0.99 * hours_listening_to_public_radio

这就是所谓的回归方程(regression equation),其中 0.0015 和 -0.99 称作回归系数(regression weights),求这些回归系数的过程就是回归。

回归一词的由来:是由达尔文(Charles Darwin)的表兄弟 Francis Galton 发明的。

线性回归的代价函数是: \[ cost = \sum^m_{i = 1}(y_i - x^T_i W)^2 \]

用矩阵可以表示为 \((y - XW)^T(y - XW)\),如果对 W 求导就可以得到 \(X^T(Y - XW)\)。令其等于 0,解得 W: \[ \hat{W} = (X^TX)^{-1} X^Ty \] 这公式也可以被称为正规方程。需要注意的点是 \((X^TX)^{-1}\) 是一个求逆的过程,但是矩阵求逆在有些情况下是无解的,所以 \((X^TX)^{-1}\) 必须有解才可以使用正规方程,如果无解就不能直接使用正规方程。

上述求解过程被称为最小二乘法(ordinary least squares),简称 OLS。

局部加权线性回归

线性回归的一个问题是有可能出现欠拟合现象。所以有些方法允许在估计中引入一些偏差,从而降低预测的均方差。其中一个方法是局部加权线性回归(Locally Weighted Linear Regression, LWLR),该算法给待预测点附近的每个点赋予一定的权重。所以正规方程的公式变为:

\[ \theta = (X^TWX)^{-1}X^TWy \]

需要说明一点省得搞混了,刚才我自己都乱了,这里引入的偏差并不是线性方程 y = WX + b 中的偏差。公式中的 W 是一个矩阵,用来给每个数据点赋予权重。LWLR 使用“核”(与支持向量机中的核类似)来对附近的点赋予更高的权重。核的类型可以自由选择,最常用的核就是高斯核,对应权重如下(那两竖不是求绝对值,而是求模长):

\[ w(i, i) = exp(\frac{|x^{(i)} - x|}{-2k^2}) \]

这样就构建了一个只含对角的权重矩阵 W,并且点 x 与 \(x^{(i)}\) 越近,w(i, i)将会越大。上述公式包含一个需要用户指定的参数 k,它决定了对附近的点赋予多大的权重。对高斯核公式的解释:

  1. W 是一个对角矩阵,因为高斯核每次赋值都是在 (i, i)点上赋值。主要说明 \(|x^{(i)} - x|\) 部分,其他部分都很好理解。首先说明 x 代表待预测的点,其次开始遍历每一项数据,数据记为t,计算每一个 |t - x| ,这样就得到了一个对角矩阵。意思就是通过待预测点经过一系列运算,为所有数据加上了一个权重。当然这里肯定也计算自己本身,不过自己减自己就是等于 0,e 的 0 次方等于1,所以就等于没有给自己加权重。最后使用公式 \((X^TWX)^{-1}X^TWy\) 求出了解,也就是回归方程的回归系数 W。这里面有两个一模一样的 W,但是意思完全不同,应该可以理解,我就不改了。有了回归系数就可以做预测了,prediction = XW。结束。
  2. 这样一来就计算好了第一个数据,注意:假设我们有 200 条数据,上述的步骤仅仅才计算了第一条数据,接着取出第二条数据 x(待预测点),再经过上述的步骤,又得到了回归系数 W,做预测,结束。
  3. 如此反复,直到取出第 200 条数据 x(待预测点),再经过上述的步骤,又得到了回归系数 W,做预测,结束。
  4. 这部分理解起来比较麻烦,故下面放出代码。从for 循环开始到 return 前都是上述123步的代码版本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import numpy as np
import os


def LWLR(X, Y, k=1):
"""
局部加权线性回归,Locally Weighted Linear Regression
:param X: input
:param Y: label
:param k: 超参数
:return:
prediction: 预测值
W: 回归系数,占个位置,可能以后会有用,现在没卵用
"""
X, Y = np.matrix(X), np.matrix(Y)
if np.linalg.det(np.dot(X.T, X)) == 0:
print("矩阵不可逆")
return
m = X.shape[0]
weights = np.matrix(np.eye(m))
prediction = np.empty((m, 1))

# 使用第 i 个数据点对包括自己在内的每个数据点赋予权重,对自己就是赋予 1 的权重值,也就是说等于没赋予。
for i in range(m):
predict_dot = X[i, :]
# 计算权重
for j in range(m):
# 这是高斯核的公式
difference = X[j, :] - predict_dot
weights[j, j] = np.exp((difference * difference.T) / (-2 * (k ** 2)))
W = (X.T * weights * X).I * (X.T * weights * Y)
prediction[i] = predict_dot * W
return prediction, np.empty((m, m, m))

岭回归(L2)

岭回归中的岭是什么?

岭回归使用了单位矩阵乘以常量 \(\lambda\),观察单位矩阵 I,发现值 1 贯穿这个对角线,其余元素全是 0。形象地,在 0 构成的平面上有一条由 1 组成的“岭”,这就是岭的由来。

简单来说,岭回归就是在矩阵 \(X^TX\) 上加上一个 \(\lambda I\)从而使得矩阵非奇异。进而能对 \(X^X + \lambda I\)求逆,其中 I 是一个单位矩阵,而 \(\lambda\) 是用户定义的数值。正规方程变为:

\[ \theta = (X^TX + \lambda I)^{-1}X^Ty \]

这里发现这个公式与加入 L2 正则化一样。(经百度之后,发现还真一样,所以这部分就不细写了)

加入 L2 正则化的代价函数为:

\[ \begin{aligned} cost & = \sum^m_{i = 1}(y_i - x^T_i W)^2 + \lambda ||W||_2\\ & = \sum^m_{i = 1}(y_i - x^T_i W)^2 + \lambda \sum^m_{j = 1}w^2_j \end{aligned} \]

知乎问题

lasso(L1)

略。

补充,参考文章,发现岭回归其实就是在代价函数注意是代价函数,不是正规方程)中加入了 L2 正则化,lasso 其实就是在代价函数中加入了 L1 正则化。

前向逐步回归