Ita*_*aia 7 java math curve-fitting
如何使用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);
}
Run Code Online (Sandbox Code Playgroud)
i80*_*and 16
所以,这是一个老问题,但我最近遇到了同样的问题,最终不得不深入研究邮件列表和Apache Commons Math源代码来解决这个问题.
这个API的文档记录非常少,但是在当前版本的Apache Common Math(3.3+)中,有两个部分,假设你有一个带有多个参数的变量:要适应的函数(实现ParametricUnivariateFunction)和曲线拟合器(扩展了AbstractCurveFitter).
适合的功能
public double value(double t, double... parameters)
fnc逻辑的地方.public double[] gradient(double t, double... parameters)
曲线钳工
protected LeastSquaresProblem getProblem(Collection<WeightedObservedPoint> points)
总而言之,这是您特定情况下的示例解决方案:
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));
}
}
Run Code Online (Sandbox Code Playgroud)
我知道这个问题已经很老了并且在i80上做得很好,但是我只是想补充一下(对于将来的SO-ers),有一种非常简单的方法可以使用Apache Math计算导数或偏导数(因此您没有为雅各比矩阵做自己的微分)。这是DerivativeStructure。
扩展i80and的答案以使用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));
}
}
Run Code Online (Sandbox Code Playgroud)
就是这样。我知道这是一个令人费解的/令人困惑的类,但是当您处理非常复杂的方程式而要手工获取部分导数会很麻烦时(这在我不久前就发生了),它肯定会派上用场当您想导出偏导数时,请说出二阶或三阶。
对于二阶,三阶等等的导数,您要做的就是:
// 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)
Run Code Online (Sandbox Code Playgroud)
希望这对某人有所帮助。