小張 发表于 2024-1-20 14:20:52

用C#实现最小二乘法(用OxyPlot绘图)✨

最小二乘法介绍✨

最小二乘法(Least Squares Method)是一种常见的数学优化技术,广泛应用于数据拟合、回归分析和参数估计等领域。其目标是通过最小化残差平方和来找到一组参数,使得模型预测值与观测值之间的差异最小化。
最小二乘法的原理✨

线性回归模型将因变量 (y) 与至少一个自变量 (x) 之间的关系建立为:

在 OLS 方法中,我们必须选择一个b1和b0的值,以便将 y 的实际值和拟合值之间的差值的平方和最小化。
平方和的公式如下:

我们可以把它看成是一个关于b1和b0的函数,分别对b1和b0求偏导,然后让偏导等于0,就可以得到最小平方和对应的b1和b0的值。
先说结果,斜率最后推导出来如下所示:

截距推导出来结果如下:

don't worry about that,慢慢推导总是可以弄明白的(不感兴趣可以直接略过):



用C#实现最小二乘法✨

创建数据点✨

首先创建想要拟合的数据点:
NDArray? x, y;x,y为全局变量。
 //使用NumSharp创建线性回归的数据集<br>  x = np.arange(0, 10, 0.2);<br>  y = 2 * x + 3 + np.random.normal(0, 3, x.size);使用到了NumSharp,需要为项目添加NumSharp包:

x = np.arange(0, 10, 0.2);的意思是x从0增加到10(不包含10),步长为0.2:

np.random.normal(0, 3, x.size);的意思是生成了一个均值为0,标准差为3,数量与x数组长度相同的正态分布随机数数组。这个数组被用作线性回归数据的噪声。
使用OxyPlot画散点图✨

OxyPlot是一个用于在.NET应用程序中创建数据可视化图表的开源图表库。它提供了丰富的功能和灵活性,使开发者能够轻松地在其应用程序中集成各种类型的图表,包括折线图、柱状图、饼图等。

添加OxyPlot.WindowsForms包:

将PlotView控件添加到窗体设计器上:

// 初始化散点图数据<br>var scatterSeries = new ScatterSeries<br>{<br>    MarkerType = MarkerType.Circle,<br>    MarkerSize = 5,<br>    MarkerFill = OxyColors.Blue<br>};表示标志为圆形,标志用蓝色填充,标志的大小为5。
 for (int i = 0; i < x.size; i++)<br>{<br>      scatterSeries.Points.Add(new ScatterPoint(x, y));<br>}添加数据点。
PlotModel? plotModel;将plotModel设置为全局变量。
// 创建 PlotModel<br> plotModel = new PlotModel()<br> {<br>     Title = "散点图"<br> };<br> plotModel.Series.Add(scatterSeries);<br>​<br> // 将 PlotModel 设置到 PlotView<br> plotView1.Model = plotModel;这样就成功绘制了散点图,效果如下所示:

使用最小二乘法拟合数据点✨

double a = 0;<br>double c = 0;<br>​<br>double x_mean = x?.mean();<br>double y_mean = y?.mean();<br>​<br>//计算a和c<br>for(int i = 0; i < x?.size; i++) <br>{<br>    a += (x - x_mean) * (y? - y_mean);<br>    c += (x - x_mean) * (x - x_mean);<br>}<br>​<br>//计算斜率和截距<br>double m = a / c;<br>double b = y_mean - m * x_mean;<br>​<br>//拟合的直线<br>var y2 = m * x + b;套用公式就可以,a表示上面斜率公式的上面那部分,c表示上面斜率公式的下面那部分。
double x_mean = x?.mean();<br>double y_mean = y?.mean();计算x与y的平均值。
使用OxyPlot画拟合出来的直线✨

//画这条直线         <br> var lineSeries = new LineSeries<br> {<br>     Points = { new DataPoint(x?, y2), new DataPoint(x?[-1], y2[-1]) },<br>     Color = OxyColors.Red<br> };<br>​<br> // 创建 PlotModel         <br> plotModel?.Series.Add(lineSeries);<br>​<br> // 为图表添加标题<br> if (plotModel != null)<br> {<br>     plotModel.Title = $"拟合的直线 y = {m:0.00}x + {b:0.00}";<br> }<br>​<br> // 刷新 PlotView<br> plotView1.InvalidatePlot(true); Points = { new DataPoint(x?, y2), new DataPoint(x?[-1], y2[-1]) },画直线只要添加两个点就好了x?, y2表示x和y的第一个点,x?[-1], y2[-1])表示x和y的最后一个点,使用了NumSharp的切片语法。
画出来的效果如下所示:

C#实现的全部代码:
using NumSharp;<br>using OxyPlot.Series;<br>using OxyPlot;<br>namespace OlsRegressionDemoUsingWinform<br>{<br>    public partial class Form1 : Form<br>  {<br>        NDArray? x, y;<br>        PlotModel? plotModel;<br>        public Form1()<br>      {<br>            InitializeComponent();<br>      }<br>​<br>        private void button1_Click(object sender, EventArgs e)<br>      {<br>            //使用NumSharp创建线性回归的数据集<br>            x = np.arange(0, 10, 0.2);<br>            y = 2 * x + 3 + np.random.normal(0, 3, x.size);<br>​<br>            // 初始化散点图数据<br>            var scatterSeries = new ScatterSeries<br>          {<br>                MarkerType = MarkerType.Circle,<br>                MarkerSize = 5,<br>                MarkerFill = OxyColors.Blue<br>          };<br>​<br>            for (int i = 0; i < x.size; i++)<br>          {<br>                scatterSeries.Points.Add(new ScatterPoint(x, y));<br>          }<br>​<br>            // 创建 PlotModel<br>            plotModel = new PlotModel()<br>          {<br>                Title = "散点图"<br>          };<br>            plotModel.Series.Add(scatterSeries);<br>​<br>            // 将 PlotModel 设置到 PlotView<br>            plotView1.Model = plotModel;<br>​<br>​<br>​<br>​<br>      }<br>​<br>        private void button2_Click(object sender, EventArgs e)<br>      {<br>            double a = 0;<br>            double c = 0;<br>​<br>            double x_mean = x?.mean();<br>            double y_mean = y?.mean();<br>​<br>            //计算a和c<br>            for(int i = 0; i < x?.size; i++) <br>          {<br>                a += (x - x_mean) * (y? - y_mean);<br>                c += (x - x_mean) * (x - x_mean);<br>          }<br>​<br>            //计算斜率和截距<br>            double m = a / c;<br>            double b = y_mean - m * x_mean;<br>​<br>            //拟合的直线<br>            var y2 = m * x + b;<br>​<br>            //画这条直线         <br>            var lineSeries = new LineSeries<br>          {<br>                Points = { new DataPoint(x?, y2), new DataPoint(x?[-1], y2[-1]) },<br>                Color = OxyColors.Red<br>          };<br>​<br>            // 创建 PlotModel         <br>            plotModel?.Series.Add(lineSeries);<br>​<br>            // 为图表添加标题<br>            if (plotModel != null)<br>          {<br>                plotModel.Title = $"拟合的直线 y = {m:0.00}x + {b:0.00}";<br>          }<br>           <br>            // 刷新 PlotView<br>            plotView1.InvalidatePlot(true);<br>​<br>      }<br>  }<br>}用Python实现最小二乘法✨

import numpy as np<br>import matplotlib.pyplot as plt<br>​<br># 用最小二乘法拟合 y = mx + b<br>​<br># 设置随机数种子以保证结果的可复现性<br>np.random.seed(0)<br>​<br># 生成一个在区间内均匀分布的100个数作为x<br>x = np.linspace(0, 10, 100)<br>​<br># 生成y,y = 2x + 噪声,其中噪声是):<br>   a += (x - x_mean) * (y - y_mean)<br>   c += (x - x_mean) ** 2<br>​<br># 计算斜率和截距<br>m = a / c<br>b = y_mean - m * x_mean<br>   <br># 画这条直线<br>y2 = m * x + b<br>plt.plot(x, y2, color='red')<br>​<br># 画数据点<br>plt.scatter(x, y)<br>plt.xlabel('x')<br>plt.ylabel('y')<br>plt.title(f'y = {m:.2f}x + {b:.2f}')<br>plt.show()运行效果如下所示:

总结✨

本文向大家介绍了最小二乘法以及公式推导的过程,并使用C#与Python进行实现。重点介绍了C#中是如何实现的,同时介绍了在C#中如何使用OxyPlot绘图。希望对你有所帮助。
参考✨

1、Understanding Ordinary Least Squares (OLS) Regression | Built In
2、Machine Learning Series-Linear Regression Ordinary Least Square Method - YouTube
 
来源:https://www.cnblogs.com/mingupupu/p/17976196
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 用C#实现最小二乘法(用OxyPlot绘图)✨