极客秀
搜索

基于C#的软件大杂烩(3.1)—— 线性拟合工具

前面人工智能导论(2)——基本算法程序编写——回归介绍了Python中使用线性拟合工具,我就想在C#中能不能做一个线性拟合工具,方便我们进行线性拟合。
界面布局和基础准备

我们简单的绘制一个窗体,其中可以进行选择数据,显示原始数据以及进行数据拟合。 其中的存放数据的容器使用的是DataGripView,其他的应该都很熟悉。
之前在设计串口示波器的时候,我们引入了MathNet数学库,本期我们也是利用MathNet库中的方法进行数据拟合。


using MathNet.Numerics.LinearAlgebra;using MathNet.Numerics.LinearAlgebra.Double;using MathNet.Numerics.LinearRegression;

导入我们的MathNet相关库(在NuGet中获取)
除此之外我们还需要安装其他的几个库,也在NuGet管理库中添加。 CsvHelper, EPPlus
这两个库可以帮助我们解析CSV文件和EXCEL文件。 功能编写


private void DataChoose_Click(object sender, EventArgs e){  using (OpenFileDialog openFileDialog = new OpenFileDialog())  {     openFileDialog.Filter = "CSV Files (*.csv)|*.csv|Excel Files (*.xls;*.xlsx)|*.xls;*.xlsx|All Files (*.*)|*.*";     DialogResult result = openFileDialog.ShowDialog();     if (result == DialogResult.OK)     {         string selectedFilePath = openFileDialog.FileName;         LoadDataFromSelectedFile(selectedFilePath);     }  }}

当我们点击按钮的时候,唤醒资源管理器,选择我们的CSV文件或者Excel文件,并且将文件路劲作为变量传递给
LoadDataFromSelectedFile函数。


private void LoadDataFromSelectedFile(string filePath)        {            try            {                DataTable dataTable = new DataTable();                //作为数据源                using (StreamReader sr = new StreamReader(filePath))                {                    string[] headers = sr.ReadLine().Split(',');                    foreach (string header in headers)                    {                        dataTable.Columns.Add(header);                    }  
                    while (!sr.EndOfStream)                    {                        string[] rows = sr.ReadLine().Split(',');                        DataRow dr = dataTable.NewRow();                        for (int i = 0; i < headers.Length; i++)                        {                            dr[i] = rows[i];//读取列                        }                        dataTable.Rows.Add(dr);                    }  
                }                 DataGridView.DataSource = dataTable;                foreach (DataGridViewColumn column in DataGridView.Columns)                {                    string columnHeader = column.HeaderText;                    XdataChoose.Items.Add(columnHeader);//添加头                    YDataChoose.Items.Add(columnHeader);//添加头                }            }            catch (Exception ex)            {                MessageBox.Show("数据错误: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);            }        }

在这个函数中,我们将标题头坐标添加到ComomBox控件上,之后方便我们选择数据。新建一个DataTable变量,这个变量作为数据源将数据文件中的行列送入,
之后把DataGripView绑定到数据源上,使得我们的数据可以显示出来。


private void DataShowInChart_Click(object sender, EventArgs e)        {            //检查数据是否选择            if (XdataChoose.SelectedItem == null || YDataChoose.SelectedItem == null)            {                MessageBox.Show("未选择数据", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);                return;            }  
            string xColumnName = XdataChoose.SelectedItem.ToString();            string yColumnName = YDataChoose.SelectedItem.ToString();  
           //获取标签索引            int xColumnIndex = -1;            foreach (DataGridViewColumn column in DataGridView.Columns)            {                if (column.HeaderText == xColumnName)                {                    xColumnIndex = column.Index;                    break;                }            }  
            int yColumnIndex = -1;            foreach (DataGridViewColumn column in DataGridView.Columns)            {                if (column.HeaderText == yColumnName)                {                    yColumnIndex = column.Index;                    break;                }            }  
                        if (xColumnIndex == -1 || yColumnIndex == -1)            {                MessageBox.Show("未找到数据", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);                return;            }  
            // 删除原来的曲线            DataChart.Series.Clear();  
                        Series series = new Series("原始数据");            series.ChartType = SeriesChartType.Point;   
                        foreach (DataGridViewRow row in DataGridView.Rows)            {                //检查不是空行                if (!row.IsNewRow)                {                                       double xValue = Convert.ToDouble(row.Cells[xColumnIndex].Value);                    double yValue = Convert.ToDouble(row.Cells[yColumnIndex].Value);  
                    series.Points.AddXY(xValue, yValue);                }            }            DataChart.Series.Add(series);  
            //设置标签            DataChart.ChartAreas[0].AxisX.Title = xColumnName;            DataChart.ChartAreas[0].AxisY.Title = yColumnName;        }

当我们点击数据显示按钮的时候,先检查我们的XY轴是否已经选择,如果没有选择我们则进行报错,并退出函数。
如果选择没有问题的话,我们就先检测数据是否有异常(这里应该添加更多的判断逻辑)之后根据我们选择的XY轴来将数据打印到Chart上作为原始数据。


        private void LineFit()        {            //检查数据是否已经选择            if (XdataChoose.SelectedItem == null || YDataChoose.SelectedItem == null)            {                MessageBox.Show("未选择数据", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);                return;            }  
            string xColumnName = XdataChoose.SelectedItem.ToString();        
            // 创建列表来存储数据            List<double> xData = new List<double>();            List<double> yData = new List<double>();  
            foreach (DataPoint point in DataChart.Series[0].Points)  //数据在第一个系列中            {                xData.Add(point.XValue);                yData.Add(point.YValues[0]);  // Y 值在第一个 Y 值中            }  
            var regression = MathNet.Numerics.Fit.Line(xData.ToArray(), yData.ToArray());  
            double slope = regression.Item2;//斜率            double intercept = regression.Item1;//截距            //打印拟合函数            Result.Text = $"y = {slope:F4}x + {intercept:F4}";            //遍历XData,将XData的数据代入拟合函数打印到DataChart上            Series fitSeries = new Series("拟合曲线");            fitSeries.ChartType = SeriesChartType.Line;            fitSeries.BorderWidth = 3;            //计算拟合曲线            foreach (double xValue in xData)            {                double yValue = slope * xValue + intercept;                fitSeries.Points.AddXY(xValue, yValue);            }            DataChart.Series.Add(fitSeries);        }

当我们点击拟合按钮,我们从波形图中获取各个点的数据保存到列表中,之后调用数学库中的线性拟合函数,将XY作为参数传入。
** 效果展示 ** regression 的两个成员item1和item2分别是截距和斜率,根据我们的截距和斜率来画出我们的线性拟合曲线。

1.转载请保留原文链接谢谢!
2.本站所有资源文章出自互联网收集整理,本站不参与制作,如果侵犯了您的合法权益,请联系本站我们会及时删除。
3.本站发布资源来源于互联网,可能存在水印或者引流等信息,请用户擦亮眼睛自行鉴别,做一个有主见和判断力的用户。
4.本站资源仅供研究、学习交流之用,若使用商业用途,请购买正版授权,否则产生的一切后果将由下载用户自行承担。
5.联系方式(#替换成@):pm#vimge.com

  相关内容