2012-07-04 35 views
5

Làm cách nào để sử dụng Math Commons CurveFitter để phù hợp với một chức năng cho một tập hợp dữ liệu? Tôi được yêu cầu sử dụng CurveFitter với LevenbergMarquardtOptimizerParametricUnivariateFunction, nhưng tôi không biết phải viết gì trong các phương thức giá trị và phương thức giá trị tham số ParametricUnivariateFunction. Bên cạnh đó, sau khi viết chúng, làm thế nào để có được các thông số chức năng được trang bị? chức năng của tôi:Làm thế nào để sử dụng Java Math Commons CurveFitter?

public static double fnc(double t, double a, double b, double c){ 
    return a * Math.pow(t, b) * Math.exp(-c * t); 
} 

Trả lời

11

Vì vậy, đây là một câu hỏi cũ, nhưng tôi chạy vào cùng một vấn đề thời gian gần đây, và đã kết thúc phải đi sâu vào danh sách gửi thư và mã nguồn Apache Commons Math để con nó ra.

API này ít được ghi nhận tài liệu, nhưng trong phiên bản hiện tại của Apache Common Math (3.3+), có hai phần, giả sử bạn có một biến duy nhất với nhiều tham số: ParametricUnivariateFunction) và fitter đường cong (mở rộng AbstractCurveFitter).

Chức năng Fit

  • public double value(double t, double... parameters)
    • phương trình của bạn. Đây là nơi bạn sẽ đặt logic fnc của mình.
  • public double[] gradient(double t, double... parameters)
    • Trả về một mảng của đạo hàm riêng của các bên trên đối với từng thông số với. This calculator có thể hữu ích nếu (như tôi) bạn đang gỉ trên tính toán của bạn, nhưng bất kỳ hệ thống đại số máy tính tốt có thể tính toán các giá trị này.

cong Fitter

  • protected LeastSquaresProblem getProblem(Collection<WeightedObservedPoint> points)
    • Sets lên một bó của crap soạn sẵn, và trả về một hình vuông vấn đề nhất là trong fitter để sử dụng.

Đưa nó tất cả cùng nhau, đây là một giải pháp ví dụ trong trường hợp cụ thể của bạn:

import java.util.*; 
import org.apache.commons.math3.analysis.ParametricUnivariateFunction; 
import org.apache.commons.math3.fitting.AbstractCurveFitter; 
import org.apache.commons.math3.fitting.leastsquares.LeastSquaresBuilder; 
import org.apache.commons.math3.fitting.leastsquares.LeastSquaresProblem; 
import org.apache.commons.math3.fitting.WeightedObservedPoint; 
import org.apache.commons.math3.linear.DiagonalMatrix; 

class MyFunc implements ParametricUnivariateFunction { 
    public double value(double t, double... parameters) { 
     return parameters[0] * Math.pow(t, parameters[1]) * Math.exp(-parameters[2] * t); 
    } 

    // Jacobian matrix of the above. In this case, this is just an array of 
    // partial derivatives of the above function, with one element for each parameter. 
    public double[] gradient(double t, double... parameters) { 
     final double a = parameters[0]; 
     final double b = parameters[1]; 
     final double c = parameters[2]; 

     return new double[] { 
      Math.exp(-c*t) * Math.pow(t, b), 
      a * Math.exp(-c*t) * Math.pow(t, b) * Math.log(t), 
      a * (-Math.exp(-c*t)) * Math.pow(t, b+1) 
     }; 
    } 
} 

public class MyFuncFitter extends AbstractCurveFitter { 
    protected LeastSquaresProblem getProblem(Collection<WeightedObservedPoint> points) { 
     final int len = points.size(); 
     final double[] target = new double[len]; 
     final double[] weights = new double[len]; 
     final double[] initialGuess = { 1.0, 1.0, 1.0 }; 

     int i = 0; 
     for(WeightedObservedPoint point : points) { 
      target[i] = point.getY(); 
      weights[i] = point.getWeight(); 
      i += 1; 
     } 

     final AbstractCurveFitter.TheoreticalValuesFunction model = new 
      AbstractCurveFitter.TheoreticalValuesFunction(new MyFunc(), points); 

     return new LeastSquaresBuilder(). 
      maxEvaluations(Integer.MAX_VALUE). 
      maxIterations(Integer.MAX_VALUE). 
      start(initialGuess). 
      target(target). 
      weight(new DiagonalMatrix(weights)). 
      model(model.getModelFunction(), model.getModelFunctionJacobian()). 
      build(); 
    } 

    public static void main(String[] args) { 
     MyFuncFitter fitter = new MyFuncFitter(); 
     ArrayList<WeightedObservedPoint> points = new ArrayList<WeightedObservedPoint>(); 

     // Add points here; for instance, 
     WeightedObservedPoint point = new WeightedObservedPoint(1.0, 
      1.0, 
      1.0); 
     points.add(point); 

     final double coeffs[] = fitter.fit(points); 
     System.out.println(Arrays.toString(coeffs)); 
    } 
} 
+1

Tôi đang bối rối về việc thu thập điểm. Không có X_value cho họ? Tại sao mục tiêu chỉ chứa giá trị Y? –

+0

Ngoài ra làm thế nào tôi có thể thêm ràng buộc vào các tham số (ví dụ tham số a trong f (x) = c * ln (a * x) cần phải luôn luôn dương)? –

1

