commons-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Luc Maisonobe <...@spaceroots.org>
Subject Re: [math] Curve fitting ...
Date Thu, 14 Aug 2014 18:28:55 GMT
Hi South Light,

Le 14/08/2014 19:05, South Light a écrit :
> Hi Thomas,
> 
> My problem is to find the best A value in y = 10 ^ ((x + 82) / (-10 * A))
> that fits better in a set of data. I'll be getting different sets of data.
> 
> I'm new in the use of the math lib and the examples found are all based
> on deprecated classes.
> 
> Now I'm a little lost in terms of which class will be better to solve the
> problem, was thinking CurveFitter was the way to go.
> 
> Can someone help me and clear my ideas ?

Here is what I would suggest to you (beware, I did not check it, just
scribbled it in a few minutes).

Given your specific function, create a dedicated curve fitter, taking
the GaussianCurveFitter class as an example, slightly edited:

public class MyFitter extends AbstractCurveFitter {

  /** Center. */
  private final double center;

  /** Initial guess. */
  private final double guessedA;

  private MyFitter(final double center, final double guessedA) {
    this.center   = center;
    this.guessedA = guessedA;
  }

  protected LeastSquaresProblem
    getProblem(Collection<WeightedObservedPoint> points) {

    // Prepare least-squares problem.
    final int len = observations.size();
    final double[] target  = new double[len];
    final double[] weights = new double[len];

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

    ParametricUnivariateFunction function =
    new ParametricUnivariateFunction() {
            @Override
            public double value(double x, double ... p) {
                // get the single "a" parameter
                double a = p[0];
                // value of the function f(x), with current a
                return FastMath.pow(10, ((x + center) / (-10 * a));
            }

            @Override
            public double[] gradient(double x, double ... p) {
                // get the single "a" parameter
                double a = p[0];
                // derivative df/da
                return new double[] {
                  -FastMath.ln(10) / (10 * a * value(x, p));
                };
            }
        };

    final AbstractCurveFitter.TheoreticalValuesFunction model =
      new AbstractCurveFitter.TheoreticalValuesFunction(function,
                                                        observations);

    // Return a new least squares problem set up to fit curve
    // to the observed points.
        return new LeastSquaresBuilder().
                maxEvaluations(Integer.MAX_VALUE).
                maxIterations(100).
                start(new double[] { guessedA }).
                target(target).
                weight(new DiagonalMatrix(weights)).
                model(model.getModelFunction(),
                      model.getModelFunctionJacobian()).
                build();

  }

}

This consider the center (85.0 in your example) is fixed and never
adjusted, while the parameter a is adjusted during the fitting.

Use this as follows:

  // set up observed points
  List<WeightedObservedPoint> observations =
    new ArrayList<WeightedObservedPoint>();
  for (int i = 0; i < n; i++) {
    observations.add(new WeightedObservedPoint(1.0, x[i], y[i));
  }

  // set up fitter, initial guess is a = 1.0 here
  MyFitter fitter = new MyFitter(85.0, 1.0);

  // perform fitting
  double[] fitted = fitter.fit(observations);

  // get the fitted value a:
  System.out.println("fitted a = " + fitted[0]);


Once again, beware this is a quick answer, it probably needs soem
adjustments. Typically, the fitter is completely hard-coded (except for
the center value which you can provide at construction). The curve
fitters provided in Apache Commons Math for some classical curves
(harmonic, gaussian, polynomial) have more bells and whistles, in order
to change for example the start value or the max number of iterations. I
don't know if you need this level of flexibility in your case.

Hope this helps,
Luc

> 
> Many thanks for all your feedback.
> 
> 
> Thanks a lot
> .
> 
> 
> 
> 2014-08-14 13:47 GMT-03:00 Thomas Vandahl <tv@apache.org>:
> 
>> I take it, you ask for help for doing your homework?
>>
>> Bye, Thomas
>>
>>> Am 14.08.2014 um 15:56 schrieb South Light <southlight25@gmail.com>:
>>>
>>> Hi Ted,
>>>
>>> Thanks a lot for your suggestion but I need to add it using java.
>>>
>>> Thanks
>>> ​again​
>>> .​
>>>
>>>
>>>
>>> 2014-08-14 2:22 GMT-03:00 Ted Dunning <ted.dunning@gmail.com>:
>>>
>>>> Have you considered using an interactive system like R, Matlab or
>> Octave?
>>>>
>>>> You might be happier.
>>>>
>>>> Or even have you considered goal search in Excel?
>>>>
>>>>
>>>>
>>>>
>>>> On Wed, Aug 13, 2014 at 6:08 PM, South Light <southlight25@gmail.com>
>>>> wrote:
>>>>
>>>>> Hi,
>>>>>
>>>>> May be someone can help me with this problem.
>>>>>
>>>>> Given the follow function: y = 10 ^ ((x + 82) / (-10 * A))
>>>>>
>>>>> I would like to found the A value witch curve fit better for a set of
>> x,y
>>>>> values, usually the set is about 20 to 25 x,y values.
>>>>>
>>>>> I use the CurveFitter class and the ParametricUnivariateFunction
>>>>>
>>>>>
>>>>> ParametricUnivariateFunction function = new
>>>> ParametricUnivariateFunction()
>>>>> {
>>>>>
>>>>> ​  ​
>>>>> @Override
>>>>> ​  ​
>>>>> public double[] gradient(double x, double[] params) {
>>>>> ​
>>>>> (????? comment)
>>>>> ​  ​
>>>>> }
>>>>>
>>>>> ​  ​
>>>>> @Override
>>>>> ​  ​
>>>>> public double value(double x, double[] params) {
>>>>>
>>>>> ​    ​
>>>>> double a = params[0];
>>>>>
>>>>> ​    ​
>>>>> return Math.pow(10, ((x + 82) /
>>>>> ​(​
>>>>> -10 *
>>>>> ​a
>>>>> ​)​
>>>>> ));
>>>>>
>>>>> ​  ​
>>>>> }
>>>>>
>>>>> };
>>>>>
>>>>> LevenbergMarquardtOptimizer optimizer = new
>>>> LevenbergMarquardtOptimizer();
>>>>>
>>>>> CurveFitter<ParametricUnivariateFunction> fitter = new
>>>>> CurveFitter<ParametricUnivariateFunction>(optimizer);
>>>>>
>>>>> double[] x = {
>>>>> -82
>>>>> ,
>>>>> ​-85
>>>>> ,
>>>>> ​-89
>>>>> };
>>>>>
>>>>> double[] y = {
>>>>> ​1
>>>>> ,
>>>>> ​1.4
>>>>> ,
>>>>> ​2
>>>>> };
>>>>>
>>>>> for (int i = 0; i < x.length; i++)
>>>>> ​  ​
>>>>> fitter.addObservedPoint(x[i], y[i]);
>>>>>
>>>>> double[] result = fitter.fit(function, new double[] { 1, 10 });
>>>>>
>>>>>
>>>>>
>>>>> ​A. ​Is this the best way to solve the problem or there's another
>> better
>>>>> way?
>>>>>
>>>>> B. What do we need to write on the gradient area (????? comment) ?​
>>>>>
>>>>> Any help will be more then welcome.
>>>>>
>>>>> Many thanks !!
>>>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: user-unsubscribe@commons.apache.org
>> For additional commands, e-mail: user-help@commons.apache.org
>>
>>
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@commons.apache.org
For additional commands, e-mail: user-help@commons.apache.org


Mime
View raw message