C#中利用最小二乘法实现曲线拟合

一.说明

本文主要讲解利用最小二乘法解决曲线拟合的问题,并利用C#代码实现。重点在代码实现,原理简单介绍下,本文所有解释都以二次曲线举例


二.简单介绍最小二乘法原理

最小二乘法(又称最小平方法)是一种数学优化技术。它通过最小化误差的平方和寻找数据的最佳函数匹配。利用最小二乘法可以简便地求得未知的数据,并使得这些求得的数据与实际数据之间误差的平方和为最小。
在曲线拟合的应用场景中,相当于拟合的曲线后的方程利用给定x坐标计算出结果y1与给的y坐标的所有平方和最小即: ∑ i = 1 n [ y ( x i ) − y i ] 2 \sum_{i=1}^{n}[y(x_i)-y_i]^2 i=1n[y(xi)yi]2最小

最终转化对系数a1 a2 a3求偏导,多次迭代后算出估算值
偏导公式: ∂ Q / ∂ a j = 2 ∑ i = 1 n [ y ( x i ) − y i ] x j ∂Q/∂a_j = 2\sum_{i=1}^{n}[y(x_i)-y_i]x^j Q/aj=2i=1n[y(xi)yi]xj

1.对常数a3偏导: ∂ Q / ∂ a 3 = 2 ∑ i = 1 n [ ( a 1 x i 2 + a 2 x i + a 3 ) − y i ] = 0 ∂Q/∂a_3 = 2\sum_{i=1}^{n}[(a_1x_i^2+a_2x_i+a_3)-y_i]=0 Q/a3=2i=1n[(a1xi2+a2xi+a3)yi]=0

2.对一次系数a2偏导: ∂ Q / ∂ a 2 = 2 ∑ i = 1 n [ ( a 1 x i 2 + a 2 x i + a 3 ) − y i ] x = 0 ∂Q/∂a_2 = 2\sum_{i=1}^{n}[(a_1x_i^2+a_2x_i+a_3)-y_i]x=0 Q/a2=2i=1n[(a1xi2+a2xi+a3)yi]x=0

3.对二次系数a3偏导: ∂ Q / ∂ a 1 = 2 ∑ i = 1 n [ ( a 1 x i 2 + a 2 x i + a 3 ) − y i ] x 2 = 0 ∂Q/∂a_1 = 2\sum_{i=1}^{n}[(a_1x_i^2+a_2x_i+a_3)-y_i]x^2=0 Q/a1=2i=1n[(a1xi2+a2xi+a3)yi]x2=0

由此推导出
a 3 = ( ∑ i = 1 n y i − a 1 ∑ i = 1 n x i 2 − a 2 ∑ i = 1 n x i ) / n a3 = ( \sum_{i=1}^{n}y_i - a_1 \sum_{i=1}^{n}x_i^2-a_2 \sum_{i=1}^{n}x_i)/n a3=(i=1nyia1i=1nxi2a2i=1nxi)/n

a 2 = ( ∑ i = 1 n y i x i − a 3 ∑ i = 1 n x i − a 1 ∑ i = 1 n x i 3 ) / ∑ i = 1 n x i 2 a2 = ( \sum_{i=1}^{n}y_ix_i - a_3\sum_{i=1}^{n}x_i-a_1 \sum_{i=1}^{n}x_i^3)/ \sum_{i=1}^{n}x_i^2 a2=(i=1nyixia3i=1nxia1i=1nxi3)/i=1nxi2

a 1 = ( ∑ i = 1 n y i x i 2 − a 3 ∑ i = 1 n x i 2 − a 2 ∑ i = 1 n x i 3 ) / ∑ i = 1 n x i 4 a1 = ( \sum_{i=1}^{n}y_ix_i^2 - a_3 \sum_{i=1}^{n}x_i^2-a_2 \sum_{i=1}^{n}x_i^3)/\sum_{i=1}^{n}x_i^4 a1=(i=1nyixi2a3i=1nxi2a2i=1nxi3)/i=1nxi4


