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

news2024/9/21 20:36:19

最小二乘法介绍✨

最小二乘法(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,慢慢推导总是可以弄明白的(不感兴趣可以直接略过):

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最小二乘法推导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包:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

将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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1421696.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023年春秋杯网络安全联赛冬季赛_做题记录

可信计算 基于挑战码的双向认证1 可信计算赛题-双向认证挑战模式.docx 使用命令进行SSH登录上去 ssh player8.147.131.156 -p 18341 # 记得加上-p参数指定端口&#xff0c;不然默认的是22端口看见word文档的提示&#xff0c;先尝试一下 直接获得了flag1 web 魔术方…

public class和class的区别

不用public修饰的类 一个Java源文件中可以定义多个不用public修饰的class&#xff0c;且类名不用和java源文件名一致。public修饰的类可以没有。编译之后&#xff0c;一个class就会对应生成一个class字节码文件 对于用public修饰的类 如果一个类用了public修饰&#xff0c;那…

成功解决Error:AttributeError: module ‘numpy‘ has no attribute ‘long‘.

成功解决Error&#xff1a;AttributeError: module ‘numpy‘ has no attribute ‘long‘. &#x1f335;文章目录&#x1f335; &#x1f333;引言&#x1f333;&#x1f333;报错分析&#x1f333;&#x1f333;解决方案1&#xff1a;降低NumPy版本&#x1f333;&#x1f333…

Github 上传项目(个人令牌token)

1.点击 github头像 &#xff1a; setting -> Developer Settings -> Personal access tokens 2.在要上传的文件夹下运行以下命令&#xff1a; git init git commit -m "first commit" git branch -M main 利用以下命令模…

使用流服务器m7s对接gb28181

优&#xff1a;sip品牌兼容性比较好&#xff0c;大华&#xff0c;海康都稳定可以&#xff0c;srs的5.0 sip品牌兼容性大华没反应&#xff0c;akstream-sip 大华也有问题&#xff0c;wvp也还可以 缺&#xff1a;目前最新的4.7.4版本&#xff0c;&#xff0c;sip协议用udp正常&a…

IP 层转发分组的过程

目录 IP 层转发分组的过程 1.1 基于终点的转发 1.2 最长前缀匹配 转发表中的 2 种特殊的路由 主机路由 (host route) 默认路由 (default route) 路由器分组转发算法 1.3 使用二叉线索查找转发表 IP 层转发分组的过程 1.1 基于终点的转发 分组在互联网中是逐跳转发的。…

Angular组件(二) 分割面板ShrinkSplitter

Angular组件(二) 分割面板ShrinkSplitter 前言 在Angular组件(一) 分割面板ShrinkSplitter文章中我们实现了Splitter组件&#xff0c;后来在业务场景中发现在开关右侧容器和底部容器时&#xff0c;使用起来不方便&#xff0c;ngModel绑定的值始终是左侧容器和顶部容器的大小&…

电路分享 —— 单片机 1个IO口检测多路按键

一、设计要求 设计要求&#xff1a;因为单片机的IO口数量较少&#xff0c;要求使用1路IO口检测4路按键。 二、设计思路 设计思路&#xff1a;单片机的IO口数量较少的情况下&#xff0c;使用1路IO口检测4路按键&#xff0c;可以通过检测电压值来进行区分&#xff0c;即使用IO口…

如何纯前端实现文件下载

业务场景 有一个下载文件的功能&#xff0c;不引入后端资源&#xff0c;纯前端应该如何实现&#xff1f; 解决方案 在vue2或者vue3项目中&#xff0c;可以把文件放在 public 文件夹下&#xff0c;然后使用a标签进行文件下载。 如&#xff1a;我要下载的文件是模版.xlsx 。首…

STM32学习笔记二——STM32时钟源时钟树

目录 STM32芯片内部系统架构详细讲解&#xff1a; 1.芯片内部混乱电信号解决方案&#xff1a; 2.时钟树&#xff1a; 1.内部RC振荡器与外部晶振的选择 2. STM32 时钟源 3.STM32中几个与时钟相关的概念 4.时钟输出的使能及其流程 5.时钟设置的基本流程 时钟源——单片机…

应用下载页源码简洁高大尚下载单页

首先可以设置多个下载源 软件截图可以滚动 暗夜主题交换 图片都可以自定义配置 精美的页面会让你眼前一亮的 源代码学习资料&#xff1a;https://pan.baidu.com/s/1ulE9zde2XMs-6E7eF3D3kg?pwdfhxq 密码&#xff1a;123

1178:单词数

题目描述 统计一篇文章里不同单词的总数。 输入 有多组数据&#xff0c;每组一行&#xff0c;每组就是一篇小文章。每篇小文章都是由大小写字母和空格组成&#xff0c;没有标点符号&#xff0c;遇到#时表示输入结束。每篇文章的单词数小于1000&#xff0c;每个单词最多由30个…

系统分析师-22年-下午题目

系统分析师-22年-下午题目 更多软考知识请访问 https://ruankao.blog.csdn.net/ 试题一必答&#xff0c;二、三、四、五题中任选其中两题作答 试题一 (25分) 说明 某软件公司拟开发一套博客系统&#xff0c;要求能够向用户提供一个便捷发布自已心得&#xff0c;及时有效的…

Cmake编译Opencv3.3.1遇到有些文件无法下载的错误解决:

前言&#xff1a; 对于&#xff0c;opencv有些配置文件错误并未致命&#xff0c;所以&#xff0c;有错误也不影响后续的编译&#xff1a;但是&#xff0c;后引用如果要用&#xff0c;在回过头来还是要解决的。 问题表述&#xff1a; 比如&#xff0c;有些文件下载的错误&am…

穷游网酒店数据采集与可视化分析与实现

摘 要 穷游网酒店数据采集与可视化分析大屏的背景是为了满足用户对酒店数据的需求以及提供数据洞察和决策支持。随着旅游业的快速发展&#xff0c;人们对酒店信息的需求日益增加&#xff0c;而穷游网作为一家专注于旅游信息的网站&#xff0c;拥有丰富的酒店数据资源。 这个大…

JS基础 - 遍历对象方法(6种)

初始值&#xff1a; var obj {a: 1,b: 2,c: 3,d: 4,e: 5,}; 第一种&#xff1a;for in for (let key in obj) {console.log(key ":" obj[key]);} 第二种&#xff1a;Object.keys 获取key Object.keys(obj).forEach((key) > {console.log(key ":" …

【乳腺肿瘤诊断分类及预测】基于Elman神经网络

课题名称&#xff1a;基于Elman神经网络的乳腺肿瘤诊断分类及预测 版本日期&#xff1a;2023-05-15 运行方式: 直接运行Elman0501.m 文件即可 代码获取方式&#xff1a;私信博主或QQ&#xff1a;491052175 模型描述&#xff1a; 威斯康辛大学医学院经过多年的收集和整理&a…

关于TongWeb部署应用报错java.lang.NoSuchFieldError: REFLECTION (by liuhui)

关于TongWeb部署应用报错java.lang.NoSuchFieldError: REFLECTION &#xff08;by liuhui&#xff09; 关于TongWeb部署应用报错java.lang.NoSuchFieldError: REFLECTION 问题现象&#xff1a;xml解析对象工厂类错误导致解析失败 解决办法&#xff1a;增加配置参数问题解决 -…

学习鸿蒙基础(2)

arkts是声名式UI DevEcoStudio的右侧预览器可以预览。有个TT的图标可以看布局的大小。和html的布局浏览很像。 上图布局对应的代码&#xff1a; Entry //入口 Component struct Index {State message: string Hello Harmonyos //State 数据改变了也刷新的标签build() {Row()…

MATLAB知识点:MATLAB的文件管理

​讲解视频&#xff1a;可以在bilibili搜索《MATLAB教程新手入门篇——数学建模清风主讲》。​ MATLAB教程新手入门篇&#xff08;数学建模清风主讲&#xff0c;适合零基础同学观看&#xff09;_哔哩哔哩_bilibili 节选自第2章 上一章我们说过&#xff0c;MATLAB是一款非常强…