Tôi biết của khá cũ và i80and đã làm một công việc tuyệt vời trả lời này, nhưng tôi chỉ nghĩ cho câu hỏi này thêm (đối với các SO-ers trong tương lai) có một cách khá dễ dàng để tính toán các dẫn xuất hoặc các dẫn xuất từng phần với Apache Math (vì vậy bạn không phải làm sự khác biệt của riêng bạn cho ma trận Jacobian). Đó là số DerivativeStructure.

Mở rộng câu trả lời i80and 's sử dụng lớp DerivativeStructure:

//Everything stays the same except for the Jacobian Matrix 

import java.util.*; 
import org.apache.commons.math3.analysis.ParametricUnivariateFunction; 
import org.apache.commons.math3.fitting.AbstractCurveFitter; 
import org.apache.commons.math3.fitting.leastsquares.LeastSquaresBuilder; 
import org.apache.commons.math3.fitting.leastsquares.LeastSquaresProblem; 
import org.apache.commons.math3.fitting.WeightedObservedPoint; 
import org.apache.commons.math3.linear.DiagonalMatrix; 
import org.apache.commons.math3.analysis.differentiation.DerivativeStructure; 

class MyFunc implements ParametricUnivariateFunction { 
    public double value(double t, double... parameters) { 
     return parameters[0] * Math.pow(t, parameters[1]) * Math.exp(-parameters[2] * t); 
    } 

    // Jacobian matrix of the above. In this case, this is just an array of 
    // partial derivatives of the above function, with one element for each parameter. 
    public double[] gradient(double t, double... parameters) { 
     final double a = parameters[0]; 
     final double b = parameters[1]; 
     final double c = parameters[2]; 

     // Jacobian Matrix Edit 

     // Using Derivative Structures... 
     // constructor takes 4 arguments - the number of parameters in your 
     // equation to be differentiated (3 in this case), the order of 
     // differentiation for the DerivativeStructure, the index of the 
     // parameter represented by the DS, and the value of the parameter itself 
     DerivativeStructure aDev = new DerivativeStructure(3, 1, 0, a); 
     DerivativeStructure bDev = new DerivativeStructure(3, 1, 1, b); 
     DerivativeStructure cDev = new DerivativeStructure(3, 1, 2, c); 

     // define the equation to be differentiated using another DerivativeStructure 
     DerivativeStructure y = aDev.multiply(DerivativeStructure.pow(t, bDev)) 
       .multiply(cDev.negate().multiply(t).exp()); 

     // then return the partial derivatives required 
     // notice the format, 3 arguments for the method since 3 parameters were 
     // specified first order derivative of the first parameter, then the second, 
     // then the third 
     return new double[] { 
       y.getPartialDerivative(1, 0, 0), 
       y.getPartialDerivative(0, 1, 0), 
       y.getPartialDerivative(0, 0, 1) 
     }; 

    } 
} 

public class MyFuncFitter extends AbstractCurveFitter { 
    protected LeastSquaresProblem getProblem(Collection<WeightedObservedPoint> points) { 
     final int len = points.size(); 
     final double[] target = new double[len]; 
     final double[] weights = new double[len]; 
     final double[] initialGuess = { 1.0, 1.0, 1.0 }; 

     int i = 0; 
     for(WeightedObservedPoint point : points) { 
      target[i] = point.getY(); 
      weights[i] = point.getWeight(); 
      i += 1; 
     } 

     final AbstractCurveFitter.TheoreticalValuesFunction model = new 
       AbstractCurveFitter.TheoreticalValuesFunction(new MyFunc(), points); 

     return new LeastSquaresBuilder(). 
       maxEvaluations(Integer.MAX_VALUE). 
       maxIterations(Integer.MAX_VALUE). 
       start(initialGuess). 
       target(target). 
       weight(new DiagonalMatrix(weights)). 
       model(model.getModelFunction(), model.getModelFunctionJacobian()). 
       build(); 
    } 

    public static void main(String[] args) { 
     MyFuncFitter fitter = new MyFuncFitter(); 
     ArrayList<WeightedObservedPoint> points = new ArrayList<WeightedObservedPoint>(); 

     // Add points here; for instance, 
     WeightedObservedPoint point = new WeightedObservedPoint(1.0, 
       1.0, 
       1.0); 
     points.add(point); 

     final double coeffs[] = fitter.fit(points); 
     System.out.println(Arrays.toString(coeffs)); 
    } 
} 

Và đó là nó.Tôi biết đó là một lớp khá phức tạp/khó hiểu, nhưng nó chắc chắn có ích khi bạn đối phó với các phương trình rất phức tạp, có thể gây rắc rối để có được các dẫn xuất từng phần bằng tay (điều này xảy ra với tôi cách đây không lâu), hoặc khi bạn muốn lấy được các dẫn xuất một phần nói đến thứ tự thứ hai hoặc thứ ba.

Trong trường hợp,, vân vân dẫn xuất bậc ba thứ hai, tất cả các bạn sẽ phải làm là:

// specify the required order as the second argument, say second order so 2 
DerivativeStructure aDev = new DerivativeStructure(3, 2, 0, a);   
DerivativeStructure bDev = new DerivativeStructure(3, 2, 1, b); 
DerivativeStructure cDev = new DerivativeStructure(3, 2, 2, c); 

// and then specify the order again here 
y.getPartialDerivative(2, 0, 0), 
y.getPartialDerivative(0, 2, 0), 
y.getPartialDerivative(0, 0, 2) 

Hy vọng rằng, điều này sẽ giúp ai đó lúc nào đó.

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