4. 線性回歸
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using System.Xml.Serialization.Configuration;
namespace Q4
{
public partial class Form1 : Form
{
string t;
bool ignore = false;
int len = -1;
List<PointF> dots = new List<PointF>();
public Form1()
{
InitializeComponent();
ignore = true;
textBox1.Text = "線性回歸(Linear Regression)\r\n";
textBox1.Text += "利用最小平方方法讓一條直線逼近一些點\r\n";
textBox1.Text += "請輸入資料總數: ";
ignore = false;
t = textBox1.Text;
draw();
}
double? M, B;
void draw()
{
var series = new Series("輸入資料");
series.ChartType = SeriesChartType.Point;
foreach (var item in dots)
{
var p = series.Points[series.Points.AddXY(item.X, item.Y)];
p.MarkerSize = 10;
p.MarkerStyle = MarkerStyle.Circle;
}
chart1.Series.Clear();
chart1.Series.Add(series);
if (M != null)
{
var line = new Series("逼近的直線");
line.ChartType = SeriesChartType.Line;
line.Points.AddXY(0, B);
double x = Math.Ceiling(dots.Max(e => e.X));
line.Points.AddXY(x, M * x + B);
line.BorderWidth= 3;
chart1.Series.Add(line);
}
}
private void Form1_Load(object sender, EventArgs e)
{
chart1.ChartAreas.First()
.AxisX.MajorGrid.LineDashStyle = ChartDashStyle.DashDot;
chart1.ChartAreas.First()
.AxisX.LabelStyle.Format = "0";
chart1.ChartAreas.First()
.AxisX.Title = "x";
chart1.ChartAreas.First()
.AxisY.MajorGrid.LineDashStyle = ChartDashStyle.DashDot;
chart1.ChartAreas.First()
.AxisY.LabelStyle.Format = "0";
chart1.ChartAreas.First()
.AxisY.Title = "y";
chart1.Titles.Add("線性回歸 - 最小平方逼近");
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
if (ignore) return;
if (textBox1.Text.Length < t.Length)
{
textBox1.Text = t;
textBox1.SelectionStart = textBox1.Text.Length;
return;
}
if (!textBox1.Text.EndsWith("\r\n"))
{
return;
}
var input = (textBox1.Text.Substring(t.Length, textBox1.Text.Length - t.Length - 2));
if (len == -1)
{
len = int.Parse(input);
}
else
{
var l = input.Replace("[", "").Replace("]", "").Split(' ').ToList();
var x = double.Parse(l[0]);
var y = double.Parse(l[1]);
dots.Add(new PointF(((float)x), ((float)y)));
len--;
}
if (len != -1 && len != 0)
{
ignore = true;
textBox1.Text += "請輸入每一點資料的x,y座標[x y]: ";
ignore = false;
t = textBox1.Text;
textBox1.SelectionStart = textBox1.Text.Length;
}
else if (len == 0)
{
var sumx = 0.0;
var sumy = 0.0;
var sumxy = 0.0;
var sumxx = 0.0;
var avgX = dots.Average(d => d.X);
var avgY = dots.Average(d => d.Y);
foreach (var item in dots)
{
sumxx += item.X * item.X;
sumxy += item.X * item.Y;
sumx += item.X;
sumy += item.Y;
}
var m = M = (sumxy - sumx * avgY) / (sumxx - sumx * avgX);
var b = B = avgY - m * avgX;
ignore = true;
textBox1.Text += "最小平方直線的回歸係數: \r\n";
textBox1.Text += $" 斜率 (m) \t= \t{m:f3}\r\n";
textBox1.Text += $" 截距 (b) \t= \t{b:f3}\r\n";
textBox1.Text += "總資料點數 \t= \t" + dots.Count;
draw();
}
}
}
}
Last updated