Lesson 3 线性回归

1 minute read

Published:

问题

\[h(x) = \sum_{i=1}^m w_i x_i + b = w^T x + b\]

目标:对于给定的若干组 $x,y$,找到“最好”的参数 $w,b$。

损失函数

损失函数 (Loss function) $J(w,b)$ 定量衡量 $w,b$ 的好坏。我们要求的 $w,b$ 即为

\[\arg \min_{w,b} J(w,b)\]

常用的误差函数有 MSERMSEMAE 三种。

平均绝对误差 MAE

平均绝对误差 (Mean absolute error, MAE)

\[J(w,b) = \frac 1 m \sum_{i=1}^m \lvert h(x^{(i)}) - y^{(i)} \rvert\]

和后面的方法比起来,MAE 使用的只是绝对值,对误差大小不敏感。

最小二乘法

误差平方和:

\[J(w,b) = \sum_{i=1}^m (h(x^{(i)}) - y^{(i)})^2\]

均方误差 (Mean squared error, MSE)

\[J(w,b) = \frac 1 m \sum_{i=1}^m (h(x^{(i)}) - y^{(i)})^2\]

以上两个主要是数学上比较有意义,实际上一般用的是均方根误差 (Root mean square error, RMSE)

\[J(w,b) = \sqrt{MSE} = \sqrt{\frac 1 m \sum_{i=1}^m (h(x^{(i)}) - y^{(i)})^2}\]

RMSE 由于带平方,相对于 MAE 来说会放大误差大的数据,但是对异常数据会更敏感

求解方法

为了方便,我们多加一个第 $0$ 维。$x_0$ 总等于 $1$;$w_0 = b$。这样我们就不用单独考虑 $b$ 了。

正规方程

对于最小二乘的问题,我们就是要找:

\[\arg \min_w \lVert Xw - y \rVert\]

这等价于 $Xw - y$ 与 $X$ 的列空间正交:

\[X^T (Xw - y) = 0\] \[\boxed{ X^T X w = X^T y }\]

这个公式被称为正规方程 (Normal equation)

若数据性质较好(特征之间线性无关,且样本数量足够等),$X^T X$ 可逆,则:

\[\boxed{ w = (X^T X)^{-1} X^T y }\]

由于矩阵乘法和矩阵求逆时间复杂度较高,一般只在数据规模较小时使用。

梯度下降

实践中往往采用梯度下降法 (Gradient Descent) 求解优化问题。

选择一个任意起点,反复执行以下迭代,则 $w$ 理应会收敛到一个局部最小值:

\[w \gets w - \alpha \nabla J(w)\]

其中参数 $\alpha$ 被称为学习率 (learning rate)

  • 学习率太小,则收敛过慢。
  • 学习率太大,则可能错过最小值,产生震荡等。

注意梯度下降法不局限于线性回归问题,当你需要最小化任意一个函数时就可以优先考虑梯度下降法。

各种梯度下降

若需要梯度下降的函数是若干函数之和(一般来说是给定的若干样本的函数值之和)的形式,则我们可以考虑在选取样本上做点手脚。

  • 全梯度下降(FGD):使用全部样本计算梯度。
    • 慢,但是准。
  • 随机梯度下降(SGD):随机使用仅一个样本计算梯度。
    • 快,但是会不太稳。
  • 小批量梯度下降(mini-batch SGD):随机使用 $B$ 个样本计算梯度。
    • $B=1$ 即为 SGD,$B=m$ 即为 FGD。
    • 平衡了 SGD 和 FGD,是工程上好用的做法。
  • 随机平均梯度下降(SAG):维护每一个维度上的偏导数值形成一个数组,每次更新随机更新一个维度,用这个数组更新。
    • 训练的初期比较拉,因为初期数组基本上是全 $0$。

Python 第三方库

正规方程:

from sklearn.linear_model import LinearRegression

X = [[160], [166], [172], [174], [180]]
y = [56.3, 60.6, 65.1, 68.5, 75]

model = LinearRegression()
model.fit(X, y)

print("Coefficients:", model.coef_)
print("Intercept:", model.intercept_)

print(model.predict([[176]]))

SGD:

from sklearn.linear_model import SGDRegressor

X = [[160], [166], [172], [174], [180]]
y = [56.3, 60.6, 65.1, 68.5, 75]

# 此处参数需细调!!!这里只是例子
model = SGDRegressor(loss="squared_error", fit_intercept=True, learning_rate="constant", eta0=1e-5)
model.fit(X, y)

print("Coefficients:", model.coef_)
print("Intercept:", model.intercept_)

print(model.predict([[176]]))

欠拟合与过拟合

  • 欠拟合:训练集上拉,测试集上也拉。说明模型太简单。
  • 过拟合:虽然训练集上好,但是测试集上拉。说明模型太复杂。

  • 欠拟合的解决方案
    • 添加新特征
      • 特别地,对于线性的模型,可以尝试添加多项式特征项,如二次项等。
  • 过拟合的解决方案
    • 减少特征,防止维度灾难
    • 清洗数据
    • 增大数据量
    • 正则化

正则化

对于过大到离谱的系数,我们要进行惩罚。

假设我们原先的 loss function 是 MSE。那现在我们多加一项:

\[J(w) = \text{MSE}(w) + \alpha \sum_{i=1}^n f(w_i)\]

$\alpha$ 叫做惩罚系数。这里的 $f$ 有两种常用选择:

  • $f(x) = \lvert x \rvert$,这被称为 L1 正则化,这种回归称为 Lasso 回归
  • $f(x) = x^2$,这被称为 L2 正则化,这种回归称为 岭回归

Lasso 回归更容易使部分权重为 $0$,这让它可以做 feature selection。

工程上倾向于使用 L2 正则。