☰
最小二乘法全解:从线性拟合到传感器标定的工程实战指南
2026/10/15 11:38:26 网站建设 项目流程

1. 从一根拟合线说起:为什么工程师都得会最小二乘法

如果你做过传感器标定、做过数据拟合、做过曲线预测,那你大概率已经用过最小二乘法,只是可能没意识到它的名字。我第一次真正“认识”它,是在处理一个压力传感器的标定数据时——传感器输出的电压值和真实压力之间看着像线性关系,但又不是严格的一条直线,几十个采样点散在那里,凭肉眼画线怎么画都觉得不踏实。后来前辈甩了一句“用最小二乘拟合一下”,才打开了这扇门。

最小二乘法(Least Squares Method)说白了就是干一件事:**给定一堆散点,找一条曲线(通常先假设是直线或多项式),让这条曲线和所有点的“误差平方和”最小。**它之所以叫“最小二乘”,是因为我们衡量误差用的是“残差的平方”而不是直接加残差,“二乘”就是平方的意思。为什么用平方不用绝对值?因为平方对大误差更敏感,能逼着拟合结果照顾到每一个偏离的点,而且平方和函数的光滑性好,可以直接求导找极值,数学上特别好处理。

这篇文章我打算用工程师的视角,把它从定义、推导、矩阵形式、代码实现到抗噪处理全部过一遍,不堆公式吓人,而是把每一步“为什么这么做”讲透。无论你是做嵌入式、做算法、做数据分析,还是准备面试被问到“最小二乘的原理”,这篇都值得花二十分钟读完。

2. 最小二乘法的直觉与核心思想

2.1 先从“误差平方和”这个选择说起

我们拿到一组数据点 \((x_1, y_1), (x_2, y_2), …, (x_n, y_n)\),想找一个函数 \(f(x)\) 来描述它们的趋势。最自然的想法是让每个点都落在函数上,但现实世界充满噪声,不可能全部落在。那就退一步:让整体偏差最小。

先定义残差:

\[ r_i = y_i - f(x_i) \]

如果把所有 \(r_i\) 直接相加,正负残差会互相抵消——比如一个点偏上 5,一个点偏下 5,相加得 0,看起来模型“完美无缺”,实际上一塌糊涂。平方之后就不一样了:\((-5)^2 = 25\),是正的,会真实地反映偏差程度。

为什么不用绝对值?绝对值虽然也能避免抵消,但 \(|r|\) 在 \(r=0\) 处不可导,求极值的时候麻烦;而且绝对值给大误差和小误差的权重是线性的,不会特别惩罚那些离群点。平方则是“按误差的平方放大惩罚”,误差大一点点,损失就大很多,这会驱动拟合曲线往所有点的“重心”靠拢。

工程实践里我个人的体会是:平方误差适合噪声接近正态分布的场景(传感器数据大多如此),如果数据里混入了大量粗大误差,后面必须引入抗差手段,这个放到第 5 章细说。

2.2 三张图看懂拟合的本质

第一张图:所有数据点画出来,像一条有厚度的“带子”斜着上升。拟合就是在带子中间画一条线,让它到带子上下边缘的距离尽量均衡。

第二张图:把残差画出来,每个点到直线的垂直距离(严格说是 y 方向距离)有长有短,最小二乘就是调整直线参数,让这些距离的平方和最小。

第三张图:把损失函数画出来——它是参数 \(a, b\) 的二元函数,形状像一个碗。我们做的就是找碗底。

图不重要,重要的是要建立起“拟合 = 优化损失函数”的思维框架。后面不管换成多项式、指数、还是复杂模型,框架不变,变的只是损失函数和求解方式。

3. 完整推导:从一元线性回归到矩阵通解

3.1 一元线性拟合的推导过程

先看最简单的直线拟合:\(y = ax + b\)。我们的目标是找到 \(a, b\),让损失函数

\[ J(a, b) = \sum_{i=1}^{n} (y_i - a x_i - b)^2 \]

最小。这是一个无约束优化问题,极值点必然满足偏导数为零:

\[ \frac{\partial J}{\partial a} = -2 \sum (y_i - a x_i - b) x_i = 0 \] \[ \frac{\partial J}{\partial b} = -2 \sum (y_i - a x_i - b) = 0 \]

展开后得到一个二元一次方程组:

\[ a \sum x_i^2 + b \sum x_i = \sum x_i y_i \] \[ a \sum x_i + b n = \sum y_i \]

解这个方程组就得到了经典公式:

\[ a = \frac{n \sum x_i y_i - \sum x_i \sum y_i}{n \sum x_i^2 - (\sum x_i)^2} \] \[ b = \frac{\sum y_i - a \sum x_i}{n} \]

很多课本直接给公式就结束了,但这里有一个工程师非常关心的点:分母 \(n \sum x_i^2 - (\sum x_i)^2\) 什么时候会出问题?当所有 \(x_i\) 都相同时,分母为零——数据没有变化,无法拟合出斜率;当 \(x_i\) 分布范围很窄时,分母很小,\(a\) 对微小噪声极度敏感。所以工程中做拟合之前,先看一眼 x 数据的方差,方差太小就别硬拟合,结果没有意义。

3.2 向量与矩阵视角:为什么拟合本质是投影

从一元到多元,手推偏导就有点烦了。这时候矩阵登场。把模型写成矩阵形式:

\[ \mathbf{y} = \mathbf{X} \mathbf{\beta} \]

其中 \(\mathbf{X}\) 是设计矩阵,每一行是样本的特征(第一列通常全 1,对应截距),\(\mathbf{\beta}\) 是待求参数向量。损失函数写为:

\[ J(\mathbf{\beta}) = (\mathbf{y} - \mathbf{X}\mathbf{\beta})^T (\mathbf{y} - \mathbf{X}\mathbf{\beta}) \]

对 \(\mathbf{\beta}\) 求导并令其为零,得到正规方程:

\[ \mathbf{X}^T \mathbf{X} \mathbf{\beta} = \mathbf{X}^T \mathbf{y} \]

所以:

\[ \mathbf{\beta} = (\mathbf{X}^T \mathbf{X})^{-1} \mathbf{X}^T \mathbf{y} \]

这就是最小二乘的矩阵通解。它一次性能搞定一元、多元、多项式(把 \(x^2, x^3\) 作为额外特征列加入 \(\mathbf{X}\) 即可)。

我们还可以换一个几何视角理解它:拟合的本质,是把观测向量 \(\mathbf{y}\) 投影到由 \(\mathbf{X}\) 的各列张成的线性子空间上。误差向量 \(\mathbf{y} - \mathbf{X}\mathbf{\beta}\) 与这个子空间正交,所以 \(\mathbf{X}^T (\mathbf{y} - \mathbf{X}\mathbf{\beta}) = 0\),也就是正规方程。我当年第一次看懂这个投影关系时,有种通了电的感觉——最小二乘不是“发明”出来的公式,而是几何里“点到子空间最短距离就是垂线段”的直接推论。

3.3 数值稳定性:正规方程不是万能的

矩阵通解看起来漂亮,但工程时直接用 \((\mathbf{X}^T \mathbf{X})^{-1}\) 有隐患。当 \(\mathbf{X}\) 的各列接近线性相关时(比如多项式拟合次数过高、特征高度共线),\(\mathbf{X}^T \mathbf{X}\) 会接近奇异,求逆时数值误差被急剧放大。

我踩过的坑是:用 \(x, x^2, x^3\) 拟合一组数据,次数放到 8 的时候,用正规方程直接算,系数已经出现几十万的绝对值,画出来倒是能过每个点,但预测新数据完全飞掉。后来换成 QR 分解或 SVD 求解,才稳定住。

数值方法选择建议看这张表:

求解方式适用场景稳定性备注
正规方程直接求逆特征少、不共线、数据量小一般实现最简单,适合教学理解
QR 分解大多数常规拟合任务较好工程首选,内存占用适中
SVD 分解强共线、病态问题、秩亏最好最稳定,但计算量大些