三.代码实现

代码中的a代表二次系数,b代表一次系数,c代表常数。
这里构造了x参数xarray[],y参数yarray[]进行演示,最终结果也与我们构造的参数基本一致。
这里的z1,z2,z3用来评估该次运算精度是否达到我们的预期值,值越小计算时间越久。

        var xarray = new double[100];
        var yarray = new double[100];

        for (int i = 0; i < xarray.Length; i++)
        {
            xarray[i] = i;
            yarray[i] = 1.356*i*i+7.969 * i - 0.26;
        }

        double a, b, c, m1, m2, m3, z1, z2, z3;
        a = b = c = 0;
        double sumx = 0, sumx2 = 0, sumx3 = 0, sumx4 = 0, sumy = 0, sumxy = 0, sumx2y = 0;
        for (var i = 0; i < xarray.Length; i++)
        {
            sumx += xarray[i];
            sumy += yarray[i];
            sumx2 += Math.Pow(xarray[i], 2);
            sumxy += xarray[i] * yarray[i];
            sumx3 += Math.Pow(xarray[i], 3);
            sumx2y += Math.Pow(xarray[i], 2) * yarray[i];
            sumx4 += Math.Pow(xarray[i], 4);
        }
        do
        {
            m1 = a;
            a = (sumx2y - sumx3 * b - sumx2 * c) / sumx4;
            z1 = (a - m1) * (a - m1);
            m2 = b;
            b = (sumxy - sumx * c - sumx3 * a) / sumx2;
            z2 = (b - m2) * (b - m2);
            m3 = c;
            c = (sumy - sumx2 * a - sumx * b) / xarray.Length;
            z3 = (c - m3) * (c - m3);
        } while (z1 > 1e-13 || z2 > 1e-13 || z3 > 1e-13);

        Debug.WriteLine($"a:{a} b;{b} c:{c}");
    }

四.其他方法

其他次数曲线同理,除了利用最小二乘法,还可以利用高斯牛顿方程求解,下一节介绍利用高斯牛顿方程及场景应用,各位大佬有其他更好的方法也可告知。

  • 23
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于使用C#实现最小二乘法进行曲线拟合,你可以按照以下步骤进行操作: 1. 首先,确定你想要拟合的曲线类型,例如直线、多项式等。假设你选择的是多项式曲线拟合。 2. 创建一个C#类,并添加一个方法来执行最小二乘法拟合。该方法将接受输入的数据点集合和拟合的阶数作为参数,并返回拟合结果。 3. 在最小二乘法拟合方法,首先计算数据点的总数以及自变量和因变量的和与平方和。 4. 接下来,根据拟合的阶数,构建一个系数矩阵和一个常数向量。系数矩阵的行数等于数据点的总数,列数等于拟合的阶数加1。 5. 使用数据点的自变量值和因变量值来填充系数矩阵和常数向量。每个元素的值等于自变量值的幂次方。 6. 利用最小二乘法的公式计算出系数矩阵的逆矩阵和最终的系数向量。 7. 最后,返回拟合的系数向量作为最小二乘法曲线拟合的结果。 这是一个简单的示例代码,用于执行多项式曲线拟合最小二乘法: ```csharp using System; using MathNet.Numerics.LinearAlgebra; public class LeastSquaresFitting { public static Vector<double> PolynomialFit(Vector<double> xData, Vector<double> yData, int order) { int n = xData.Count; int m = order + 1; Matrix<double> A = Matrix<double>.Build.Dense(n, m); Vector<double> b = Vector<double>.Build.Dense(n); for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { A[i, j] = Math.Pow(xData[i], j); } b[i] = yData[i]; } Matrix<double> ATransposeA = A.TransposeAndMultiply(A); Vector<double> ATransposeb = A.TransposeThisAndMultiply(b); Vector<double> coefficients = ATransposeA.Solve(ATransposeb); return coefficients; } } ``` 在这个示例,我们使用了MathNet.Numerics库来处理线性代数运算。你可以根据你的实际需求进行修改和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值