如何使用Math Commons CurveFitter将函数拟合到一组数据?有人告诉我使用带有LevenbergMarquardtOptimizer和ParametricUnivariateFunction的CurveFitter,但我不知道在ParametricUnivariateFunction梯度和值方法中要写什么.另外,在写完之后,如何获得拟合的函数参数?我的功能:
public static double fnc(double t,double a,double b,double c){ return a * Math.pow(t,b) * Math.exp(-c * t); }
解决方法
所以,这是一个老问题,但我最近遇到了同样的问题,最终不得不深入研究邮件列表和Apache Commons Math源代码来解决这个问题.
这个API的文档记录非常少,但是在当前版本的Apache Common Math(3.3)中,有两个部分,假设你有一个带有多个参数的变量:拟合的函数(实现ParametricUnivariateFunction)和曲线拟合器(它扩展了AbstractCurveFitter).
适合的功能
>公共双值(双t,双…参数)
>你的等式.这是您放置fnc逻辑的地方.
> public double [] gradient(double t,double …参数)
>根据每个参数返回上述偏导数的数组.如果(像我一样)你的微积分生锈了,但是任何好的计算机代数系统都可以计算出这些值,This calculator可能会有所帮助.
曲线钳工
>受保护的LeastSquaresProblem getProblem(集合< WeightedObservedPoint>点)
>设置一堆样板垃圾,并返回最小二乘问题供装配工使用.
总而言之,这是您特定情况下的示例解决方案:
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); points.add(point); final double coeffs[] = fitter.fit(points); System.out.println(Arrays.toString(coeffs)); } }