实际用 Python 的 numpy 时,np.linalg.lstsq底层走的就是 SVD,这也是为什么我建议别自己写正规方程——内置函数已经替你做了数值稳定的处理。

4. 工程落地的标准姿势:numpy 一套带走

4.1 最少代码完成曲线拟合

工程里我基本不手写公式,直接用 numpy 一把梭。比如拟合一组一维数据的二次曲线:

import numpy as np x = np.array([0, 1, 2, 3, 4, 5]) y = np.array([1.2, 3.1, 5.8, 9.4, 14.3, 21.1]) # 构造设计矩阵:1, x, x^2 X = np.vstack([np.ones_like(x), x, x**2]).T # 最小二乘求解 coeff, residuals, rank, sv = np.linalg.lstsq(X, y, rcond=None) print(coeff) # [b, a, c] 对应 y = c*x^2 + a*x + b

这里有个容易犯的错:设计矩阵的列顺序决定了系数顺序。np.vstack([1, x, x^2]).T的结果是每行[1, xi, xi^2],所以coeff[0]是截距,coeff[1]是一次项,coeff[2]是二次项。如果顺序反了,后面做预测X @ coeff就对不上。

预测新点直接用矩阵乘法:

x_new = 6.0 y_new = np.array([1, x_new, x_new**2]) @ coeff print(y_new)

整个过程不超过十行。这也是最小二乘在工程中长盛不衰的原因——简单、快速、可解释。

4.2 多项式拟合的度:记忆还是趋势?

numpy 里有现成的np.polyfit,但我要提醒一句:次数越高不一定是好事。次数上去了,曲线会“调皮”地穿过每一个数据点,把噪声也当成趋势学进去——这是典型的过拟合。

我曾经拟合一条温度-电压曲线,20 个采样点,5 次多项式拟合的测试误差远小于 3 次,但拿到现场验证时,5 次曲线在中段出现了诡异的波浪,直接导致补偿后的精度比原来还差。后来学乖了:先用低次拟合画出曲线,肉眼判断残差是否还有明显结构,有结构再升次数。

一个经验法则:数据点数 n 与多项式最高次数 m 之间,至少要满足 n > 3m。数据点连次数的一半都不到时,任何高次拟合都是自欺欺人。

4.3 拟合质量怎么评估:别只看 R²

R²(决定系数)是大家最常用的指标,公式是:

\[ R^2 = 1 - \frac{\sum (y_i - \hat{y}_i)^2}{\sum (y_i - \bar{y})^2} \]

它衡量的是模型解释了总方差的比例。但工程中我从来不只是看 R²,而是必看残差图——横轴是 \(x\),纵轴是残差 \(y_i - \hat{y}_i\)。如果残差随机散布在 0 附近,说明模型结构正确;如果残差呈现明显的抛物线或周期形状,说明还有未被建模的规律,模型次数或形式该调整了。

这个习惯救过我很多次。有一次拟合电流-转速关系,R² 达到了 0.997,看着非常完美,但残差图出现明显 U 形,说明实际上该用二次项,线性模型虽然“大部分准”但系统性偏差会跟着转速变化,导致某一转速段误差超标。

5. 加权最小二乘:当数据不是“生而平等”的时候

5.1 为什么需要给数据加权

普通最小二乘假设每个数据点的噪声方差相同,所有点对拟合结果的“话语权”一样大。但工程现场经常不是这样:有的传感器在量程中段精度高,两端精度低;有的采样点是在强干扰下取的,可信度差。

这时候就要用加权最小二乘(Weighted Least Squares),损失函数变成:

\[ J(\mathbf{\beta}) = \sum_{i=1}^{n} w_i (y_i - \mathbf{x}_i^T \mathbf{\beta})^2 \]

权重 \(w_i\) 越大,该点对拟合结果的影响越大。矩阵解变成:

\[ \mathbf{\beta} = (\mathbf{X}^T \mathbf{W} \mathbf{X})^{-1} \mathbf{X}^T \mathbf{W} \mathbf{y} \]

