开发语言:C#
在实际项目中,经常需要用到直线拟合,比如已有一些数值,需要插值出一些离散点,本文利用常见的一元线性回归算法和最小二乘法拟合直线。
调用方法:
LineFitMethod.LinearFit(pionts, out a, out b);
double y1 = LineFitMethod.LinearVal(x, a, b);
dCorr1 = LineFitMethod.Corrcoef(DY.ToArray(), listY.ToArray());
(0<|Corr(X,Y)|<1 表示具有一定线性相关性,越接近1表示越线性相关)
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Drawing; namespace Method.Yosao{ /*=================================================== * 类名称: LineFitMethod * 类描述:直线拟合及相关系数计算 * 创建人: Yosao * 创建时间: 2020/6/6/星期六 11:49:28 * 修改人: * 修改时间: * 版本: @version 1.0 =====================================================*/ class LineFitMethod { /// <summary> /// 一元线性回归 最小平方算法 /// 将离散点拟合为 y = a x + b 型直线 /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="a"></param> /// <param name="b"></param> public static bool LinearFit(double[] x, double[] y, out double a, out double b) { double xsum = 0; double ysum = 0; double xysum = 0; double x2sum = 0; int size = x.Length; if (size < 2) { a = 0; b = 0; return false; } for (int i = 0; i < size; i++) { xsum = xsum + x[i]; ysum = ysum + y[i]; xysum = xysum + x[i] * y[i]; x2sum = x2sum + x[i] * x[i]; } a = (size * xysum - xsum * ysum) / (size * x2sum - xsum * xsum + 1e-10); b = (ysum - a * xsum) / size; return true; } /// <summary> /// 计算拟合后的值 /// </summary> /// <param name="x"></param> /// <param name="a"></param> /// <param name="b"></param> /// <param name="y"></param> public static void LinearVal(double[] x, double a, double b, double[] y) { for (int i = 0; i < x.Length; i++) { y[i] = a * x[i] + b; } } /// <summary> /// 计算拟合后的值 /// </summary> /// <param name="x"></param> /// <param name="a"></param> /// <param name="b"></param> /// <returns>y</returns> public static double LinearVal(double x, double a, double b) { return a * x + b; } /// <summary> /// 计算相关系数,线性相关性 /// l=线性相关 0<| Corr(X,Y)|<1的时候,说明两个随机变量具有一定程度的线性关系。越大线性相关性越强 /// </summary> /// <param name="y1"></param> /// <param name="y2"></param> /// <returns></returns> public static double Corrcoef(double[] y1, double[] y2) { double xy = 0, x = 0, y = 0, xsum = 0, ysum = 0; double corrc = 0; int m = y1.Length; for (int i = 0; i < m; i++) { xsum += y1[i]; ysum += y2[i]; } for (int i = 0; i < m; i++) { x = x + (m * y1[i] - xsum) * (m * y1[i] - xsum); y = y + (m * y2[i] - ysum) * (m * y2[i] - ysum); xy = xy + (m * y1[i] - xsum) * (m * y2[i] - ysum); } corrc = Math.Abs(xy) / (Math.Sqrt(x) * Math.Sqrt(y)); return corrc; } /// <summary> /// * 最小二乘法直线拟合(不是常见的一元线性回归算法) /// * 将离散点拟合为 a x + b y + c = 0 型直线 /// * 假设每个点的 X Y 坐标的误差都是符合 0 均值的正态分布的。 /// * 与一元线性回归算法的区别:一元线性回归算法假定 X 是无误差的,只有 Y 有误差。 /// * 最后将直线改写为 y = a x + b 形式 /// </summary> /// <param name="points"></param> /// <param name="a"></param> /// <param name="b"></param> /// <param name="c"></param> /// <returns></returns> public static bool LinearFit(List<PointF> points, out double a, out double b) { double c = 0; int size = points.Count; if (size < 2) { a = 0; b = 0; c = 0; return false; } double x_mean = 0; double y_mean = 0; for (int i = 0; i < size; i++) { x_mean += points[i].X; y_mean += points[i].Y; } x_mean /= size; y_mean /= size; //至此,计算出了 x y 的均值 double Dxx = 0, Dxy = 0, Dyy = 0; for (int i = 0; i < size; i++) { Dxx += (points[i].X - x_mean) * (points[i].X - x_mean); Dxy += (points[i].X - x_mean) * (points[i].Y - y_mean); Dyy += (points[i].Y - y_mean) * (points[i].Y - y_mean); } double lambda = ((Dxx + Dyy) - Math.Sqrt((Dxx - Dyy) * (Dxx - Dyy) + 4 * Dxy * Dxy)) / 2.0; double den = Math.Sqrt(Dxy * Dxy + (lambda - Dxx) * (lambda - Dxx)); a = Dxy / den; b = (lambda - Dxx) / den; c = -a * x_mean - b * y_mean; //将参数由 a x + b y + c = 0转换为y = a x + b if (b != 0) { a = - a / b; b = - c / b; } else { //直线方程则为x=c/a; return false; } return true; } }}
欢迎关注@机器视角,我们将结合机器视觉技术、RPA技术、机器人技术,和大家一起讨论工业人工智能的新技术新方法。同时也会不定期给大家推荐分析一些好用的工具、产品和代码。
本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:dandanxi6@qq.com