Dan
Dan

Reputation: 7724

Working out a point using curve fitting in java

The following code produces a curve that should fit fit the points

1, 1
150, 250
10000, 500
100000, 750
100000, 1000

I built this code based off the documentation here, however, I am not entirely sure how to use the data correctly for further calcuations and whether PolynomialCurveFitter.create(3) will affect the answers in these future calcuations.

For example, how would I use the data outputted to calculate what is the x value if the y value is 200 and how would the value differ if I had PolynomialCurveFitter.create(2) instead of PolynomialCurveFitter.create(3)?

import java.util.ArrayList;
import java.util.Arrays;

import org.apache.commons.math3.fitting.PolynomialCurveFitter;
import org.apache.commons.math3.fitting.WeightedObservedPoints;

public class MyFuncFitter {
    public static void main(String[] args) {
        ArrayList<Integer> keyPoints = new ArrayList<Integer>();
        keyPoints.add(1);
        keyPoints.add(150);
        keyPoints.add(10000);
        keyPoints.add(100000);
        keyPoints.add(1000000);

        WeightedObservedPoints obs = new WeightedObservedPoints();
        if(keyPoints != null && keyPoints.size() != 1) {
            int size = keyPoints.size();
            int sectionSize = (int) (1000 / (size - 1));
            for(int i = 0; i < size; i++) {
                if(i != 0)
                    obs.add(keyPoints.get(i),  i * sectionSize);
                else
                    obs.add(keyPoints.get(0),  1);
            }
        } else if(keyPoints.size() == 1 && keyPoints.get(0) >= 1) {
            obs.add(1,  1);
            obs.add(keyPoints.get(0),  1000);
        }

        PolynomialCurveFitter fitter = PolynomialCurveFitter.create(3);
        fitter.withStartPoint(new double[] {keyPoints.get(0), 1});
        double[] coeff = fitter.fit(obs.toList());
        System.out.println(Arrays.toString(coeff));
    }
}

Upvotes: 2

Views: 3511

Answers (1)

Fabien Benoit-Koch
Fabien Benoit-Koch

Reputation: 2841

About what the consequences of changing d for your function

PolynomialCurveFitter.create takes the degree of the polynomial as a parameter.

Very (very) roughly speaking, the polynomial degree will describe the "complexity" of the curve you want to fit. A low-level degree will produce simple curves (just a parabola for d=2), whereas higher degrees will produce more intricate curves, with lots of peaks and valleys, of highly varying sizes, therefore more able to perfectly "fit" all your data points, at the expense of not necessarily being a good "prediction" of all other values.

Like the blue curve on this graphic:

enter image description here

You can see how the straight line would be a better "approximation", while not fitting the data point properly.

How to compute x for any y values in the computed function

You "simply" need to solve the polynomial ! Using the very same library. Add the inverted y value to your coefficents list, and find its root.

Let's say you chose a degree of 2.

Your coefficients array coeffs will contains 3 factors {a0, a1, a2} which describes the equation as such:

a0 + a1 * x + a2 * x²

If you want to solve this for a particular value, like y= 600, you need to solve :

a0 + a1 * x + a2 * x² = 600

So, basically,

a0 - 600 + a1 * x + a2 * x² = 0

So, just substract 600 to a0:

coeffs[0] -= 600

and find the root of the polynomial using the dedicated function:

PolynomialFunction polynomial = new PolynomialFunction(coeffs);
LaguerreSolver laguerreSolver = new LaguerreSolver();
double x = laguerreSolver.solve(100, polynomial, 0, 1000000);
System.out.println("For y = 600, we found x = " + x);

Upvotes: 4

Related Questions