尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

最小二乘法:从原理到实践,掌握线性回归与机器学习基石

最小二乘法:从原理到实践,掌握线性回归与机器学习基石 1. 项目概述从“猜”到“算”的思维跃迁干了这么多年数据分析和算法工程我越来越觉得很多听起来高大上的机器学习概念其核心思想往往朴素得惊人。今天想聊的“最小二乘法”就是这样一个典型。你可能在各种教科书、论文或者技术博客里见过它公式看起来有点复杂但它的内核其实就是我们解决“猜不准”这个问题时一种最本能、最优雅的数学表达。简单说它就是在一堆散乱的数据点里找出一条最“合适”的直线或曲线让这条线到所有点的“总体距离”最小。这个“总体距离”用的就是“差的平方和”所以叫“最小二乘”。别被“机器学习”这个词吓到。无论你是刚入门的数据科学新生还是在为“山东大学机器学习期末”或“西电机器学习期末”复习抓耳挠腮的同学亦或是工作中需要快速理解模型原理的工程师最小二乘法都是你必须啃下的第一块硬骨头。它不仅是线性回归的基石更是理解整个参数化模型拟合思想的钥匙。掌握了它你再看逻辑回归、支持向量机甚至一些神经网络都会有“哦原来是这个思路”的豁然开朗感。它解决的就是从“transform机器学习 word文档”里那些枯燥理论到亲手构建一个“机器学习模型”并理解其“应用流程”之间最关键的一步跨越。2. 核心思想与数学原理拆解2.1 问题场景我们究竟想干什么想象一个最经典的场景你想研究房屋面积X和售价Y之间的关系。你手头有100套房子的数据把它们画在坐标系上得到100个散点。肉眼看去这些点大致呈一条斜向上的带状分布但并非严格在一条直线上。现在你想用一条直线来概括这种关系以便预测一个新面积的房子大概能卖多少钱。这条直线方程我们设为Y wX b。这里的w权重和b偏置就是我们需要确定的两个参数。问题来了有无数条可能的直线哪一条才是“最好”的这就需要定义一个“好”的标准。2.2 损失函数如何定义“犯错”的成本“好”的反面是“犯错”。对于第i个数据点(x_i, y_i)我们用直线预测的值是ŷ_i w*x_i b真实值是y_i。那么预测误差残差就是e_i y_i - ŷ_i。如果简单地把所有误差加起来Σe_i行不行不行。因为误差有正有负直接相加会相互抵消比如一条直线在某个点高估了10万在另一个点低估了10万总和为0但这显然不是一条好直线。于是很自然地想到用绝对值来消除正负影响Σ|e_i|。这叫做最小一乘法。它在数学上没问题但绝对值函数在零点不可导后续求解计算比较麻烦。最小二乘法采用了另一种更“平滑”的思路对误差取平方e_i²。平方操作同样消除了正负号并且放大了大误差的影响因为平方增长更快同时平方函数处处可导性质非常好。我们把所有数据点的误差平方加起来就得到了损失函数Loss Function也称为目标函数L(w, b) Σ(y_i - (w*x_i b))²求和从 i1 到 nn是样本数我们的目标就是找到一对w和b使得这个损失函数L的值达到最小。这就是“最小二乘法”名称的由来最小化误差的平方和。注意为什么是“二乘”“二乘”就是平方的意思。中国古代称平方为“二乘”这个叫法在数学中沿用下来。2.3 求解过程从几何与微积分视角理解如何找到使L最小的w和b这是微积分中的经典问题求多元函数的极值点。1. 几何视角损失函数L(w, b)可以看作一个三维空间中的曲面碗状。这个曲面必然有一个最低点。最小二乘法的解就是这个碗的碗底坐标(w*, b*)。2. 微积分视角在碗底这个最低点函数L分别对w和b的偏导数都应为0这是极值点的必要条件。这为我们提供了两个方程∂L/∂w 0-2 * Σ[x_i * (y_i - w*x_i - b)] 0∂L/∂b 0-2 * Σ(y_i - w*x_i - b) 0整理这两个方程我们得到一个关于w和b的二元一次方程组称为正规方程Normal Equationsw * Σx_i² b * Σx_i Σ(x_i * y_i) w * Σx_i b * n Σy_i解这个方程组就能得到w和b的解析解闭式解w (nΣx_i y_i - Σx_i Σy_i) / (nΣx_i² - (Σx_i)²) b (Σy_i - wΣx_i) / n这个解是精确的、唯一的只要分母不为零。这意味着对于线性回归问题我们不需要用复杂的迭代算法直接通过一套公式计算就能得到全局最优解。这是最小二乘法在线性模型中的一个巨大优势。2.4 扩展到多元情形现实中房价不可能只由面积决定。我们还可能考虑房间数、楼层、房龄等多个特征。此时自变量X从一个标量变成了一个向量[x1, x2, ..., xp]参数w也变成一个向量[w1, w2, ..., wp]。模型变为Y w1*X1 w2*X2 ... wp*Xp b用矩阵表示非常简洁Y Xβ这里X是增加了全为1的列以包含偏置b的矩阵β是包含所有参数的向量。此时的损失函数为L(β) (Y - Xβ)^T (Y - Xβ)对其求导并令导数为零得到正规方程的矩阵形式X^T X β X^T Y解为β (X^T X)^{-1} X^T Y这个公式是机器学习中最重要的公式之一它清晰地展示了数据X、Y与模型参数β之间的数学关系。3. 实操实现从公式到代码理解了原理我们动手实现它。这里我会展示纯Python实现和利用NumPy的向量化实现并比较它们的优劣。3.1 基础Python实现我们先从最直观的、基于公式的循环实现开始。这有助于彻底理解计算过程的每一个细节。def least_squares_naive(x_list, y_list): 使用最小二乘法拟合一元线性回归模型 (原始公式版) 参数: x_list: 自变量列表 y_list: 因变量列表 返回: w: 斜率 b: 截距 n len(x_list) # 计算必要的中间量 sum_x sum(x_list) sum_y sum(y_list) sum_xy sum(x * y for x, y in zip(x_list, y_list)) sum_x2 sum(x * x for x in x_list) # 计算分母防止除零错误 denominator n * sum_x2 - sum_x * sum_x if abs(denominator) 1e-10: # 处理数值问题 raise ValueError(数据可能导致分母为零或过小无法计算。) # 根据公式计算 w 和 b w (n * sum_xy - sum_x * sum_y) / denominator b (sum_y - w * sum_x) / n return w, b # 示例数据房屋面积(平米)和售价(万元) areas [50, 60, 70, 80, 90, 100] prices [150, 180, 210, 240, 265, 290] w, b least_squares_naive(areas, prices) print(f拟合直线方程: y {w:.4f} * x {b:.4f}) print(f斜率w(单价): 每平米约{w:.2f}万元) print(f截距b(基础价): {b:.2f}万元)输出结果示例拟合直线方程: y 2.8571 * x 7.1429 斜率w(单价): 每平米约2.86万元 截距b(基础价): 7.14万元实操心得在实现基础公式时一定要处理分母为零或接近零的边界情况。这通常发生在所有x值都相同的时候意味着数据没有提供任何关于x变化的信息自然无法拟合出有意义的斜率。添加一个极小的阈值判断是工程上的好习惯。3.2 NumPy向量化实现对于多元回归或大数据集循环效率太低。NumPy的向量化操作能极大提升计算速度并且代码更简洁。import numpy as np def least_squares_vectorized(X, y): 使用最小二乘法拟合线性回归模型 (NumPy向量化版) 参数: X: 特征矩阵形状为 (n_samples, n_features)。对于一元回归需reshape为列向量。 y: 目标值向量形状为 (n_samples,) 返回: beta: 参数向量包含偏置项。beta[0]是偏置bbeta[1:]是权重w。 # 为X添加一列全1用于计算偏置项b (即X01的系数) X_b np.c_[np.ones((X.shape[0], 1)), X] # 拼接后形状: (n_samples, n_features1) # 计算正规方程的解: beta (X^T X)^{-1} X^T y # 使用np.linalg.pinv求伪逆比直接求逆更数值稳定能处理X^T X不满秩的情况 beta np.linalg.pinv(X_b.T X_b) X_b.T y # 等价于: beta np.linalg.lstsq(X_b, y, rcondNone)[0] (更推荐专门求解最小二乘) return beta # 示例一元回归 areas_np np.array(areas).reshape(-1, 1) # 转为列向量 (6,1) prices_np np.array(prices) beta least_squares_vectorized(areas_np, prices_np) print(f参数向量beta: {beta}) print(f偏置b: {beta[0]:.4f}) print(f权重w: {beta[1]:.4f}) # 示例多元回归假设新增一个特征房间数 rooms np.array([2, 2, 3, 3, 4, 4]) # 构造特征矩阵X两列面积和房间数 X_multi np.column_stack((areas_np, rooms)) beta_multi least_squares_vectorized(X_multi, prices_np) print(f\n多元回归参数: {beta_multi}) print(f方程: 价格 {beta_multi[0]:.2f} {beta_multi[1]:.2f}*面积 {beta_multi[2]:.2f}*房间数)输出结果示例参数向量beta: [ 7.14285714 2.85714286] 偏置b: 7.1429 权重w: 2.8571 多元回归参数: [ 5.00000000e00 2.50000000e00 1.25000000e01] 方程: 价格 5.00 2.50*面积 12.50*房间数核心技巧np.linalg.lstsq是NumPy提供的专门用于求解最小二乘问题的函数它内部使用了更稳定、更高效的数值算法如SVD分解能处理秩亏矩阵比手动计算(X^T X)^{-1}更健壮是生产环境中的首选。手动求逆仅适用于教学和理解原理。3.3 使用Scikit-learn进行生产级实现在实际的机器学习项目中我们几乎总是使用成熟的库如Scikit-learn。它高效、稳定且接口统一。from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_squared_error, r2_score # 准备数据 X np.array(areas).reshape(-1, 1) y np.array(prices) # 创建模型实例。注意默认设置fit_interceptTrue拟合截距normalizeFalse。 model LinearRegression() # 拟合模型训练 model.fit(X, y) # 获取参数 print(fScikit-learn 拟合结果:) print(f截距 (b): {model.intercept_:.4f}) print(f系数 (w): {model.coef_}) # 进行预测 areas_new np.array([[55], [120]]) # 预测55平和120平房子的价格 prices_pred model.predict(areas_new) print(f预测房价: 55平 - {prices_pred[0]:.2f}万, 120平 - {prices_pred[1]:.2f}万) # 评估模型 y_pred model.predict(X) mse mean_squared_error(y, y_pred) r2 r2_score(y, y_pred) print(f均方误差 (MSE): {mse:.2f}) print(f决定系数 (R²): {r2:.4f})输出结果示例Scikit-learn 拟合结果: 截距 (b): 7.1429 系数 (w): [2.85714286] 预测房价: 55平 - 164.29万, 120平 - 350.00万 均方误差 (MSE): 14.88 决定系数 (R²): 0.9949注意事项LinearRegression默认使用最小二乘法基于scipy.linalg.lstsq。R²值越接近1说明模型对数据的拟合程度越好。但要注意高R²在训练集上很容易获得不代表模型泛化能力强需在测试集上进一步验证。4. 深入理解假设、局限与陷阱最小二乘法不是银弹它的有效性建立在一系列统计假设之上。忽略这些假设盲目使用很可能得到错误甚至荒谬的结论。4.1 高斯-马尔可夫定理与经典假设最小二乘法能得到“最优”估计BLUE最佳线性无偏估计依赖于以下经典假设线性关系因变量与自变量之间确实存在线性关系。这是模型形式的基本假设。随机抽样样本数据是随机从总体中抽取的。无完全共线性自变量之间不存在严格的线性关系。否则X^T X矩阵不可逆无法求解。条件零均值误差项ε的期望值为0。这意味着没有系统性偏差所有影响Y的因素都已包含在模型中。同方差性误差项ε的方差为常数。即数据点的波动幅度大致相同。无自相关不同观测值的误差项之间不相关。正态性可选但常用误差项ε服从正态分布。这个假设主要用于假设检验和构建置信区间。4.2 常见问题与诊断当这些假设被违反时模型就会出现问题。下面是一个问题诊断表问题可能违反的假设诊断方法后果与解决方案预测不准模式复杂线性关系绘制Y与X的散点图绘制残差与预测值的散点图若存在曲线模式则违反。模型无法捕捉真实模式。方案考虑添加多项式特征如X²、使用样条回归或非线性模型。异方差同方差性绘制残差与预测值的散点图观察残差分布是否随预测值增大而扩散如漏斗形。参数估计仍无偏但标准误估计不准导致假设检验失效。方案使用加权最小二乘法WLS或稳健标准误。异常值/强影响点所有假设计算库克距离、杠杆值。可视化残差图、杠杆值图。个别点对回归线产生巨大拉扯扭曲整体关系。方案检查数据是否正确使用稳健回归方法如RANSAC Huber回归。多重共线性无完全共线性计算方差膨胀因子VIF。通常VIF 10表示存在严重共线性。系数估计值方差变大不稳定难以解释单个变量的影响。方案剔除高度相关的变量使用主成分回归PCR或岭回归L2正则化。自相关时间序列常见无自相关绘制残差序列图进行Durbin-Watson检验DW统计量接近2表示无自相关。标准误被低估导致t检验失效。方案使用时间序列模型如ARIMA或包含滞后项。4.3 一个关键的陷阱过拟合与正则化最小二乘法的目标是完美拟合训练数据使损失函数降到最低。但在特征很多p很大甚至接近样本数n时这会导致一个严重问题过拟合。模型会变得极其复杂不仅拟合了数据中的普遍规律也“记住”了训练数据中的随机噪声。其结果是在训练集上表现完美R²很高MSE很低但在未见过的测试集上表现糟糕。解决方案是引入正则化即在损失函数中加入对模型复杂度的惩罚项。岭回归Ridge Regression, L2正则化 损失函数变为L(β) Σ(y_i - ŷ_i)² α * Σβ_j²j从1到p通常不惩罚截距项 它惩罚大的系数使所有系数向零收缩能有效处理多重共线性提高模型稳定性。套索回归Lasso Regression, L1正则化 损失函数变为L(β) Σ(y_i - ŷ_i)² α * Σ|β_j|它不仅能收缩系数还能将一些不重要的特征的系数压缩至零从而实现自动特征选择。from sklearn.linear_model import Ridge, Lasso from sklearn.preprocessing import StandardScaler # 正则化前通常需要标准化 # 假设我们有一个高维数据集 # X_high_dim: (n_samples, n_features), n_features 很大 scaler StandardScaler() X_scaled scaler.fit_transform(X_high_dim) # 岭回归 ridge_model Ridge(alpha1.0) # alpha是正则化强度 ridge_model.fit(X_scaled, y) print(岭回归系数部分趋于小值但很少为0:, ridge_model.coef_[:5]) # 套索回归 lasso_model Lasso(alpha0.01, max_iter10000) lasso_model.fit(X_scaled, y) print(套索回归系数部分严格为0:, lasso_model.coef_[:5]) print(f非零系数个数: {np.sum(lasso_model.coef_ ! 0)})实操心得使用正则化时特征标准化减均值除标准差是必须的步骤。因为正则化惩罚项对系数大小一视同仁如果特征量纲不同如年龄0-100和收入0-1000000量纲大的特征会天然承受更大的惩罚这不公平。StandardScaler能解决这个问题。alpha参数控制正则化强度需要通过交叉验证来调优。5. 工程实践与性能考量在实际的机器学习应用流程中最小二乘法及其变种的应用远不止于拟合一条直线。我们需要从工程角度考虑其效率、规模和稳定性。5.1 大规模数据下的求解迭代方法当数据量极大样本数n或特征数p上百万时直接求解正规方程β (X^T X)^{-1} X^T Y会变得不可行。计算X^T X的复杂度是O(p² n)求逆的复杂度是O(p³)内存和计算开销都巨大。此时我们需要使用迭代优化算法来近似求解最小二乘问题最常见的是梯度下降法及其变种随机梯度下降SGD、小批量梯度下降。梯度下降法的核心思想是损失函数L(β)的梯度方向是其上升最快的方向。那么沿着梯度的反方向即下降方向更新参数β就能逐步逼近最小值。对于线性回归的损失函数L(β) (1/2n) Σ(y_i - ŷ_i)²其对参数β_j的梯度为∂L/∂β_j -(1/n) Σ x_ij (y_i - ŷ_i)参数更新公式为β_j : β_j - η * ∂L/∂β_j其中η是学习率控制每一步更新的幅度。# 梯度下降法实现线性回归简易版 def gradient_descent(X, y, learning_rate0.01, n_iters1000): n_samples, n_features X.shape # 初始化参数 beta np.zeros(n_features) # 为计算方便添加偏置列 X_b np.c_[np.ones(n_samples), X] # 梯度下降迭代 for i in range(n_iters): # 计算预测值 y_pred X_b.dot(beta) # 计算误差 error y_pred - y # 计算梯度 (向量化形式) gradients (1/n_samples) * X_b.T.dot(error) # 更新参数 beta - learning_rate * gradients # 可选每100次迭代打印损失 if i % 100 0: loss (1/(2*n_samples)) * np.sum(error**2) print(fIteration {i}: loss {loss:.4f}) return beta # 使用标准化后的数据 beta_gd gradient_descent(X_scaled, y, learning_rate0.1, n_iters1000) print(梯度下降求解的参数:, beta_gd)核心技巧学习率η的选择至关重要。太大可能导致震荡甚至发散太小则收敛缓慢。通常需要尝试一系列值如0.001, 0.01, 0.1并观察损失函数下降曲线。对于特征尺度差异大的数据务必先进行标准化否则梯度下降会很难收敛。5.2 数值稳定性与病态问题即使数据规模不大直接求解正规方程也可能遇到数值计算问题。核心在于矩阵X^T X的条件数。如果特征之间存在高度相关性多重共线性或者某些特征的尺度相差巨大X^T X会接近奇异矩阵行列式接近0其条件数很大求逆运算会变得非常不稳定微小的数据扰动会导致解的巨大变化。解决方案特征标准化/归一化如前所述这是预处理的基本步骤。使用更稳定的求解器如np.linalg.lstsq或scipy.linalg.lstsq它们内部使用SVD奇异值分解或QR分解比直接求逆更稳定。添加正则化岭回归在X^T X的对角线上添加一个小的常数α即求解(X^T X αI)β X^T y。这能显著改善矩阵的条件数使求逆操作稳定。这本质上是为问题引入了一点先验信息系数不应太大。5.3 在线学习与增量更新在流式数据或实时学习场景下数据是源源不断到来的。我们不可能每次都保存全部历史数据重新计算(X^T X)^{-1} X^T Y。这时需要递归最小二乘法RLS或随机梯度下降SGD这类在线学习算法。其核心思想是当新数据点(x_{new}, y_{new})到来时利用旧的参数估计和协方差矩阵通过一个更新公式快速得到新的参数估计而无需重新处理全部数据。这在“储能EMS系统”的实时负荷预测或“机器学习检测”系统中的模型快速自适应等场景下非常有用。虽然RLS的推导稍复杂但其思想与卡尔曼滤波类似是工程实践中处理序列数据拟合的强大工具。6. 从最小二乘看机器学习模型评估拟合完模型我们如何知道它好不好最小二乘法的损失函数本身——均方误差MSE——就是一个最直接的评估指标。但仅仅看MSE是不够的。6.1 误差分解与R²总平方和SST衡量了因变量Y自身的总波动SST Σ(y_i - y_mean)²回归平方和SSR衡量了模型解释的波动SSR Σ(ŷ_i - y_mean)²残差平方和SSE衡量了模型未能解释的波动SSE Σ(y_i - ŷ_i)²三者关系SST SSR SSE决定系数 R²定义为R² SSR / SST 1 - SSE / SST它表示模型能够解释的目标变量方差的比例。R²越接近1说明模型对数据的拟合程度越好。但要注意R²会随着特征数量的增加而自然增大即使加入无关特征。因此对于多元回归我们更常用调整后R²Adjusted R² 1 - [(1 - R²)(n - 1) / (n - p - 1)]其中p是特征数。调整后R²会对无关特征进行惩罚。6.2 交叉验证防止过拟合的黄金准则正如前文所述在训练集上表现好高R²低MSE可能是过拟合的结果。为了可靠地评估模型泛化能力必须使用交叉验证。最常用的是K折交叉验证将数据集随机分成K个大小相似的子集折。依次将其中一个子集作为测试集其余K-1个子集作为训练集。在训练集上训练模型在测试集上计算评估指标如MSE。重复K次得到K个测试分数最后计算其平均值作为模型泛化性能的估计。from sklearn.model_selection import cross_val_score from sklearn.linear_model import LinearRegression model LinearRegression() # 执行5折交叉验证评估指标为负均方误差scikit-learn约定 scores cross_val_score(model, X, y, cv5, scoringneg_mean_squared_error) # 将负MSE转为正MSE mse_scores -scores print(f各折MSE: {mse_scores}) print(f交叉验证平均MSE: {mse_scores.mean():.2f} (/- {mse_scores.std() * 2:.2f}))注意事项交叉验证的折数K需要选择。K太小如2评估方差大K太大如等于样本数即留一法计算成本高且各折训练集高度相似。K5或K10是常见的选择。进行交叉验证前如果数据有顺序如时间序列需要先打乱或使用专门的时间序列交叉验证方法。7. 总结与延伸思考走完这一趟从原理到公式、从代码到实践、从优势到陷阱的旅程你应该对最小二乘法不再感到陌生和畏惧。它就像一把精准的尺子为我们从混乱的数据中丈量出那条最“公允”的趋势线。我个人在多年的实践中对最小二乘法的体会是它首先是一种思想其次才是一个方法。“最小化误差平方和”这个思想贯穿了整个监督学习。当你学习支持向量机SVM时它的目标是最大化间隔这可以转化为一个带约束的优化问题当你学习逻辑回归时它的目标是最大化似然函数等价于最小化交叉熵损失。这些不同形式的损失函数其核心哲学与最小二乘一脉相承——定义一个衡量模型“犯错”程度的函数然后想办法让这个函数值最小。最后分享一个在特征工程中的小技巧当你怀疑特征与目标之间的关系不是简单的直线而可能是曲线时不要急于换用复杂的非线性模型。可以先尝试使用最小二乘法拟合一个多项式回归。这非常简单只需将原始特征X扩展为[X, X², X³, ...]然后扔进线性回归模型。这本质上还是在用最小二乘法但模型能力却得到了非线性扩展。当然要小心过拟合务必使用交叉验证来选择合适的多项式阶数。机器学习的世界浩瀚如海但只要你牢牢掌握了最小二乘法这把钥匙就相当于打通了理解众多模型的第一道关隘。无论是应对期末考试还是在实际项目中构建预测模型这份从根基处建立起来的直觉和理解都会让你走得更稳、更远。
返回列表