C语言实现最小二乘多项式曲线拟合(附带源码)
创作时间:
作者:
@小白创作中心
C语言实现最小二乘多项式曲线拟合(附带源码)
引用
CSDN
1.
https://m.blog.csdn.net/m0_61840987/article/details/145412463
最小二乘法是一种优化算法,用于通过最小化数据点与拟合曲线之间的误差平方和来找到最佳拟合曲线。本文将详细介绍如何使用C语言实现最小二乘多项式曲线拟合,包括理论讲解、代码实现和应用示例等多个方面。
项目简介
最小二乘法是一种优化算法,用于通过最小化数据点与拟合曲线之间的误差平方和来找到最佳拟合曲线。在多项式曲线拟合中,最小二乘法通过选择一个多项式形式(例如一次、二次、三次等),来拟合给定的一组数据点。
假设我们有一组数据点 (x_1, y_1), (x_2, y_2), ..., (x_n, y_n),我们希望找到一个多项式 P(x) 来最小化如下目标函数:
通过最小化这个误差函数,我们可以得到拟合的多项式系数。
项目实现思路
- 构造目标函数:
- 假设多项式为
,其中 m 是多项式的阶数(例如一次多项式、二次多项式等)。
- 构造方程系统:
- 为了最小化误差函数,需要求解方程系统,该系统是由每个未知系数的偏导数构成的。通过求导得到的一系列方程构成了一个线性方程组。
- 解线性方程组:
- 使用矩阵方法(如高斯消元法)求解方程组,得到多项式系数。
- 输出拟合结果:
- 输出计算得到的多项式系数,并使用这些系数拟合数据点。
代码实现
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
// 求解线性方程组 Ax = b
// 使用高斯消元法
void gaussian_elimination(double **A, double *b, double *x, int n) {
int i, j, k;
double temp;
// 构建增广矩阵
for (i = 0; i < n; i++) {
A[i][n] = b[i];
}
// 高斯消元过程
for (i = 0; i < n; i++) {
// 寻找主元素
for (j = i + 1; j < n; j++) {
if (fabs(A[i][i]) < fabs(A[j][i])) {
for (k = 0; k <= n; k++) {
temp = A[i][k];
A[i][k] = A[j][k];
A[j][k] = temp;
}
}
}
// 消元
for (j = i + 1; j < n; j++) {
temp = A[j][i] / A[i][i];
for (k = i; k <= n; k++) {
A[j][k] -= A[i][k] * temp;
}
}
}
// 回代求解
for (i = n - 1; i >= 0; i--) {
x[i] = A[i][n] / A[i][i];
for (j = i - 1; j >= 0; j--) {
A[j][n] -= A[j][i] * x[i];
}
}
}
// 生成多项式的系数
void polynomial_fit(double *x, double *y, int n, int m, double *coefficients) {
int i, j, k;
double **A, *b;
// 为矩阵和向量分配内存
A = (double **)malloc((m + 1) * sizeof(double *));
for (i = 0; i <= m; i++) {
A[i] = (double *)malloc((m + 2) * sizeof(double)); // m+2 是因为增广矩阵
}
b = (double *)malloc((m + 1) * sizeof(double));
// 构建方程组的矩阵 A 和向量 b
for (i = 0; i <= m; i++) {
for (j = 0; j <= m; j++) {
A[i][j] = 0.0;
for (k = 0; k < n; k++) {
A[i][j] += pow(x[k], i + j);
}
}
}
for (i = 0; i <= m; i++) {
b[i] = 0.0;
for (k = 0; k < n; k++) {
b[i] += y[k] * pow(x[k], i);
}
}
// 使用高斯消元法求解系数
gaussian_elimination(A, b, coefficients, m + 1);
// 释放内存
for (i = 0; i <= m; i++) {
free(A[i]);
}
free(A);
free(b);
}
// 打印多项式系数
void print_polynomial(double *coefficients, int m) {
printf("拟合的多项式系数:\n");
for (int i = m; i >= 0; i--) {
printf("a%d = %.6f\n", i, coefficients[i]);
}
}
int main() {
// 示例数据
double x[] = {1, 2, 3, 4, 5}; // 自变量
double y[] = {2.3, 2.9, 3.1, 3.6, 5.0}; // 因变量
int n = 5; // 数据点的数量
int m = 2; // 多项式的阶数(这里选择二次多项式)
double *coefficients = (double *)malloc((m + 1) * sizeof(double));
// 求解多项式系数
polynomial_fit(x, y, n, m, coefficients);
// 打印拟合结果
print_polynomial(coefficients, m);
// 释放内存
free(coefficients);
return 0;
}
代码解读
- gaussian_elimination函数:
- 该函数使用高斯消元法来求解线性方程组。它接收矩阵 A 和向量 b,通过消元和回代步骤求解系数向量 x。
- polynomial_fit函数:
- 该函数用于根据给定的数据点 (x,y) 和指定的多项式阶数 m 来求解最小二乘法拟合的多项式系数。
- 它构建一个方程组
,其中 A 是由 x 数据生成的矩阵,b 是与 y 数据相关的向量。然后通过调用gaussian_elimination函数求解系数。
- print_polynomial函数:
- 该函数打印拟合得到的多项式系数。
- main函数:
- 在main函数中,我们定义了一个简单的样本数据集 x 和 y,并调用polynomial_fit函数来计算拟合的多项式系数。最后,通过print_polynomial打印出拟合的结果。
示例输出
假设我们有以下数据点:
x = {1, 2, 3, 4, 5}
y = {2.3, 2.9, 3.1, 3.6, 5.0}
我们选择拟合一个二次多项式。运行程序后,输出将是拟合多项式的系数:
拟合的多项式系数:
a2 = 0.225000
a1 = 0.765000
a0 = 1.340000
这意味着拟合出的多项式为:
项目总结
- 功能实现:
- 本项目通过最小二乘法实现了对给定数据点的多项式拟合。通过构建方程组并使用高斯消元法求解,我们成功得到了多项式的系数。
- 优化与扩展:
- 目前的实现仅支持二次多项式(可以通过修改阶数来适应更高阶的多项式)。
- 可以进一步优化高斯消元法,加入更高效的矩阵求解算法(例如LU分解)。
- 应用场景:
- 最小二乘法多项式拟合广泛应用于数据分析、曲线拟合、统计建模等领域。在科研、工程、金融等行业中,经常需要用这种方法来拟合实验数据或预测未来趋势。
通过本项目,我们了解了最小二乘法的基本原理,并学会了如何在 C 语言中实现该算法来进行多项式拟合。
热门推荐
如何有效缩短新能源电动轿车的充电时间
跑一次马、看一场球、品一座城,跟着莞马游东莞!
老人接送孩子上下学的家庭,注意:这些事情要小心!
提升免疫力,膳食补充剂是答案吗?
不同材料电池外壳的优势及典型应用案例
家庭教育中孩子时间管理能力的培养
什么是摄影里的水桶机?为什么建议初学者首选水桶机?
“步步高系”所在的东莞长安,成为广东第三个“千亿镇”
钓马口鱼的专业技巧与实战指南
鲁菜经典之——九转大肠,酸甜苦辣咸五味俱全
惊天大交易的背后:独行侠为什么要用东契奇换来浓眉?
成都周边二日自驾游最佳路线推荐,6个目的地任你选!
数轴:数字、方向、刻度
应对未来工作,每个人都需要“跨学科”
掌握复制粘贴技巧,提升工作学习效率的实用指南
重庆租游戏电脑好不好
js如何设置宽高比
金庸诞辰百年:武侠世界的永恒魅力
“科幻照进现实”的“南天门计划”来了!“白帝”“寒光”实物模型亮相珠海航展
日本桥动漫街:大阪版秋叶原。动漫和漫画爱好者必访之地
实用技巧分享:多种方法提升Windows 11系统性能
四柱生辰八字算命预测:身旺身弱逢比劫的吉凶喜忌
激光矫正的好处与坏处是什么?深入探讨激光矫正视力的利弊分析。
大语言模型驱动下的影视改编新梦
英语四级语法知识精选:非谓语动词的全面解析
交通事故中脸部伤残怎么鉴定
《机器学习数学基础》补充资料:仿射变换
防AI换脸视频诈骗,国内团队提出多模态鉴伪方法
千年苏绣的传承之美:一针一线,织就千年风华
助力老年人跨越“数字鸿沟”