C#中的非线性回归

我正在寻找一种基于2D数据集生成非线性(最好是二次)曲线的方法,用于预测目的。 现在我正在使用我自己的普通最小二乘(OLS)实现来产生线性趋势,但我的趋势更适合曲线模型。 我正在分析的数据是系统负载随着时间的推移。

这是我用来生成线性系数的等式:

普通最小二乘(OLS)公式

我已经看过Math.NET Numerics和其他一些库,但它们要么提供插值而不是回归 (这对我来说没用),或者代码不能以某种方式工作。

任何人都知道任何可以产生这种曲线系数的免费开源库或代码示例吗?

我使用了MathNet.Iridium版本,因为它与.NET 3.5和VS2008兼容。 该方法基于Vandermonde矩阵。 然后我创建了一个类来保存我的多项式回归

 using MathNet.Numerics.LinearAlgebra; public class PolynomialRegression { Vector x_data, y_data, coef; int order; public PolynomialRegression(Vector x_data, Vector y_data, int order) { if (x_data.Length != y_data.Length) { throw new IndexOutOfRangeException(); } this.x_data = x_data; this.y_data = y_data; this.order = order; int N = x_data.Length; Matrix A = new Matrix(N, order + 1); for (int i = 0; i < N; i++) { A.SetRowVector( VandermondeRow(x_data[i]) , i); } // Least Squares of |y=A(x)*c| // tr(A)*y = tr(A)*A*c // inv(tr(A)*A)*tr(A)*y = c Matrix At = Matrix.Transpose(A); Matrix y2 = new Matrix(y_data, N); coef = (At * A).Solve(At * y2).GetColumnVector(0); } Vector VandermondeRow(double x) { double[] row = new double[order + 1]; for (int i = 0; i <= order; i++) { row[i] = Math.Pow(x, i); } return new Vector(row); } public double Fit(double x) { return Vector.ScalarProduct( VandermondeRow(x) , coef); } public int Order { get { return order; } } public Vector Coefficients { get { return coef; } } public Vector XData { get { return x_data; } } public Vector YData { get { return y_data; } } } 

然后我像这样使用它:

 using MathNet.Numerics.LinearAlgebra; class Program { static void Main(string[] args) { Vector x_data = new Vector(new double[] { 0, 1, 2, 3, 4 }); Vector y_data = new Vector(new double[] { 1.0, 1.4, 1.6, 1.3, 0.9 }); var poly = new PolynomialRegression(x_data, y_data, 2); Console.WriteLine("{0,6}{1,9}", "x", "y"); for (int i = 0; i < 10; i++) { double x = (i * 0.5); double y = poly.Fit(x); Console.WriteLine("{0,6:F2}{1,9:F4}", x, y); } } } 

用输出计算[1,0.57,-0.15]系数:

  xy 0.00 1.0000 0.50 1.2475 1.00 1.4200 1.50 1.5175 2.00 1.5400 2.50 1.4875 3.00 1.3600 3.50 1.1575 4.00 0.8800 4.50 0.5275 

这与Wolfram Alpha的二次结果相符。 二次方程二次拟合

编辑1要获得所需的拟合,请尝试以下x_datay_data初始化:

 Matrix points = new Matrix( new double[,] { { 1, 82.96 }, { 2, 86.23 }, { 3, 87.09 }, { 4, 84.28 }, { 5, 83.69 }, { 6, 89.18 }, { 7, 85.71 }, { 8, 85.05 }, { 9, 85.58 }, { 10, 86.95 }, { 11, 87.95 }, { 12, 89.44 }, { 13, 93.47 } } ); Vector x_data = points.GetColumnVector(0); Vector y_data = points.GetColumnVector(1); 

产生以下系数(从最低功率到最高功率)

 Coef=[85.892,-0.5542,0.074990] xy 0.00 85.8920 1.00 85.4127 2.00 85.0835 3.00 84.9043 4.00 84.8750 5.00 84.9957 6.00 85.2664 7.00 85.6871 8.00 86.2577 9.00 86.9783 10.00 87.8490 11.00 88.8695 12.00 90.0401 13.00 91.3607 14.00 92.8312 

@ ja72代码非常好。 但我将它移植到Math.NET的当前版本(MathNet.Iridium现在不支持我的理解)并优化代码大小和性能(Math.Pow函数因为性能低而不能在我的解决方案中使用)。

 public class PolynomialRegression { private int _order; private Vector _coefs; public PolynomialRegression(DenseVector xData, DenseVector yData, int order) { _order = order; int n = xData.Count; var vandMatrix = new DenseMatrix(xData.Count, order + 1); for (int i = 0; i < n; i++) vandMatrix.SetRow(i, VandermondeRow(xData[i])); // var vandMatrixT = vandMatrix.Transpose(); // 1 variant: //_coefs = (vandMatrixT * vandMatrix).Inverse() * vandMatrixT * yData; // 2 variant: //_coefs = (vandMatrixT * vandMatrix).LU().Solve(vandMatrixT * yData); // 3 variant (most fast I think. Possible LU decomposion also can be replaced with one triangular matrix): _coefs = vandMatrix.TransposeThisAndMultiply(vandMatrix).LU().Solve(TransposeAndMult(vandMatrix, yData)); } private Vector VandermondeRow(double x) { double[] result = new double[_order + 1]; double mult = 1; for (int i = 0; i <= _order; i++) { result[i] = mult; mult *= x; } return new DenseVector(result); } private static DenseVector TransposeAndMult(Matrix m, Vector v) { var result = new DenseVector(m.ColumnCount); for (int j = 0; j < m.RowCount; j++) for (int i = 0; i < m.ColumnCount; i++) result[i] += m[j, i] * v[j]; return result; } public double Calculate(double x) { return VandermondeRow(x) * _coefs; } } 

它也可以在github:gist上找到 。

我不认为你想要非线性回归。 即使您使用二次函数,它仍然称为线性回归。 你想要的是多变量回归。 如果你想要二次方,你只需将ax平方项添加到因变量中。

我会看看http://mathforum.org/library/drmath/view/53796.html ,试着了解它是如何完成的。

然后这有一个很好的实现,我认为会帮助你。