かなりマニアックなネタ。
Apache commons mathは、数値計算用のJavaのライブラリで、Levenberg-Marqurdt法によるフィッティングや、機械学習など、いろんなメソッドが用意されている。Fijiにも外部ライブラリとして利用されている。
2次元のガウス分布でのフィッティング(例えば蛍光輝点のフィッティングなど)には、
optimizationライブラリの、LevenbergarquardtOptimizerを使う。
詳しいやり方は省くが、
- モデル関数とそのモデル関数のjacobianを、それぞれMultivariateVectorFuncion, MultivariateMatrixFunctionとして作る
- LevenbergMarquardtOptimizerのオブジェクトを作るLevenbergMarquardtOptimizer lmo = new LevenbergMarquardtOptimizer();
- LeastSquaresProblemを作り、lmo.optimizeのパラメータとして渡す。返り値として、最適化されたパラメータを受け取るLeastSquaresOptimizer.Optimun lsoo = lmo.optimize(lsp); // lsp -> LeastSquaresProblemのオブジェクト
ここで、lspはLeastSquaresBuilderで作ることができる。
LeastSquaresBuilder lsb = new LeastSquaresBuilder();
lsb.model(modelfunction(), jacobianfunction()); // モデル関数とそのjacobian
lsb.target(data); // 入力データ
lsb.start(newStart); // パラメータの初期値
lsb.maxIterations(1000); // 最大itterationの回数
例えば有名なグラフ・統計解析ソフトのOriginでは、非線形フィッティングの際に、パラメータに制約条件を付けることができる。Apache commons mathでもできるが、詳しいやり方はちゃんと書いてない。一応、LeastSquaresのParameters Validationにそれっぽい記述がある。
In some cases, the model function requires parameters to lie within a specific domain. For example a parameter may be used in a square root and needs to be positive, or another parameter represents the sine of an angle and should be within -1 and +1, or several parameters may need to remain in the unit circle and the sum of their squares must be smaller than 1. The least square solvers available in Apache Commons Math currently don't allow to set up constraints on the parameters. This is a known missing feature. There are two ways to circumvent this.
Both ways are achieved by setting up a ParameterValidator instance. The input of the value and jacobian model functions will always be the output of the parameter validator if one exists.
どうやらこの、ParameterValidatorを使えばできそうな雰囲気だが、Javadocを見てもほとんど情報がない。ParameterValidatorはinterfaceで、validate(RealVector params)というメソッドを実装するインターフェースである。なんとなくこのparamsというのが怪しそうだが、RealVector型もよくわからん。
LeastSquaresBuilderで作ったlsbのメソッドで、parameterValidatorがあるのでなんとなく使ってみる。
lsb.parameterValidator(new ParameterValidator() { ... }
lsb.parameterValidator(new ParameterValidator() {
    @Override
    public RealVector validate(RealVector params) { ... }
});
The input of the value and jacobian model functions will always be the output of the parameter validator if one exists.
なんとなく訳すと、「値とjacobian モデル関数の入力は、Parameter Validatorが存在するときには常にその出力となります」というようなことが書いてあり、多分iterationのたんびにparameterValidatorが呼び出されることになりそう。あとは、パラメータにアクセスできればよい。
RealVector型であるparamsからパラメータにアクセスするには、
getEntry(int index)
setEntry(int index, double value)
public RealVector validate(RealVector params) {
 System.out.println("parameter[0]: " + params.getEntry(0));
 return params;
}
v0: 255.0
v0: 76.64496657297977
v0: 215.79832218070536
...
v0: 258.1698480422253
というように、iterationごとでv0がどのような値になったかを出力してくれるようになる。
従って、例えばv0は必ず0より大きな値をとる必要があるのであれば、
if (params.getEntry(0) < 0) params.setEntry(0, 0.00001);
これで、フィッティングのパラメータに制約を与えることができるようになった。
ちなみにこの方法をネット上で検索したが、英語のサイトでもまず見つからない。かなりレアな情報だと思う。
 

