7

Math Commons CurveFitterを使用して、関数をデータセットに適合させるにはどうすればよいですか?LevenbergMarquardtOptimizerParametricUnivariateFunctionでCurveFitterを使用するように言われましたが、ParametricUnivariateFunctionのグラデーションと値のメソッドで何を書くべきかわかりません。その上、それらを書いた後、どのように適合された関数パラメータを取得するのですか?私の機能:

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

2 に答える 2

17

ですから、これは古い質問ですが、最近同じ問題に遭遇し、それを理解するためにメーリングリストとApacheCommonsMathのソースコードを調べなければならなくなりました。

このAPIの文書化は非常に不十分ですが、Apache Common Mathの現在のバージョン(3.3以降)では、複数のパラメーターを持つ単一の変数があると仮定すると、2つの部分があります。適合関数(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));
    }
}
于 2014-11-15T02:56:21.210 に答える
5

私はこの質問がかなり古く、i80でこれに答えるのに優れた仕事をしたことを知っていますが、Apache Mathを使用して導関数または偏導関数を計算する非常に簡単な方法があることを(将来のSO-erのために)追加しようと思いました( Jacobian Matrixに対して独自の差別化を行うため)。それはDerivativeStructureです。

DerivativeStructureクラスを使用するためにi80andの回答を拡張します。

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

以上です。使用するのはかなり複雑で紛らわしいクラスであることは知っていますが、偏導関数を手作業で取得するのが面倒な非常に複雑な方程式を扱う場合(これはそれほど前に私には起こりませんでした)、または偏導関数を導出したい場合は、2次または3次と言います。

2次、3次などの次数導関数の場合、実行する必要があるのは次のとおりです。

// 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)

うまくいけば、これはいつか誰かを助けるでしょう。

于 2017-10-31T16:58:22.143 に答える