其中 \(\mathbf{W}\) 是对角矩阵,对角元就是各个 \(w_i\)。

5.2 权重怎么定:两种实用策略

策略一:基于传感器精度。每个数据点对应一个测量不确定度 \(\sigma_i\),权重取 \(w_i = 1/\sigma_i^2\)。精度越高的点权重越大,这是统计上的最优做法。

策略二:基于残差迭代(鲁棒化)。先用普通最小二乘算一遍,得到残差;对残差大的点降低权重,再重新拟合;反复几次。这其实就是后面要讲的 IRLS(迭代加权最小二乘)的雏形。

一个工程细节:加权最小二乘里权重如果相差太大(比如差 100 倍以上),数值上要小心 \(\mathbf{X}^T \mathbf{W} \mathbf{X}\) 的条件数。如果出现奇异警告,先把权重归一化到 [0.1, 1] 区间再计算,可以有效缓解。

6. 抗离群点:RANSAC 与最小二乘的接力

6.1 最小二乘的软肋:一个离群点毁掉一切

最小二乘对高斯噪声很稳健,但对粗大误差(离群点)极其脆弱。因为平方放大了大残差的惩罚,一个偏离很远的坏点,会像“杠杆”一样把整条拟合线拉向自己——哪怕其他 99 个点都好好的。

我处理某设备位置标定时就遇到过:数据里混进一个因为通信丢包导致的大误差点,普通最小二乘拟合出来的斜率明显偏小,补偿后的系统精度直接超差。那之后,我把“先抗离群点,再执行最小二乘”写成了标准流程。

6.2 RANSAC 实操流程

RANSAC(随机抽样一致性算法)的思路特别工程化:不要试图一开始就把所有点拟合好,先找“最大共识”。

步骤拆开是这样的:

  1. 从数据里随机抽 2 个点(拟合直线所需最小点数),算出直线参数。
  2. 计算所有点到这条直线的距离,距离小于阈值的点记为“内点”。
  3. 统计内点数量;重复步骤 1-2 若干次(比如 100-200 次)。
  4. 内点最多的那次模型,作为最终候选。
  5. 用所有内点再跑一次普通最小二乘,得到最终模型。

代码思路:

import numpy as np from sklearn.linear_model import RANSACRegressor # 假设 X 是形状 (n,1) 的特征,y 是目标 ransac = RANSACRegressor(random_state=42) ransac.fit(X, y) inlier_mask = ransac.inlier_mask_ coeff = ransac.estimator_.coef_

RANSAC 的好坏很大程度上取决于阈值怎么设。阈值设太大,离群点混进内点集;阈值设太小,内点被白白丢弃。我的经验是先看数据的整体噪声水平:如果日常噪声是 ±0.5 个单位,阈值取 1.5-2 倍噪声作为“内点判定线”,效果比较靠谱。

6.3 什么时候不能用 RANSAC

RANSAC 不是银弹。当离群点比例超过 50% 时,随机抽样很难抽到“全是内点”的组合,结果会不稳定;数据量太大时,迭代次数要增加,实时性变差。

所以我现在的工作流是:离线标定类的任务,先用 RANSAC 或者基于残差 IRLS 清洗数据,再用加权最小二乘拟合;实时嵌入式环境下,则是通过中值滤波或限幅滤波在前端把离群点干掉,后端再用传统最小二乘。两条路互为备份,互相兜底。

7. 递推最小二乘:在线场景的实时更新姿势

7.1 为什么在线要用递推版本

很多工程场景不允许“等数据全攒齐再统一算一次”。比如电机参数在线辨识、飞行器姿态滤波、自适应控制系统,每来一个新数据,就要立刻更新模型参数。如果每次都把历史数据全部重算,数据量一大就扛不住。

递推最小二乘(Recursive Least Squares, RLS)解决的就是这个问题。它的更新公式长这样:

\[ \mathbf{K}{k} = \frac{\mathbf{P}{k-1} \mathbf{x}{k}}{\lambda + \mathbf{x}{k}^T \mathbf{P}{k-1} \mathbf{x}{k}} \] \[ \mathbf{\beta}{k} = \mathbf{\beta}{k-1} + \mathbf{K}{k} (y_k - \mathbf{x}{k}^T \mathbf{\beta}{k-1}) \] \[ \mathbf{P}{k} = \frac{1}{\lambda} (\mathbf{I} - \mathbf{K}{k} \mathbf{x}{k}^T) \mathbf{P}_{k-1} \]

光看公式容易懵,其实拆开就三件事:

  • \(\mathbf{K}_k\) 是“增益”,决定新数据修正老参数的多大力度;
  • \(y_k - \mathbf{x}k^T \mathbf{\beta}{k-1}\) 是“新息”,也就是新数据带来的预测误差;
  • \(\mathbf{P}_k\) 是协方差矩阵,跟踪当前参数估计的不确定性。

\(\lambda\) 是遗忘因子(0.95 - 1.0 之间)。\(\lambda = 1\) 时所有旧数据权重相同;\(\lambda < 1\) 时旧数据被指数衰减遗忘,让算法更“激动”,能跟随参数时变。系统参数本身变化剧烈,就把 \(\lambda\) 调小;系统稳定但噪声大,就把 \(\lambda\) 往 1 靠。

7.2 初值设置的两个实务细节

第一,\(\mathbf{\beta}_0\) 怎么给?没有先验信息就设全零向量。

第二,\(\mathbf{P}_0\) 怎么给?一般设成 \(\mathbf{P}_0 = c \mathbf{I}\),\(c\) 取大数(比如 100-1000)。为什么?\(c\) 越大,表示初始时对参数越没信心,前几个数据点会大步修正;\(c\) 太小,算法会“自信”地赖在初值附近不动,收敛慢。

我踩过的坑:在某个量产设备上做在线标定,初值 \(\mathbf{P}_0\) 设了个小值,结果参数一直没收敛到真实值附近,排查了一整天才发现是初始协方差给得太小,算法认为初始参数已经很准,拒绝接受新信息。

7.3 数值病态:必须加正则化的几种情况

说一个真实场景:拟合多项式次数较高时,设计矩阵 \(\mathbf{X}\) 的各列之间相关性很强,\(\mathbf{X}^T \mathbf{X}\) 接近奇异。此时直接求解会得到大得离谱的系数。解决办法是加正则化项,把损失函数改成:

\[ J(\mathbf{\beta}) = \|\mathbf{y} - \mathbf{X}\mathbf{\beta}\|^2 + \alpha \|\mathbf{\beta}\|^2 \]

这就是岭回归(Ridge Regression),解变成:

\[ \mathbf{\beta} = (\mathbf{X}^T \mathbf{X} + \alpha \mathbf{I})^{-1} \mathbf{X}^T \mathbf{y} \]

\(\alpha\) 取多大会影响拟合偏差:太小起不到稳定作用,太大曲线被压平。我一般用交叉验证选 \(\alpha\),范围从 1e-4 到 10 里挑一个。

8. 最小二乘在工程里的实战地图

8.1 传感器标定:最常见的应用

工程里最经典的使用方式就是传感器标定。比如采集温度传感器的 ADC 值和真实温度,标出线性关系 \(T = k \cdot ADC + b\)。实测时 ADC 有噪声,真实温度又有波动,直接取两点计算容易偏,最小二乘把所有样本一起用上,平均掉随机噪声。

实操时我建议手动记录至少 15 个数据点,覆盖传感器量程的 10%-90%,不要只测一两个点就拟合。曾经有同事只标定了 3 个点,结果中间段误差肉眼可见,复测后重标才恢复正常。

8.2 系统辨识与参数估计

在控制系统里,最小二乘用来估计模型参数。例如给系统输入一段激励信号,采集系统输出,基于假设的模型结构(一阶惯性、二阶振荡等)构造设计矩阵,然后估计传递函数参数。

