2011-10-17 50 views
22

Tôi đang tìm cách tạo đường cong phi tuyến tính (tốt nhất bậc hai), dựa trên tập dữ liệu 2D, cho mục đích dự báo. Ngay bây giờ tôi đang sử dụng thực hiện của riêng tôi của bình phương ít nhất bình phương (OLS) để sản xuất một xu hướng tuyến tính, nhưng xu hướng của tôi là phù hợp hơn nhiều với một mô hình đường cong. Dữ liệu tôi đang phân tích là tải hệ thống theo thời gian.Hồi quy phi tuyến tính trong C#

Dưới đây là phương trình mà tôi đang sử dụng để sản xuất hệ số tuyến tính của tôi:

Ordinary Least Squares (OLS) formula

Tôi đã có một cái nhìn tại Math.NET numerics và một vài libs khác, nhưng họ hoặc cung cấp suy thay vì hồi quy (không sử dụng được với tôi) hoặc mã không hoạt động theo một cách nào đó.

Bất kỳ ai biết về bất kỳ libs nguồn mở miễn phí hoặc mẫu mã nào có thể tạo ra các hệ số cho một đường cong như vậy?

+0

Đây chính xác là kết quả tôi đang tìm kiếm: 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

Một q khác có liên kết: http://stackoverflow.com/questions/882009/is-there-any-tool-for-regression-model Một điều liên quan đến codeproject: http: //www.codeproject.com/KB/recipes/QuadraticRegression.aspx – AakashM

+0

Trước đây là tập hợp các liên kết đến các mô hình nội suy, và sau đó cho kết quả không chính xác/không chính xác, ngay cả sau khi chuyển đổi nó thành 'thập phân' thay vì' double '. – Polynomial

Trả lời

24

Tôi đã sử dụng bản phát hành MathNet.Iridium vì nó tương thích với .NET 3.5 và VS2008. Phương pháp này dựa trên ma trận Vandermonde. Sau đó, tôi tạo ra một lớp học để giữ hồi quy đa thức của tôi

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

mà sau đó tôi sử dụng nó như thế này:

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

hệ số Tính của [1,0.57,-0.15] với sản lượng:

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 

nào phù hợp với quadratic kết quả từ Wolfram Alpha. Quadratic Equation Quadratic Fit

Sửa 1 Để có được để phù hợp bạn muốn thử khởi sau cho 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); 

trong đó sản xuất các hệ số sau đây (từ điện thấp nhất đến cao nhất)

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

Giải quyết vấn đề của tôi một cách hoàn hảo. Cảm ơn :) – Polynomial

+3

Tôi đã tối ưu hóa và nâng cấp câu trả lời của bạn :) http://stackoverflow.com/a/12770686/1046374 –

0

Tôi sẽ xem http://mathforum.org/library/drmath/view/53796.html để thử có ý tưởng về cách thực hiện.

Sau đó, this có triển khai tốt đẹp mà tôi nghĩ sẽ giúp bạn.

+0

Việc triển khai đó không hiệu quả đối với tôi. Nó đã cho kết quả hoàn toàn không chính xác (0/1/0 cho coeffs) ra khỏi hộp và sau khi một số tinh chỉnh vẫn hoàn toàn không chính xác. Không có gì giống như kết quả Wolfram Alpha mà tôi đã phát hiện trước đó. Các toán học trong liên kết bạn cung cấp là ngoài tôi, thật không may. – Polynomial

6

Tôi không nghĩ bạn muốn hồi quy phi tuyến tính. Ngay cả khi bạn đang sử dụng một hàm bậc hai, nó vẫn được gọi là hồi quy tuyến tính. Những gì bạn muốn được gọi là hồi quy đa biến. Nếu bạn muốn một bậc hai, bạn chỉ cần thêm một thuật ngữ x bình phương vào các biến phụ thuộc của bạn.

+0

Hồi quy tuyến tính cho tôi một dòng. Tôi đã không có ý tưởng làm thế nào để chỉnh sửa các phương trình tôi được đăng để làm bất cứ điều gì khác nhau. Tôi muốn nhận được kết quả như sau: 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

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

+0

Sử dụng công thức. Nhưng thay vì x1 x2 sử dụng x và x bình phương của bạn. Nếu bạn vẫn còn có vấn đề tôi sẽ cố gắng và làm cho một ví dụ calc trong excel hoặc giả mã. – Tim

7

@ ja72 mã là khá tốt. Nhưng tôi đã chuyển nó trên phiên bản hiện tại của Math.NET (MathNet.Iridium không được hỗ trợ ngay bây giờ khi tôi hiểu) và tối ưu hóa cả kích thước và hiệu suất mã (hàm Math.Pow không sử dụng trong giải pháp của tôi vì hiệu suất chậm).

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

Nó cũng có sẵn trên github:gist.

Các vấn đề liên quan