2011-10-17 7 views
22

예측 가능한 목적으로 2D 데이터 세트를 기반으로 비선형 (바람직하게는 2 차 곡선)을 만드는 방법을 찾고 있습니다. 지금은 선형 추세를 생성하기 위해 보통 최소 제곱 (OLS)을 직접 구현했지만 내 경향은 곡선 모델에 훨씬 더 적합합니다. 분석중인 데이터는 시간이 지남에 따른 시스템 부하입니다. 여기 C#의 비선형 회귀

내가 내 선형 계수를 생산하기 위해 사용하고 방정식이다 : 나는 Math.NET 메릭스와 몇 가지 다른 libs와 봐 했어

Ordinary Least Squares (OLS) formula

,하지만 그들은 보간을 제공 중 대신 회귀 (나에게 유용하지 않음)이거나 코드가 어떤 방식 으로든 작동하지 않습니다.

무료 커브의 계수를 생성 할 수있는 무료 오픈 소스 라이브러리 나 코드 샘플을 아는 사람이 있습니까?

+0

정확하게 내가 찾은 결과입니다 : http://www3.wolframalpha.com/input/?i=quadratic+fit+%7B1%2C82.96%7D%2C%7B2%2C86.23%7D % 2C % 7B3 % 2C87.09 % 7D % 2C % 7B4 % 2C84.28 % 7D % 2C % 7B5 % 2C83.69 % 7D % 2C % 7B6 % 2C89.18 % 7D % 2C % 7B7 % 2C85.71 % 7D % 2C % 7B8 % 2C85.05 % 7D % 2C % 7B9 % 2C85.58 % 7D % 2C % 7B10 % 2C86.95 % 7D % 2C % 7B11 % 2C87.95 % 7D % 2C % 7B12 % 2C89.44 % 7D % 2C % 7B13 % 2C93.47 % 7D – Polynomial

+0

링크가있는 다른 q : http://stackoverflow.com/questions/882009/is-there-any-tool-for-regression-model 관련된 찾고있는 codeproject 것 : http : //www.codeproject.com/KB/recipes/QuadraticRegression.aspx – AakashM

+0

전자는 보간 모델에 대한 링크 집합이며, 후자는 'double'대신 'decimal'을 사용하도록 변환 한 후에도 사용하기 힘든 부정확 한 결과를 제공합니다. '. – Polynomial

답변

24

.NET 3.5 및 VS2008과 호환되므로 MathNet.Iridium 릴리스를 사용했습니다. 이 방법은 Vandermonde 행렬을 기반으로합니다. [1,0.57,-0.15]

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); 
     } 
    } 
} 

계산 된 계수를 출력 :

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 

일치 그럼 어떤

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; } } 
} 

그때 나는이 같이 사용할 내 다항식 회귀 개최하는 클래스를 생성 quadratic Wolfram Alpha의 결과입니다. Quadratic Equation Quadratic Fit

편집 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] 
    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 
+0

내 문제를 완벽하게 해결했습니다. 감사합니다 :) – Polynomial

+3

나는 당신의 대답을 최적화하고 업그레이드했습니다 :) http://stackoverflow.com/a/12770686/1046374 –

0

나는 어떻게 할 수 있는지에 대한 아이디어를 얻기 위해 http://mathforum.org/library/drmath/view/53796.html을 살펴볼 것입니다.

this에는 멋진 구현이있어 도움이 될 것으로 생각됩니다.

+0

그 구현은 나를 위해 작동하지 않았다. 그것은 완전히 잘못된 결과 (coeffs에 대해 0/1/0)를 배제하고 일부 조정 후에도 여전히 무의미했습니다. 이전에 발견 한 Wolfram Alpha 결과와 같은 것은 없습니다. 불행히도 당신이 제공 한 링크의 수학은 저 밖에 있습니다. – Polynomial

6

비선형 회귀를 원하지 않는다고 생각합니다. 2 차 함수를 사용하는 경우에도 여전히 선형 회귀라고합니다. 당신이 원하는 것은 다 변수 회귀라고합니다. 만약 당신이 2 차 방정식을 원한다면 당신은 단지 x 제곱 된 항을 당신의 종속 변수에 추가하십시오.

+0

선형 회귀는 나에게 줄을 준다. 나는 다른 것을하기 위해 게시 한 방정식을 편집하는 방법을 알지 못합니다. 나는 이런 종류의 결과를 얻고 싶다 : http://www3.wolframalpha.com/input/?i=quadratic+fit+%7B1%2C82.96%7D%2C%7B2%2C86.23%7D%2C%7B3% 2C87.09 % 7D % 2C % 7B4 % 2C84.28 % 7D % 2C % 7B5 % 2C83.69 % 7D % 2C % 7B6 % 2C89.18 % 7D % 2C % 7B7 % 2C85.71 % 7D % 2C % 7B8 % 2C85.05 % 7D % 2C % 7B9 % 2C85.58 % 7D % 2C % 7B10 % 2C86.95 % 7D % 2C % 7B11 % 2C87.95 % 7D % 2C % 7B12 % 2C89.44 % 7D % 2C % 7B13 % 2C93.47 % 7D – Polynomial

+0

http://luna.cas.usf.edu/~mbrannic/files/regression/Reg2IV.html – Tim

+0

수식을 사용하십시오. 하지만 x1 x2 대신 x 및 x 제곱을 사용하십시오. 당신이 여전히 문제가 있다면 나는 엑셀이나 의사 코드에서 예제 calc를 시도해 보겠다. – Tim

7

@ ja72 코드가 꽤 좋습니다. 그러나 Math.NET의 현재 버전 (MathNet.Iridium은 현재 이해할 수 없음)에서 이식했으며 코드 크기와 성능을 모두 최적화했습니다. 성능 저하로 인해 Math.Pow 함수가 내 솔루션에 사용되지 않습니다.

public class PolynomialRegression 
{ 
    private int _order; 
    private Vector<double> _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<double> 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에서 사용할 수 있습니다.