这类应用里的关键点:输入激励要足够“丰富”。如果输入是一个恒定值,输出也基本恒定时,设计矩阵的列之间几乎线性相关,拟合出来的参数可信度极低。设计辨识实验时,输入信号要变化得足够充分,让系统各个动态特征都被激发出来,参数才可辨识。

8.3 数据预测与趋势分析

在设备维护领域,最小二乘用来做趋势预测:收集设备温升随时间的变化,拟合一个趋势线,外推判断什么时候可能过热。这类场景和曲线拟合本质一样,但要多一个心——外推范围越远,误差越大。我习惯在预测结果旁边标注“拟合残差的标准差”,提醒自己预测值的置信区间不是无限扩张的。

8.4 用数据说话:三类场景对照

场景模型假设主要坑点推荐工具
传感器线性标定\(y = kx + b\)采样点覆盖不全面np.linalg.lstsq
系统参数辨识已知模型结构,未知参数激励不够、数据共线RLS / 岭回归
离线数据趋势分析低次多项式过拟合、离群点RANSAC + 加权最小二乘

9. 我走过的弯路与防坑清单

9.1 五个容易被忽视的细节

第一,拟合前务必看一眼数据的量纲和数量级。如果 \(x\) 是数量级 1e6 的转速值,\(y\) 是量级 1 的温度值,设计矩阵里各列数量级差太多,数值求解精度会受影响。先做归一化或中心化,拟合完再换回原尺度。

第二,判断拟合好坏,一定要结合物理意义。某次拟合出了负的阻尼系数,数学上 R² 很高,但物理上完全说不通。如果参数明显违反物理规律,第一反应应是数据或模型结构有问题,而不是接受这个“好看”的拟合结果。

第三,离线拟合和在线更新要分开设计。离线可以用 RANSAC 清洗全局数据,在线必须考虑计算量与数值稳定性。最忌讳把离线算法直接搬到嵌入式定时中断里跑,算力和实时性都会出问题。

第四,矩阵维度认真核对。特征数 m 和数据点数 n 的关系搞反,np.linalg.lstsq也能算,但结果的语义完全错位。写代码前,先拿纸把 \(\mathbf{X}\) 的形状写清楚:(n 行,m 列)。

第五,正则化不是摆设。特征是 2 个还是 20 个,解法策略完全不同。特征多了以后,逐列检查相关性,相关系数超过 0.95 的两列,直接考虑合并或删除,比强行上正则化更省心。

9.2 取参速查表

参数推荐初始值调整方向
RANSAC 内点阈值2 倍噪声标准差内点太少就放大
遗忘因子 \(\lambda\)0.98参数时变大就调小
岭回归 \(\alpha\)1e-3系数发散就调大
初始协方差 \(\mathbf{P}_0\)100 I收敛太慢就调大
初始参数 \(\mathbf{\beta}_0\)零向量有先验就放先验

10. 写在最后的经验体会

最小二乘这个算法,门槛低到几天就能上手,但深度又大到够工程师钻研很久。我见过太多人拿到数据就直接np.polyfit(x, y, 3)把曲线画出来,根本不看设计矩阵、不看残差分布、不看离群点。短期看是省事,长期看是在给自己埋雷。工程和数学考试最大的区别就在这里:考试会告诉你哪道题用哪个公式,工程不会。数据不会主动告诉你它是线性还是二次、有没有离群点、噪声是否均匀,这些都是工程师自己要做出的判断。

我个人现在的最小二乘使用习惯,已经固定成一条流水线:先画散点图看趋势,再算残差判断模型结构,再用 RANSAC 或限幅清洗异常点,最后用加权最小二乘(或者 RLS)出最终结果。每一步都谈不上高深,但组合起来,就能应对现场绝大多数拟合需求。

如果你正准备在工作中用最小二乘,我的建议是别急着写代码。花十分钟把数据画出来,想想它背后代表什么物理过程,想想噪声从哪里来,再选择拟合策略。这样下来,踩坑的概率会小很多。下一期我想聊聊这一套思路如何推广到非线性回归和卡尔曼滤波上——毕竟工程算法永远不是孤立的一招一式,而是一套组合拳。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询