Es imprescindible comprender el código de forma correcta antes de utilizarlo a tu trabajo y si ttienes algo que aportar puedes dejarlo en la sección de comentarios.
Solución:
Usé la versión MathNet.Iridium porque es compatible con .NET 3.5 y VS2008. El método se basa en la matriz de Vandermonde. Luego creé una clase para contener mi regresión polinomial
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
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;
que luego lo uso así:
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,61,9", "x", "y");
for (int i = 0; i < 10; i++)
double x = (i * 0.5);
double y = poly.Fit(x);
Console.WriteLine("0,6:F21,9:F4", x, y);
Coeficientes calculados de [1,0.57,-0.15]
con la salida:
x y
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
Lo que coincide con los resultados cuadráticos de Wolfram Alpha.
Editar 1
Para obtener el ajuste que desea, intente la siguiente inicialización para x_data
y y_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);
que produce los siguientes coeficientes (de menor potencia a mayor)
Coef=[85.892,-0.5542,0.074990]
x y
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
El código @ ja72 es bastante bueno. Pero lo porté en la versión actual de Math.NET (MathNet.Iridium no es compatible por ahora, según tengo entendido) y optimicé el tamaño y el rendimiento del código (por ejemplo, Math.Pow
La función no se usa en mi solución debido a un rendimiento lento).
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++)
double v_j = v[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;
También está disponible en github:gist.
No creo que quieras una regresión no lineal. Incluso si está utilizando una función cuadrática, todavía se llama regresión lineal. Lo que quieres se llama regresión multivariada. Si desea una cuadrática, simplemente agregue un término cuadrático a sus variables dependientes.