Lesson 3 线性回归
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)\]平均绝对误差 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 正则。