首页 > 编程语言 >用C#实现最小二乘法(用OxyPlot绘图)✨

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

时间:2024-01-20 11:33:06浏览次数:35  
标签:OxyPlot C# double plotModel 绘图 np new y2 mean

最小二乘法介绍✨

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

最小二乘法的原理✨

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

image-20240118105946580

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

平方和的公式如下:

image-20240118110247858

我们可以把它看成是一个关于b1和b0的函数,分别对b1和b0求偏导,然后让偏导等于0,就可以得到最小平方和对应的b1和b0的值。

先说结果,斜率最后推导出来如下所示:

截距推导出来结果如下:

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

最小二乘法推导1

最小二乘法推导2

最小二乘法推导3

用C#实现最小二乘法✨

创建数据点✨

首先创建想要拟合的数据点:

 NDArray? x, y;

x,y为全局变量。

  //使用NumSharp创建线性回归的数据集
 x = np.arange(0, 10, 0.2);
 y = 2 * x + 3 + np.random.normal(0, 3, x.size);

使用到了NumSharp,需要为项目添加NumSharp包:

image-20240120100221733

 x = np.arange(0, 10, 0.2);

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

image-20240120100455351

np.random.normal(0, 3, x.size);

的意思是生成了一个均值为0,标准差为3,数量与x数组长度相同的正态分布随机数数组。这个数组被用作线性回归数据的噪声。

使用OxyPlot画散点图✨

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

image-20240120101110294

添加OxyPlot.WindowsForms包:

image-20240120101228438

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

image-20240120101340414

// 初始化散点图数据
var scatterSeries = new ScatterSeries
{
   MarkerType = MarkerType.Circle,
   MarkerSize = 5,
   MarkerFill = OxyColors.Blue
};

表示标志为圆形,标志用蓝色填充,标志的大小为5。

  for (int i = 0; i < x.size; i++)
{
     scatterSeries.Points.Add(new ScatterPoint(x[i], y[i]));
}

添加数据点。

 PlotModel? plotModel;

将plotModel设置为全局变量。

 // 创建 PlotModel
plotModel = new PlotModel()
{
    Title = "散点图"
};
plotModel.Series.Add(scatterSeries);

// 将 PlotModel 设置到 PlotView
plotView1.Model = plotModel;

这样就成功绘制了散点图,效果如下所示:

image-20240120102920929

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

double a = 0;
double c = 0;

double x_mean = x?.mean();
double y_mean = y?.mean();

//计算a和c
for(int i = 0; i < x?.size; i++)
{
   a += (x[i] - x_mean) * (y?[i] - y_mean);
   c += (x[i] - x_mean) * (x[i] - x_mean);
}

//计算斜率和截距
double m = a / c;
double b = y_mean - m * x_mean;

//拟合的直线
var y2 = m * x + b;

套用公式就可以,a表示上面斜率公式的上面那部分,c表示上面斜率公式的下面那部分。

double x_mean = x?.mean();
double y_mean = y?.mean();

计算x与y的平均值。

使用OxyPlot画拟合出来的直线✨

 //画这条直线         
var lineSeries = new LineSeries
{
    Points = { new DataPoint(x?[0], y2[0]), new DataPoint(x?[-1], y2[-1]) },
    Color = OxyColors.Red
};

// 创建 PlotModel        
plotModel?.Series.Add(lineSeries);

// 为图表添加标题
if (plotModel != null)
{
    plotModel.Title = $"拟合的直线 y = {m:0.00}x + {b:0.00}";
}

// 刷新 PlotView
plotView1.InvalidatePlot(true);
 Points = { new DataPoint(x?[0], y2[0]), new DataPoint(x?[-1], y2[-1]) },

画直线只要添加两个点就好了x?[0], y2[0]表示x和y的第一个点,x?[-1], y2[-1])表示x和y的最后一个点,使用了NumSharp的切片语法。

画出来的效果如下所示:

image-20240120103737259

C#实现的全部代码:

using NumSharp;
using OxyPlot.Series;
using OxyPlot;
namespace OlsRegressionDemoUsingWinform
{
   public partial class Form1 : Form
  {
       NDArray? x, y;
       PlotModel? plotModel;
       public Form1()
      {
           InitializeComponent();
      }

       private void button1_Click(object sender, EventArgs e)
      {
           //使用NumSharp创建线性回归的数据集
           x = np.arange(0, 10, 0.2);
           y = 2 * x + 3 + np.random.normal(0, 3, x.size);

           // 初始化散点图数据
           var scatterSeries = new ScatterSeries
          {
               MarkerType = MarkerType.Circle,
               MarkerSize = 5,
               MarkerFill = OxyColors.Blue
          };

           for (int i = 0; i < x.size; i++)
          {
               scatterSeries.Points.Add(new ScatterPoint(x[i], y[i]));
          }

           // 创建 PlotModel
           plotModel = new PlotModel()
          {
               Title = "散点图"
          };
           plotModel.Series.Add(scatterSeries);

           // 将 PlotModel 设置到 PlotView
           plotView1.Model = plotModel;




      }

       private void button2_Click(object sender, EventArgs e)
      {
           double a = 0;
           double c = 0;

           double x_mean = x?.mean();
           double y_mean = y?.mean();

           //计算a和c
           for(int i = 0; i < x?.size; i++)
          {
               a += (x[i] - x_mean) * (y?[i] - y_mean);
               c += (x[i] - x_mean) * (x[i] - x_mean);
          }

           //计算斜率和截距
           double m = a / c;
           double b = y_mean - m * x_mean;

           //拟合的直线
           var y2 = m * x + b;

           //画这条直线        
           var lineSeries = new LineSeries
          {
               Points = { new DataPoint(x?[0], y2[0]), new DataPoint(x?[-1], y2[-1]) },
               Color = OxyColors.Red
          };

           // 创建 PlotModel        
           plotModel?.Series.Add(lineSeries);

           // 为图表添加标题
           if (plotModel != null)
          {
               plotModel.Title = $"拟合的直线 y = {m:0.00}x + {b:0.00}";
          }
         
           // 刷新 PlotView
           plotView1.InvalidatePlot(true);

      }
  }
}

