曲线拟合的数学本质与工程实现:从理论到代码的一体化实践
在实际业务场景中,常面临数据规律不明确的问题。需要构建简洁的数学模型去逼近复杂的现实。多项式拟合是这个过程最基础也最关键的工具之一。
多项式建模:不只是个公式,而是对自由度的掌控
为什么要用多项式?因为它'看起来非线性',但'算起来却是线性的'。
假设我们要拟合的数据满足这样一个关系:
$$ f(x) = a_0 + a_1 x + a_2 x^2 + \cdots + a_n x^n $$
这个函数整体上看当然是非线性的。可注意!它对参数 $\mathbf{a} = [a_0, a_1, …, a_n]^T$ 的依赖却是完全线性的。
范德蒙矩阵:把离散数据变成代数语言
构造所谓的 范德蒙矩阵(Vandermonde Matrix) 。
$$ \mathbf{X} = \begin{bmatrix} 1 & x_1 & x_1^2 & \cdots & x_1^n \ 1 & x_2 & x_2^2 & \cdots & x_2^n \ \vdots & \vdots & \vdots & \ddots & \vdots \ 1 & x_m & x_m^2 & \cdots & x_m^n \ \end{bmatrix} $$
每一行对应一个数据点,每一列代表一个幂次项。
std::vector<std::vector<double>> buildVandermonde(const std::vector<double>& x, int degree) {
int m = x.size();
int n = degree + 1;
std::vector<std::vector<double>> X(m, std::vector<double>(n));
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
X[i][j] = std::pow(x[i], j);
}
}
return X;
}
当 $x_i$ 比较大时,高阶项可能导致矩阵元素数量级差异巨大,称为'病态矩阵'。解决办法是归一化先行。
graph TD
A[原始数据点 xi, yi] --> B{是否需要预处理?}
B -->|是 | C[归一化/去噪]
B -->|否 | D[直接构造矩阵]
C --> D
D --> E[初始化空矩阵 X]
E --> F[遍历每个 xi]
F --> G[计算 1, xi, xi², ..., xin]
G --> H[填入矩阵第i行]
H --> I{是否所有点处理完毕?}
I -->|否 | F
I -->|是 | J[输出范德蒙矩阵 X]
阶数选择的艺术:偏差 - 方差的永恒博弈
现实中更常见的情况是:阶数越高,训练误差越低,但预测能力反而下降。
| 模型类型 | 偏差 | 方差 | 表现 |
|---|

