1. 最小二乘法与多项式拟合基础
在工程计算和数据分析领域,我们经常需要从一组离散的数据点中找出潜在的数学规律。最小二乘法(Least Squares Method)就是解决这类问题的经典数学工具,它通过最小化误差平方和来寻找数据的最佳函数匹配。
多项式拟合是其中最常见的应用场景之一。假设我们有一组n个数据点(xi, yi),想要找到一个m次多项式:
y = a₀ + a₁x + a₂x² + ... + aₘxᵐ
使得这个多项式在所有数据点上的总误差最小。这里的"误差"定义为预测值与实际值的差的平方,最小二乘法的目标就是找到一组系数a₀, a₁,...,aₘ,使得所有数据点的误差平方和最小。
注意:多项式次数m的选择需要谨慎,m过小会导致欠拟合,m过大会导致过拟合。通常m不超过数据点数量n-1。
在C++中实现这一算法,我们需要解决三个核心问题:
- 如何构建正规方程组(Normal Equations)
- 如何求解线性方程组
- 如何评估拟合质量
2. 构建正规方程组
最小二乘法的核心是建立并求解正规方程组。对于m次多项式拟合,我们需要解以下矩阵方程:
XᵀXa = Xᵀy
其中:
- X是范德蒙德矩阵(Vandermonde matrix),其第i行第j列元素为xᵢʲ⁻¹
- y是观测值向量
- a是待求的系数向量(a₀,a₁,...,aₘ)
在C++中,我们可以这样构建X矩阵:
cpp复制#include <vector>
#include <cmath>
std::vector<std::vector<double>> buildVandermonde(
const std::vector<double>& x, int degree) {
std::vector<std::vector<double>> matrix;
for (size_t i = 0; i < x.size(); ++i) {
std::vector<double> row;
for (int j = 0; j <= degree; ++j) {
row.push_back(pow(x[i], j));
}
matrix.push_back(row);
}
return matrix;
}
构建XᵀX和Xᵀy的代码实现:
cpp复制void buildNormalEquations(
const std::vector<std::vector<double>>& X,
const std::vector<double>& y,
std::vector<std::vector<double>>& XtX,
std::vector<double>& Xty) {
int cols = X[0].size();
XtX.assign(cols, std::vector<double>(cols, 0.0));
Xty.assign(cols, 0.0);
for (size_t i = 0; i < X.size(); ++i) {
for (int j = 0; j < cols; ++j) {
for (int k = 0; k < cols; ++k) {
XtX[j][k] += X[i][j] * X[i][k];
}
Xty[j] += X[i][j] * y[i];
}
}
}
3. 求解线性方程组
得到正规方程组后,我们需要解这个线性方程组。在C++中,我们可以使用多种方法:
3.1 高斯消元法
高斯消元法是解线性方程组的经典方法。以下是实现代码:
cpp复制#include <stdexcept>
void g