用Python实现最小二乘法✨

import numpy as np
import matplotlib.pyplot as plt

# 用最小二乘法拟合 y = mx + b

# 设置随机数种子以保证结果的可复现性
np.random.seed(0)

# 生成一个在[0, 10]区间内均匀分布的100个数作为x
x = np.linspace(0, 10, 100)

# 生成y,y = 2x + 噪声,其中噪声是[0, 10)之间的随机整数
y = 2 * x + 5 + np.random.randint(0, 10, size=100)

# 计算x和y的均值
x_mean = np.mean(x)
y_mean = np.mean(y)

a = 0
c = 0

for i in range(x.shape[0]):
  a += (x[i] - x_mean) * (y[i] - y_mean)
  c += (x[i] - x_mean) ** 2

# 计算斜率和截距
m = a / c
b = y_mean - m * x_mean
 
# 画这条直线
y2 = m * x + b
plt.plot(x, y2, color='red')

# 画数据点
plt.scatter(x, y)
plt.xlabel('x')
plt.ylabel('y')
plt.title(f'y = {m:.2f}x + {b:.2f}')
plt.show()

运行效果如下所示:

image-20240120104300224

总结✨

本文向大家介绍了最小二乘法以及公式推导的过程,并使用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

 

标签:OxyPlot,C#,double,plotModel,绘图,np,new,y2,mean
From: https://www.cnblogs.com/mingupupu/p/17976196

相关文章

  • 集成微软 Clarity 项目用户前端埋点
    ......
  • Android连接socket
    本文章主要是写Android作为客户端。Android客户端对于Android客户端,我们需要创建一个Socket对象,并指定服务器的IP地址和端口号。然后,使用Socket对象的connect()方法连接到服务器。连接成功后,可以使用Socket对象发送和接收数据。但其中一个比较重要的点是要使用到多线程,因为Andr......
  • CF1922B & C & D
    CF1922B分析注意到\(2^0+2^1<2^2\),因此若\(a_i\nea_j\nea_k\),这组数就是不合法的,所以题目转化为有多少对三元组\(i,j,k\)使得\(a_i,a_j,a_k\)中至少有两个数相等。考虑分类讨论。第一类,\(a_i,a_j,a_k\)中有两个数相等,不妨设\(a_i=a_j\),那么先开一个map维护所有\(a......
  • Educational Codeforces Round 161 (Rated for Div. 2)
    基本情况A犯病卡半小时。主要就是太着急,题目没有彻底分析清楚就开始想一些错误做法。C最优想法出来的慢。E比较好想。C.ClosestCitiesProblem-C-Codeforces就,显然是能走最近城市就走,不行就不走。一开始弄了一个自作聪明的预处理,但实际上每次查询还是\(\operatorn......
  • ClickHouse入门
    简介:ClickHouse是俄罗斯Yandex公司使用C++语言编写开源的列式存储数据库,主要用于在线分析查询(OLAP),使用SQL查询实时生成分析数据报告。一、安装 二、入门1. 特点A.列式存储:较MySQL行式存储有利于列的聚合、计数等操作,针对每列可选择最优的数据压缩算法来压缩......
  • Petrozavodsk Summer 2019. Day 9. MEX Foundation Contest【杂题】
    比赛链接A.TheOnePolynomialMan给定模数\(p\)和\(0\simp-1\)的两个集合\(U,V\),求有多少个有序对\((a,b)\)满足:\(f(a,b)=\prod\limits_{z\inV}\left(\frac{(2a+3b)^2+5a^2}{(3a+b)^2}+\frac{(2a+5b)^2+3b^2}{(3a+2b)^2}-z\right)\equiv0\pmo......
  • Final Cut Pro:打造专业品质的视频作品
    FinalCutPro是苹果公司开发的一款专业视频剪辑软件,被广泛应用于电影、电视和广告制作等领域。→→↓↓载FinalCutPro首先,FinalCutPro拥有直观且强大的界面,使得用户可以轻松地组织和编辑大量的视频素材。它支持多种格式的视频和音频文件,包括ProRes、RED、Canon、Panasonic......
  • leetcode 80
    题目描述删除有序数组中的重复项II给你一个有序数组nums,请你原地删除重复出现的元素,使得出现次数超过两次的元素只出现两次,返回删除后数组的新长度。不要使用额外的数组空间,你必须在原地修改输入数组并在使用O(1)额外空间的条件下完成。说明:为什么返回数值是整......
  • https速度慢解决办法(开启OCSP Stapling)
    网站通过certbot配置好之后,只要在末尾加两行即可。ssl_staplingon;ssl_stapling_verifyon;详细位置。server{listen443ssl;server_namexx.xx.com;indexindex.htmlindex.htmindex.jsp;ssl_certificateserver.pem;#证书的.cer文件路......
  • 冷泉港实验室 (The Cold Spring Harbor Laboratory)
    冷泉港实验室(TheColdSpringHarborLaboratory)又译为科尔德斯普林实验室,是一个非盈利的私人科学研究与教育中心,位于美国纽约州长岛上的冷泉港,此机构的研究对象包括癌症、神经生物学、植物遗传学、基因组学以及生物资讯学,其主要成就为分子生物学领域,在该研究所一共诞生了7......