拓冰建站拓冰建站
首页 / 资讯中心 / 正文

线性最小二乘:从数学原理到工程实践,掌握数据拟合的核心技术

1. 项目概述从“凑合”到“最优”的数学艺术“线性最小二乘”这六个字听起来充满了数学的严肃感仿佛离我们很远。但如果你曾经用Excel画过一条穿过一堆散点的趋势线或者用手机App记录体重并看到一条预测线那么你已经和它打过交道了。本质上它解决的是一个我们生活中无处不在的问题如何从一堆看起来杂乱无章的数据里找到那条最能代表它们整体规律的直线或更一般的线性规律想象一下你是一个产品经理手上有过去12个月的用户增长数据点状图看起来上下波动。老板问你“照这个趋势下个季度我们能到多少” 你不可能随便指一个点也不能画一条穿过所有点的折线那叫过拟合毫无预测能力。你需要一条简洁的直线它不一定穿过任何一个实际数据点但它到所有点的“总体距离”是最小的。这条直线就是线性最小二乘给你的答案。它不追求完美穿过每一个点那通常不可能而是追求一种全局意义上的“最佳妥协”或“最优拟合”。这种方法之所以强大不仅在于其数学上的优雅和解析解的便利性更在于它奠定了整个现代数据分析、机器学习乃至工程优化的基石之一。无论是金融领域的资本资产定价模型还是工业上的传感器校准背后都有它的身影。2. 核心思想与数学模型拆解误差的平方和最小化线性最小二乘的核心思想可以用一句话概括寻找一组参数使得模型预测值与实际观测值之差的平方和达到最小。这个“差的平方”就是“二乘”的由来古代称平方为“二乘”而“最小”就是我们的优化目标。2.1 问题形式化从场景到方程我们假设有n组观测数据每组数据包含一个自变量x和一个因变量y。我们认为y和x之间存在线性关系即y ≈ β₀ β₁ * x。这里的β₀是截距β₁是斜率它们就是我们要求解的未知参数。对于第i个数据点(x_i, y_i)模型的预测值是ŷ_i β₀ β₁ * x_i而实际值是y_i。那么预测误差或称残差就是e_i y_i - ŷ_i。线性最小二乘的目标函数S就是所有残差的平方和S(β₀, β₁) Σ (y_i - (β₀ β₁ * x_i))²其中求和i从1到n。我们的任务就是找到一对(β₀, β₁)使得S这个关于β₀和β₁的函数的值最小。为什么是平方和而不是绝对值和主要原因有两个第一数学上处理平方项求导比处理绝对值项要容易得多能直接得到解析解第二平方项对大误差给予更大的惩罚这使得拟合结果对异常值相对更敏感这既是优点也是缺点后续会讨论。2.2 求解过程求导与正规方程如何找到这个最小值点在微积分中我们知道函数在极值点处对各个自变量的偏导数应为零。因此我们分别对β₀和β₁求偏导并令其等于零对β₀求偏导∂S/∂β₀ -2 Σ (y_i - β₀ - β₁*x_i) 0对β₁求偏导∂S/∂β₁ -2 Σ [x_i * (y_i - β₀ - β₁*x_i)] 0将这两个方程整理就得到了著名的正规方程n * β₀ (Σ x_i) * β₁ Σ y_i (Σ x_i) * β₀ (Σ x_i²) * β₁ Σ (x_i * y_i)这是一个关于β₀和β₁的二元一次方程组直接求解即可得到最优参数的解析解β₁ [nΣ(x_i y_i) - Σx_i Σy_i] / [nΣ(x_i²) - (Σx_i)²]β₀ (Σy_i / n) - β₁ * (Σx_i / n) ȳ - β₁ * x̄其中x̄和ȳ分别是x和y的样本均值。这个解具有清晰的统计意义最优拟合直线必然穿过数据的中心点(x̄, ȳ)。注意这里有一个重要的前提即分母[nΣ(x_i²) - (Σx_i)²]不能为零。这等价于要求x的取值不能全部相同即方差不为零。如果所有x都相同我们是在用一条竖直线去拟合这已经超出了简单线性回归的范畴。2.3 从二维到多维矩阵形式与通用性上述是针对一个自变量的简单线性回归。现实中一个结果往往由多个因素决定。例如房价可能同时受面积、卧室数量、房龄等因素影响。此时模型扩展为多元线性回归y ≈ β₀ β₁*x₁ β₂*x₂ ... β_p*x_p。用矩阵表示会异常简洁。令y为n×1的观测值向量。X为n×(p1)的设计矩阵其第一列通常全为1对应截距β₀后续各列为各自变量的观测值。β为(p1)×1的待求参数向量。则模型可写为y ≈ Xβ。目标函数变为S(β) ||y - Xβ||²即向量差的二范数平方。通过类似的求导过程这里涉及矩阵微积分我们可以得到正规方程的矩阵形式(XᵀX) β Xᵀy如果XᵀX是可逆的则最优参数解为β (XᵀX)⁻¹ Xᵀy这个公式是线性最小二乘理论的基石它统一了从简单到复杂的所有线性拟合问题。然而“可逆”这个条件至关重要它要求设计矩阵X是列满秩的即自变量之间不能存在严格的线性相关共线性。在实际计算中即使可逆如果XᵀX接近奇异病态条件数也会导致解数值不稳定这是工程应用中需要警惕的问题。3. 核心细节解析与实操要点理解了数学原理我们来看看在实际应用中如何正确、稳健地使用线性最小二乘。这远不止是套公式计算那么简单。3.1 模型假设与诊断你的数据“听话”吗线性最小二乘之所以能给出最优线性无偏估计依赖于几个经典假设高斯-马尔可夫定理。在使用前和得到结果后检查这些假设是否被严重违背至关重要线性关系因变量与自变量之间的关系确实是线性的。可以通过绘制y与每个x的散点图来初步判断。独立性各观测值之间是相互独立的。这在时间序列数据或空间数据中常常被违反例如今天的股价受昨天影响。同方差性残差的方差应为一个常数不随自变量的变化而变化。如果残差图呈现漏斗形或扇形则存在异方差性此时最小二乘估计虽仍无偏但不再是效率最高的。正态性残差应服从正态分布。这对于小样本情况下参数估计的显著性检验t检验F检验尤为重要。可以通过Q-Q图或 Shapiro-Wilk 检验来检查。无多重共线性自变量之间不应有高度的相关性。否则会导致XᵀX矩阵病态参数估计的标准误急剧增大使得结果难以解释。可以通过方差膨胀因子来诊断。实操心得永远不要拿到数据就直接跑回归。花80%的时间做数据探索和清洗20%的时间建模这个比例是值得的。先画图看看分布看看关系检查异常值。一个明显的异常点可能把整条回归线“拉偏”。3.2 评估拟合效果几个关键指标得到拟合直线后我们如何评价它“好”还是“不好”决定系数 R²最常用的指标表示模型能够解释的因变量方差的比例。R² 1 - (SS_res / SS_tot)其中SS_res是残差平方和SS_tot是总平方和。R²越接近1拟合越好。但要注意增加自变量总会使 R² 增加即使这个变量无关紧要。因此在多元回归中更常用调整后 R²它对自变量数量进行了惩罚。残差标准误衡量模型预测的典型误差大小单位与因变量y相同比R²更直观。例如在预测房价的模型中RSE为5万元意味着模型的典型预测误差在5万元左右。F 统计量用于检验整个模型是否显著即所有自变量的系数是否不全为零。对应的 p 值若小于显著性水平如0.05则拒绝原假设认为模型整体是有效的。t 统计量与 p 值用于检验单个自变量的系数是否显著不为零。这是判断某个因素是否对结果有真实影响的关键。3.3 工具选型与实现从手算到专业库对于学习和理解我强烈建议你手动实现一遍简单线性回归的计算哪怕是在Excel里用公式算一遍Σx,Σy,Σxy,Σx²然后套用公式求解β₀和β₁。这个过程能让你对原理有肌肉记忆般的理解。对于实际工作我们当然使用现成的工具Python (scikit-learn / statsmodels)sklearn.linear_model.LinearRegression简单易用适合预测statsmodels.OLS提供更详细的统计诊断信息如假设检验、置信区间适合统计分析。R语言lm()函数是核心配合summary()可以输出非常全面的统计报告。MATLABfitlm()或直接使用反斜杠运算符\如beta X\y。这里以 Python 的statsmodels为例展示一个完整的流程包含诊断import numpy as np import statsmodels.api as sm import matplotlib.pyplot as plt # 1. 准备数据 np.random.seed(42) x np.random.randn(100) y 2.5 * x np.random.randn(100) * 0.5 1.0 # 真实模型: y 1.0 2.5*x noise # 2. 添加常数项对应截距β0 X sm.add_constant(x) # 3. 建立并拟合模型 model sm.OLS(y, X) results model.fit() # 4. 查看详细结果 print(results.summary()) # 5. 绘制拟合直线与原始数据 plt.scatter(x, y, alpha0.6, labelData) plt.plot(x, results.fittedvalues, r-, labelOLS Fit) plt.xlabel(X) plt.ylabel(Y) plt.legend() plt.show() # 6. 绘制残差图进行诊断 fig, axes plt.subplots(1, 2, figsize(12, 4)) axes[0].scatter(results.fittedvalues, results.resid, alpha0.6) axes[0].axhline(y0, colorr, linestyle--) axes[0].set_xlabel(Fitted values) axes[0].set_ylabel(Residuals) axes[0].set_title(Residuals vs Fitted) # Q-Q图检查正态性 sm.qqplot(results.resid, line45, axaxes[1]) axes[1].set_title(Q-Q Plot) plt.tight_layout() plt.show()运行results.summary()会输出一个非常丰富的表格包含系数估计值、标准误、t值、p值、R²、调整后R²、F统计量等所有关键信息。残差图用于检查同方差性Q-Q图用于检查正态性。4. 实操过程与核心环节实现让我们通过一个更贴近实际的案例走一遍完整的线性回归分析流程。假设我们是一家电商的数据分析师想研究“网站页面停留时间分钟”和“用户消费金额元”之间的关系。4.1 数据准备与探索性分析首先我们模拟并查看数据import pandas as pd import seaborn as sns # 模拟数据 np.random.seed(123) n_samples 150 time_spent np.random.uniform(1, 30, n_samples) # 停留时间 1-30分钟 # 消费金额与停留时间正相关并加入一些噪声和异常值 spend 15 5 * time_spent np.random.randn(n_samples) * 20 # 故意加入两个异常高消费值 spend[-2:] [400, 380] time_spent[-2:] [12, 25] df pd.DataFrame({time_spent: time_spent, spend: spend}) print(df.describe()) print(f\n相关系数矩阵\n{df.corr()}) # 绘制散点图 plt.figure(figsize(10, 6)) sns.scatterplot(datadf, xtime_spent, yspend) plt.title(Scatter Plot: Spend vs. Time Spent) plt.xlabel(Time Spent (min)) plt.ylabel(Spend (CNY)) plt.grid(True) plt.show()从描述性统计和散点图我们能立刻发现两个远离主体群的异常点高消费。初步看主体数据呈现一定的正相关趋势。4.2 模型建立与包含异常值的影响我们先不做任何处理直接建立模型X_raw sm.add_constant(df[time_spent]) model_raw sm.OLS(df[spend], X_raw) results_raw model_raw.fit() print(【包含异常值的模型结果】) print(results_raw.summary().tables[1])观察结果我们可能会得到一个显著的模型但残差图会立刻暴露问题# 诊断图 fig plt.figure(figsize(14, 4)) # 残差 vs 拟合值 ax1 fig.add_subplot(131) ax1.scatter(results_raw.fittedvalues, results_raw.resid, alpha0.6) ax1.axhline(y0, colorr, linestyle--) ax1.set_xlabel(Fitted Values) ax1.set_ylabel(Residuals) ax1.set_title(Residuals vs Fitted (With Outliers)) # 残差分布 ax2 fig.add_subplot(132) ax2.hist(results_raw.resid, bins20, edgecolorblack) ax2.set_xlabel(Residuals) ax2.set_ylabel(Frequency) ax2.set_title(Histogram of Residuals) # Q-Q图 ax3 fig.add_subplot(133) sm.qqplot(results_raw.resid, line45, axax3) ax3.set_title(Q-Q Plot) plt.tight_layout() plt.show()残差vs拟合值图中右上角会出现两个残差极大的点对应异常值严重违反了同方差和正态性假设。这两个点对回归线产生了巨大的“拉力”。4.3 异常值处理与稳健回归对于异常值我们需要谨慎处理。首先分析其合理性是数据录入错误还是真实的“高净值用户”如果是错误可以修正或删除如果是真实情况则需要考虑是否应该为这类用户建立单独的模型。假设我们判断这两个点为录入错误决定剔除它们。同时我们引入一种更稳健的拟合方法作为对比Huber回归。它是线性最小二乘的一种推广通过修改损失函数降低异常值的影响。from sklearn.linear_model import HuberRegressor # 方法1直接剔除异常值假设我们识别出索引为148, 149的点 df_clean df.drop([148, 149]).reset_index(dropTrue) X_clean sm.add_constant(df_clean[time_spent]) model_clean sm.OLS(df_clean[spend], X_clean) results_clean model_clean.fit() # 方法2使用稳健回归Huber处理原数据包含异常值 huber HuberRegressor(epsilon1.35) # epsilon是控制对异常值敏感度的参数 huber.fit(df[[time_spent]], df[spend]) beta1_huber, beta0_huber huber.coef_[0], huber.intercept_ print(\n【清理异常值后的模型结果】) print(results_clean.summary().tables[1]) print(f\n【Huber稳健回归结果】) print(f截距 β0: {beta0_huber:.2f}) print(f斜率 β1: {beta1_huber:.2f}) # 可视化对比 plt.figure(figsize(12, 6)) plt.scatter(df_clean[time_spent], df_clean[spend], alpha0.6, labelClean Data, s50) plt.scatter(df.loc[[148, 149], time_spent], df.loc[[148, 149], spend], colorred, markerx, s200, labelOutliers, linewidths3) # 绘制三条回归线 x_range np.linspace(df[time_spent].min(), df[time_spent].max(), 100) plt.plot(x_range, results_raw.params[0] results_raw.params[1] * x_range, k--, labelOLS (With Outliers), linewidth2) plt.plot(x_range, results_clean.params[0] results_clean.params[1] * x_range, b-, labelOLS (Clean), linewidth3) plt.plot(x_range, beta0_huber beta1_huber * x_range, g-., labelHuber Regressor, linewidth2.5) plt.xlabel(Time Spent (min)) plt.ylabel(Spend (CNY)) plt.title(Comparison of Regression Lines: Impact of Outliers and Robust Methods) plt.legend() plt.grid(True) plt.show()通过对比你会发现包含异常值的OLS线黑色虚线斜率被严重高估因为它极力想去“靠近”那两个异常高点。清理后的OLS线蓝色实线更合理地反映了主体数据的趋势。Huber回归线绿色点划线即使在不剔除异常值的情况下也能给出一个相对稳健的估计受异常值影响较小。实操心得处理异常值是建模中的关键一步。盲目删除或保留都不可取。我的经验是1) 结合业务判断异常值成因2) 对比处理前后模型的变化3) 考虑使用稳健回归方法作为补充或替代。Huber回归、RANSAC等都是很好的工具。5. 常见问题与排查技巧实录在实际应用中你会遇到各种各样的问题。下面我整理了一份“踩坑实录”希望能帮你少走弯路。5.1 共线性当自变量“抱团取暖”假设我们想预测房价同时使用了“房屋面积平方米”和“房间数”作为自变量。通常面积越大房间数可能也越多这两个变量是相关的。如果相关性极高就会导致共线性。症状模型的整体R²可能很高F检验显著。但单个自变量的回归系数变得非常不稳健标准误巨大t检验不显著p值很大甚至系数的符号可能与常识相反。在statsmodels的summary中如果看到条件数Cond. No.非常大例如1000就是强烈的警告信号。诊断计算方差膨胀因子VIF大于10通常被认为存在严重共线性。from statsmodels.stats.outliers_influence import variance_inflation_factor # 假设X是包含常数项的设计矩阵 vifs [variance_inflation_factor(X.values, i) for i in range(X.shape[1])] print(dict(zip(X.columns, vifs)))查看相关系数矩阵df.corr()寻找高度相关的自变量对。解决剔除变量从高度相关的变量中根据业务知识保留一个。主成分回归将相关变量转换为一组不相关的主成分然后用主成分做回归。岭回归或Lasso回归在损失函数中加入对系数大小的惩罚项可以稳定估计但系数会“收缩”解释性变差。5.2 异方差性误差在“变胖”或“变瘦”在残差图中如果残差随拟合值增大而呈现明显的扩散或收敛 pattern就是异方差。症状残差图呈现漏斗形、扇形或其它系统性形状。参数估计依然无偏但标准误的估计不再有效导致t检验和F检验不可靠。诊断目视检查残差vs拟合值图。进行统计检验如Breusch-Pagan检验或White检验。解决变换因变量对y进行对数变换、平方根变换等常能稳定方差。使用加权最小二乘法为不同观测值赋予不同的权重方差大的点权重小。使用稳健标准误许多统计软件如statsmodels的fit(cov_typeHC3)可以提供对异方差稳健的标准误估计这样你就不必改变模型只需修正推断。5.3 模型过简与过繁在欠拟合与过拟合间走钢丝欠拟合模型太简单例如用直线去拟合明显是曲线的数据。症状R²很低残差图显示出明显的非线性 pattern。过拟合模型太复杂包含了太多无关变量或高阶项不仅拟合了信号还拟合了噪声。症状在训练集上R²很高但在新数据测试集上表现很差。调整后R²可能比R²低很多。解决策略对付欠拟合考虑增加自变量的高阶项如x²、交互项或使用更复杂的模型如多项式回归、样条回归。对付过拟合特征选择使用逐步回归、LASSO回归等方法自动选择重要变量。正则化使用岭回归或LASSO回归在损失函数中加入惩罚项约束系数大小。交叉验证始终在独立的测试集或通过交叉验证来评估模型的泛化能力而不是只看训练集表现。5.4 一个综合排查清单当你得到一个不满意的回归结果时可以按以下顺序排查问题现象可能原因诊断方法解决思路R² 很低模型不显著1. 变量间确实无线性关系2. 存在重要变量未被纳入3. 数据存在大量噪声1. 绘制散点图矩阵2. 检查残差图是否有模式3. 领域知识判断1. 寻找新的预测变量2. 考虑非线性变换或模型3. 清洗数据处理异常值单个变量系数不显著1. 该变量确实无关2. 存在共线性3. 样本量不足1. 计算VIF2. 检查该变量与y的单独相关性1. 剔除高共线性变量2. 增加样本量3. 使用岭回归系数符号与预期相反1. 共线性最常见2. 遗漏重要变量3. 存在异常值或强影响点1. 计算VIF2. 绘制部分回归图3. 计算Cook距离诊断强影响点1. 处理共线性2. 检查并处理异常点3. 引入遗漏变量残差图显示非线性模型形式错误关系非线性观察残差vs拟合值图或成分残差图对变量进行变换如对数、平方或添加多项式项、使用非线性模型预测新数据误差大过拟合比较训练集和测试集的性能如R²使用正则化、简化模型、增加训练数据最后我想分享一点个人体会线性最小二乘就像一把瑞士军刀简单、强大、无处不在。但越是简单的工具越需要使用者深刻理解其前提和局限。不要把它当成一个黑箱输入数据输出结果就完事。每一次拟合都应该伴随着对数据的审视、对假设的检验、对结果的质疑。模型诊断的图表往往比那个光鲜的R²数值更有价值。它能告诉你故事的另一面——你的模型在哪里挣扎数据在哪里说谎。真正理解这些你才能从“会用工具”进阶到“能解决问题”。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门