【第三部分:线性回归(Linear Regression)】
前言3.1 什么是线性回归用 “预测奶茶销量” 来理解 假设你开了一家奶茶店发现天气越热卖的奶茶越多。你想预测明天能卖多少杯好准备原料。你收集了过去 7 天的数据提示以下是本篇文章正文内容下面案例可供参考一、表格温度 (℃) 销量 (杯)20 5022 5524 6026 6828 7530 8232 90二、使用步骤1.引入库代码如下示例import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns import warnings warnings.filterwarnings(ignore)import ssl ssl._create_default_https_contextssl._create_unverified_context这就是线性回归线性回归的本质找一条直线或者超平面让它尽可能贴合所有数据点然后用这条直线来预测新的数据。3.2 线性回归的数学表达代码如下示例3.2.1 一元线性回归一个特征还是奶茶的例子只有 “温度” 这一个特征。该处使用的url网络请求的数据。y w * x by预测值预测销量x特征值温度w权重 / 斜率温度每升高 1 度销量增加多少b偏置 / 截距温度为 0 时的销量数学意义实际可能没意义用奶茶例子来说假设我们算出 w 3.2b -12那么预测公式就是销量 3.2 × 温度 - 12验证一下20℃3.2×20 - 12 64 - 12 52 杯实际 50差 2 杯30℃3.2×30 - 12 96 - 12 84 杯实际 82差 2 杯还挺准的3.2.2 多元线性回归多个特征现实中影响销量的不只是温度还有星期几、有没有促销等等。假设我们有 3 个特征x₁温度x₂是不是周末1 是 0 否x₃有没有促销1 是 0 否预测公式y w₁x₁ w₂x₂ w₃*x₃ b每个特征前面都有一个权重 w代表这个特征的重要程度w₁ 大 → 温度影响大w₂ 大 → 是不是周末影响大w₃ 大 → 促销影响大用向量形式表示更简洁y w^T · x b其中 w [w₁, w₂, w₃] 是权重向量x [x₁, x₂, x₃] 是特征向量。再简化一点把 b 也放进向量里给 x 加一个恒为 1 的特征w 加一个偏置项x [1, x₁, x₂, x₃]w [b, w₁, w₂, w₃]y w^T · x3.3 损失函数 —— 怎么衡量 “拟合得好不好”问题来了怎么判断哪条直线 “最贴合” 数据我们需要一个量化的标准这就是损失函数Loss Function。3.3.1 什么是损失损失 预测值和真实值的差距对于每个数据点真实值y预测值ŷ读作 y hat误差y - ŷ但是误差有正有负加起来可能抵消所以我们用平方误差单个样本的损失 (y - ŷ)²为什么用平方 消除正负号平方后都是正的放大误差差得远的点惩罚更重对异常点敏感数学好求导平方函数求导很方便3.3.2 均方误差MSE把所有样本的损失加起来取平均就是均方误差Mean Squared ErrorMSE (1/n) * Σ(yᵢ - ŷᵢ)²n样本数量yᵢ第 i 个样本的真实值ŷᵢ第 i 个样本的预测值用奶茶例子算一下假设我们的直线是 y 3x - 103.3.3 损失函数的几何意义把损失函数想象成一个 “山谷”横轴权重 w 的取值纵轴损失函数的值MSE形状一个碗形凸函数碗底损失最小的地方也就是最优解3.4 求解方法一最小二乘法数学公式直接算线性回归有一个 “解析解”就是可以用数学公式直接算出最优解不用迭代。3.4.1 推导思路我们的目标是最小化 MSEplaintextJ(w) (1/n) * Σ(yᵢ - w^T xᵢ)²对 w 求导令导数等于 0就能解出最优的 w。3.4.2 最终公式经过矩阵求导过程比较复杂记住结论就行最优权重为plaintextw* (X^T X)⁻¹ X^T yX特征矩阵n 行 d 列n 个样本d 个特征y标签向量n 个元素X^TX 的转置(X^T X)⁻¹X^T X 的逆矩阵用 “奶茶例子” 验证一下简化版数据x [20, 22, 24, 26, 28, 30, 32]y [50, 55, 60, 68, 75, 82, 90]用最小二乘法算出来w ≈ 3.21b ≈ -13.57所以公式是销量 3.21 × 温度 - 13.573.4.3 最小二乘法的优缺点表格优点 缺点一步到位直接算出结果 特征太多时矩阵求逆计算量很大不需要调参没有学习率 数据量太大时内存可能不够一定能找到全局最优解 必须满足 X^T X 可逆有时不可逆什么时候用特征少1000、数据量不大的时候快速验证、快速出结果的时候3.5 求解方法二梯度下降法迭代优化这是机器学习里最常用的优化方法也是你之前学的 “皮卡丘下山”站在山坡上 → 找最陡的下坡方向 → 走一步 → 重复 → 直到山底用损失函数的 “山谷” 来理解每一步做什么计算当前位置的梯度损失函数对 w 的导数沿着负梯度方向走一步更新 w重复直到收敛3.5.2 梯度下降的数学公式权重更新公式plaintextw w - α * (∂J/∂w)w当前权重α学习率learning rate—— 步长多大∂J/∂w损失函数对 w 的梯度导数减号沿着负梯度方向学习率 α 很重要 3.5.3 线性回归的梯度推导损失函数MSEplaintextJ(w) (1/n) * Σ(yᵢ - w^T xᵢ)²对 w 求导用链式法则plaintext∂J/∂w (1/n) * Σ 2*(yᵢ - w^T xᵢ) * (-xᵢ) (-2/n) * Σ (yᵢ - ŷᵢ) * xᵢ直观理解(yᵢ - ŷᵢ) 是预测误差误差越大梯度越大步子迈得越大xᵢ 是特征值特征值大的影响也大简化一下把 2/n 的常数吸收到学习率里梯度方向 Σ (ŷᵢ - yᵢ) * xᵢ3.5.5 用奶茶例子走一遍数据x [20, 22, 24, 26, 28, 30, 32]温度y [50, 55, 60, 68, 75, 82, 90]销量初始化w 0, b 0学习率 α 0.001第 1 次迭代计算预测值ŷ 0*x 0 0全是 0很离谱计算误差ŷ - y [-50, -55, -60, -68, -75, -82, -90]计算梯度∂J/∂w (2/7) * Σ(误差 * x)算出来大概是… 很大的一个负数更新参数w 0 - 0.001 * (很大的负数) → w 变大b 0 - 0.001 * (很大的负数) → b 变大第 100 次迭代w ≈ 2.8, b ≈ -5预测公式y 2.8x - 5第 1000 次迭代w ≈ 3.2, b ≈ -13越来越接近最优解了第 10000 次迭代w ≈ 3.21, b ≈ -13.57基本收敛了和最小二乘法结果一样3.6 三种梯度下降的对比梯度下降有三种常见变体各有优缺点3.6.1 批量梯度下降BGDBatch Gradient Descent每次迭代用全部训练数据计算梯度优点稳定一定往最优方向走缺点数据量大时每次迭代很慢类比考试前把所有题都做完一遍才知道自己哪里错了然后改进。3.6.2 随机梯度下降SGDStochastic Gradient Descent每次迭代随机选一个样本计算梯度优点速度快数据量大也不怕缺点不稳定路线弯弯绕绕可能震荡类比做一道题就改一下做一道改一道方向忽左忽右但总体还是往对的方向走。3.6.3 小批量梯度下降MBGDMini-Batch Gradient Descent每次迭代用一小批样本比如 32 个、64 个是 BGD 和 SGD 的折中方案优点既快又相对稳定深度学习里最常用类比做 10 道题就改一次既不会太慢也不会太不稳定。3.7 代码实现手动实现线性回归现在我们用 NumPy 手动实现一个线性回归彻底搞懂每一步3.7.1 准备数据pythonimport numpy as np奶茶店数据温度、销量X np.array([20, 22, 24, 26, 28, 30, 32], dtypenp.float32)y np.array([50, 55, 60, 68, 75, 82, 90], dtypenp.float32)注意X要变成二维矩阵n行1列因为机器学习的输入都是二维的X X.reshape(-1, 1) # 变成 (7, 1) 的形状print(“X shape:”, X.shape) # (7, 1)print(“y shape:”, y.shape) # (7,)3.7.2 数据归一化很重要为什么要归一化温度是 20-30销量是 50-90数值范围不一样如果不归一化梯度下降会走得很别扭“马克波过河” 的比喻归一化方法Min-Max 归一化把数据缩放到 [0, 1] 区间plaintextx_norm (x - min) / (max - min)python特征归一化X_min X.min()X_max X.max()X_norm (X - X_min) / (X_max - X_min)标签也可以归一化可选y_min y.min()y_max y.max()y_norm (y - y_min) / (y_max - y_min)print(“归一化后的X:”, X_norm.flatten())[0. 0.16666667 0.33333334 0.5 0.66666669 0.83333331 1. ]3.7.3 初始化参数python初始化权重和偏置w np.zeros(1) # 一个特征所以一个权重b 0.0学习率learning_rate 0.01迭代次数epochs 1000n len(X_norm) # 样本数量3.7.4 梯度下降训练pythonloss_history [] # 记录每次的损失方便画图for epoch in range(epochs):# 1. 前向传播计算预测值y_pred np.dot(X_norm, w) b # shape: (7,)# 2. 计算损失MSE loss np.mean((y_pred - y_norm) ** 2) loss_history.append(loss) # 3. 计算梯度 # dw (2/n) * Σ (ŷ - y) * x dw (2/n) * np.dot(X_norm.T, (y_pred - y_norm)) # db (2/n) * Σ (ŷ - y) db (2/n) * np.sum(y_pred - y_norm) # 4. 更新参数 w w - learning_rate * dw b b - learning_rate * db # 每100次打印一下 if (epoch 1) % 100 0: print(fEpoch {epoch1}/{epochs}, Loss: {loss:.6f})print(f\n训练完成“)print(fw {w[0]:.4f}”)print(fb {b:.4f})输出大概是这样plaintextEpoch 100/1000, Loss: 0.012345Epoch 200/1000, Loss: 0.008765…Epoch 1000/1000, Loss: 0.000123训练完成w 0.9623b 0.01893.7.5 预测新数据python预测明天35度能卖多少杯new_temp 35先归一化new_temp_norm (new_temp - X_min) / (X_max - X_min)预测pred_norm np.dot(new_temp_norm, w) b反归一化还原成真实销量pred pred_norm * (y_max - y_min) y_minprint(f预测明天{new_temp}度能卖 {pred:.1f} 杯奶茶)预测明天35度能卖 98.5 杯奶茶3.7.6 完整代码封装成类pythonclass LinearRegression:definit(self, learning_rate0.01, epochs1000):self.learning_rate learning_rateself.epochs epochsself.w Noneself.b Noneself.loss_history []def fit(self, X, y): 训练模型 n_samples, n_features X.shape # 初始化参数 self.w np.zeros(n_features) self.b 0 # 梯度下降 for _ in range(self.epochs): # 前向传播 y_pred np.dot(X, self.w) self.b # 计算损失 loss np.mean((y_pred - y) ** 2) self.loss_history.append(loss) # 计算梯度 dw (2/n_samples) * np.dot(X.T, (y_pred - y)) db (2/n_samples) * np.sum(y_pred - y) # 更新参数 self.w - self.learning_rate * dw self.b - self.learning_rate * db def predict(self, X): 预测 return np.dot(X, self.w) self.b使用示例model LinearRegression(learning_rate0.01, epochs1000)model.fit(X_norm, y_norm)predictions model.predict(X_norm)3.8 模型评估怎么判断模型好不好训练完了怎么知道模型好不好3.8.1 均方误差MSEplaintextMSE (1/n) * Σ(yᵢ - ŷᵢ)²越小越好缺点数值大小和标签的量纲有关不好直观判断3.8.2 均方根误差RMSEplaintextRMSE √MSE和标签同一个量纲更好理解比如 RMSE5说明平均差 5 杯3.8.3 平均绝对误差MAEplaintextMAE (1/n) * Σ|yᵢ - ŷᵢ|用绝对值对异常点不那么敏感3.8.4 R² 分数最重要⭐R² 分数决定系数衡量模型解释了多少数据的变化。plaintextR² 1 - (SS_res / SS_tot)SS_res Σ(yᵢ - ŷᵢ)² 残差平方和模型没解释的部分SS_tot Σ(yᵢ - ȳ)² 总平方和数据本身的变化直观理解R² 1模型完美预测所有点都在直线上R² 0模型和直接预测平均值一样烂R² 0模型还不如直接预测平均值一般来说R² 0.8模型很不错R² 在 0.5-0.8模型还可以R² 0.3模型比较差3.9 线性回归的常见问题3.9.1 线性回归的假设使用前提线性回归不是万能的它有几个假设线性关系特征和标签之间是线性关系如果不是线性的线性回归就拟合不好误差独立样本之间的误差互不影响比如时间序列数据今天的误差和昨天有关就不满足误差同方差误差的方差是恒定的不能有的地方误差大有的地方误差小误差正态分布误差服从正态分布特征不相关特征之间不能高度相关多重共线性比如同时用 “身高厘米” 和 “身高米” 作为特征就完全相关了3.9.2 多重共线性问题什么是多重共线性特征之间高度相关比如特征 1身高厘米特征 2身高米这两个特征完全线性相关有什么问题权重不稳定数据稍微变一点权重变化很大权重解释性差不知道到底是哪个特征在起作用但预测结果可能还不错怎么解决删除相关的特征留一个就行用 PCA 降维用岭回归加 L2 正则化3.9.3 异常值的影响线性回归对异常值很敏感因为用的是平方误差异常点的误差会被放大。例子本来数据点都在直线附近突然来了一个离群点直线就被 “拉歪” 了。怎么解决检查并删除异常值如果是数据错误用更鲁棒的模型比如决策树用 L1 损失MAE代替 L2 损失MSE3.10 多项式回归线性回归只能拟合直线那如果数据不是线性的怎么办答案多项式回归3.10.1 什么是多项式回归给原始特征添加高次项然后还是用线性回归来拟合。例子原始特征只有 x我们添加 x²、x³…plaintext原始y w₁x b多项式y w₁x w₂x² w₃x³ b虽然特征是高次的但对权重 w 来说还是线性的所以还是叫 “线性” 回归。直观理解一次项x直线二次项x²抛物线三次项x³S 形曲线次数越高曲线越灵活能拟合更复杂的数据3.10.2 过拟合问题 ⚠️多项式次数不是越高越好plaintext次数太低欠拟合直线拟合曲线误差大●● /●//●/ ●次数适中刚好拟合●●● ●● ●● ●次数太高过拟合把每个点都精准穿过但弯弯绕绕新数据预测不准●●╱ ╲● ●╱ ╲● ●过拟合模型在训练集上表现很好但在测试集上表现很差。模型把训练数据的 “噪音” 也学进去了就像学生背答案考试遇到原题考满分换个题就不会了怎么解决过拟合增加数据量减少特征降低多项式次数正则化后面讲✅ 第三部分小结线性回归核心知识点表格知识点 核心内容 关键词什么是线性回归 找一条直线拟合数据用来预测 直线、拟合、预测数学表达 y w·x b 权重 w、偏置 b损失函数 均方误差 MSE (1/n)Σ(y-ŷ)² 平方误差、最小化最小二乘法 直接用公式算最优解 解析解、矩阵求逆梯度下降 迭代优化一步步下山 学习率、负梯度、收敛三种梯度下降 BGD/SGD/MBGD 批量、随机、小批量评估指标 MSE、RMSE、MAE、R² R² 最重要越接近 1 越好常见问题 多重共线性、异常值、过拟合 假设、前提条件多项式回归 添加高次项拟合曲线 过拟合、欠拟合