Polynomial Regression Data Fit, Polygon 4. Grades gesucht

Hi,

könnte mal jemand schauen, was hier nicht stimmt?

package org.example;

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

public class DataFit {
    public static double calcY(double i, Double[] d) {
        return d[0] * i * i * i + d[1] * i * i + d[2] * i + d[3];
    }

    public static double calcE(double[][] xys, Double[] d) {
        double sum = 0;
        for (double[] xy : xys) {
            sum += Math.abs(calcY(xy[0], d) - xy[1]);
        }
        return sum;
    }

    public static double check(double bestE, Double[] best, ArrayList<Double[]> bests, double[][] xys) {
        double e = calcE(xys, best);
        if (e < bestE) {
            bests.add(best);
            System.out.println("e = " + e);
            return e;
        }
        return 10000;
    }

    public static ArrayList<Double[]> fit(double[][] xys) {
        ArrayList<Double[]> bests = new ArrayList<>();
        double bestE = 10000;
        for (int i = 0; i <= 5000; i++) {
            System.out.println("i = " + i);
            for (int j = 0; j <= 5000; j++) {
                int c2 = 0;
                for (int k = 0; k <= 5000 && c2 < 10; k++) {
                    int c1 = 0;
                    for (int l = 0; l <= 5000 && c1 < 5; l++) {
                        Double[] best1 = {i / 100d, j / 100d, k / 100d, l / 100d};
                        Double[] best2 = {-i / 100d, -j / 100d, -k / 100d, -l / 100d};
                        double oldE = bestE;
                        bestE = Math.min(bestE, check(bestE, best1, bests, xys));
                        bestE = Math.min(bestE, check(bestE, best2, bests, xys));
                        if (oldE == bestE) {
                            c1++;
                            c2++;
                        }
                        else {
                            c1 = 0;
                            c2 = 0;
                        }
                        if (bests.size() > 20) {
                            bests.sort(Comparator.comparingDouble(a -> calcE(xys, a)));
                            while (bests.size() > 10) {
                                bests.remove(bests.size() - 1);
                            }
                        }
                    }
                }
            }
        }
        bests.sort(Comparator.comparingDouble(a -> calcE(xys, a)));
        while (bests.size() > 10) {
            bests.remove(bests.size() - 1);
        }
        return bests;
    }

    public static void main(String[] args) {
        ArrayList<Double[]> bests1 = fit(new double[][]{{0, 4.5}, {4, 43}, {8, 80}, {12, 100}});
        for (Double[] best : bests1) {
            System.out.println(Arrays.toString(best));
        }
    }
}

Mit Zeile 45 bis 52 erhalte ich folgendes Ergebnis: [0.0, 0.43, 0.0, 36.13], was falsch ist, bzw. nicht optimal.

Wenn ich Zeile 45 bis 52 auskommentiere, hält die Anwendung nicht an.

Gesucht ist ein Polygon 4. Grades ( ax^3 + bx^2 + cx + d ) mit der geringsten Standardabweichung für folgende Datenwerttabelle:

x y
0 4.5
4 43
8 80
12 100

Ferner soll noch bestimmt werden, ob die Kurve logarithmisch verläuft oder nicht.

Hi,

auch wenn meine Mathe-Kenntnisse (leider) nicht die besten sind - aber sollte das

nicht ein Polynom 3. Grades sein ??

hand, mogel

1 „Gefällt mir“

Bin mir leider auch unsicher. Geht das nach der Anzahl der Komponenten oder nach dem höchsten Exponenten?

Des Weiteren hab ich inzwischen meinen Fehler im Code gefunden. :slight_smile:

Aber ungünstigerweise (oder vielleicht glücklicherweise?) war der Gauß da schneller. hehe

Ich gehe davon aus, dass du das Ergebnis nicht teilen wirst?

Es geht nach dem höchsten Exponenten.

1 „Gefällt mir“

ist doch unwichtig, es gibt dafür bessere Verfahren, die schon vor 200 Jahren erfunden wurden… als es noch gar keine Rechenpower gab

für meinen Trial-and-Error-Ansatz sollte man zudem besser C++ verwenden, Java ist manchmal langsam

ach na ja, was solls… los, macht euch lustig über mich:

package org.example;

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

public class DataFit {
    public static double calcY(final double i, final Double[] d) {
        return d[0] * i * i * i + d[1] * i * i + d[2] * i + d[3];
    }

    public static double calcE(final double[][] xys, final Double[] d) {
        double sum = 0;
        for (double[] xy : xys) {
            sum += Math.abs(calcY(xy[0], d) - xy[1]);
        }
        return sum;
    }

    public static double check(final double bestE, final Double[] best, final ArrayList<Double[]> bests, final double[][] xys) {
        double e = calcE(xys, best);
        if (e < bestE) {
            bests.add(best);
            return e;
        }
        return 10000;
    }

    public static void shrink(final double[][] xys, final ArrayList<Double[]> bests) {
        bests.sort(Comparator.comparingDouble(a -> calcE(xys, a)));
        while (bests.size() > 10) {
            bests.remove(bests.size() - 1);
        }
    }

    public static ArrayList<Double[]> fit1(final double[][] xys, final int limit, final double step, final double[] startValues) {
        int[] starts = new int[startValues.length];
        for (int i = 0; i < starts.length; i++) {
            starts[i] = Math.max(0, (int) Math.round((startValues[i] - 1d / step * (limit / 2d)) * limit));
        }
        ArrayList<Double[]> bests = new ArrayList<>();
        double bestE = 10000;
        for (int i = starts[0]; i <= starts[0] + limit; i++) {
            for (int j = starts[1]; j <= starts[1] + limit; j++) {
                for (int k = starts[2]; k <= starts[2] + limit; k++) {
                    for (int l = starts[3]; l <= starts[3] + limit; l++) {
                        bestE = Math.min(bestE, check(bestE, new Double[]{-i / step, -j / step, -k / step, -l / step}, bests, xys));
                        bestE = Math.min(bestE, check(bestE, new Double[]{-i / step, -j / step, -k / step, l / step}, bests, xys));
                        bestE = Math.min(bestE, check(bestE, new Double[]{-i / step, -j / step, k / step, -l / step}, bests, xys));
                        bestE = Math.min(bestE, check(bestE, new Double[]{-i / step, -j / step, k / step, l / step}, bests, xys));
                        bestE = Math.min(bestE, check(bestE, new Double[]{-i / step, j / step, -k / step, -l / step}, bests, xys));
                        bestE = Math.min(bestE, check(bestE, new Double[]{-i / step, j / step, -k / step, l / step}, bests, xys));
                        bestE = Math.min(bestE, check(bestE, new Double[]{-i / step, j / step, k / step, -l / step}, bests, xys));
                        bestE = Math.min(bestE, check(bestE, new Double[]{-i / step, j / step, k / step, l / step}, bests, xys));

                        bestE = Math.min(bestE, check(bestE, new Double[]{i / step, -j / step, -k / step, -l / step}, bests, xys));
                        bestE = Math.min(bestE, check(bestE, new Double[]{i / step, -j / step, -k / step, l / step}, bests, xys));
                        bestE = Math.min(bestE, check(bestE, new Double[]{i / step, -j / step, k / step, -l / step}, bests, xys));
                        bestE = Math.min(bestE, check(bestE, new Double[]{i / step, -j / step, k / step, l / step}, bests, xys));
                        bestE = Math.min(bestE, check(bestE, new Double[]{i / step, j / step, -k / step, -l / step}, bests, xys));
                        bestE = Math.min(bestE, check(bestE, new Double[]{i / step, j / step, -k / step, l / step}, bests, xys));
                        bestE = Math.min(bestE, check(bestE, new Double[]{i / step, j / step, k / step, -l / step}, bests, xys));
                        bestE = Math.min(bestE, check(bestE, new Double[]{i / step, j / step, k / step, l / step}, bests, xys));

                        if (bests.size() > 20) {
                            shrink(xys, bests);
                        }
                    }
                }
            }
        }
        shrink(xys, bests);
        return bests;
    }

    @SuppressWarnings("UnusedReturnValue")
    public static ArrayList<Double[]> fit2(final double[][] xys) {
        ArrayList<Double[]> bests1 = new ArrayList<>();
        ArrayList<Double[]> bests2 = new ArrayList<>();

        // 0.5, 1.0 and 2.0 divisor = 2.0, 1.0 and 0.5-step width
        for (int i = 1; i <= 4; i *= 2) {
            bests1.addAll(fit1(xys, 50, i / 2d, new double[4]));
        }

        shrink(xys, bests1);

        for (Double[] best : bests1) {
            System.out.println(Arrays.toString(best));
            System.out.println(calcE(xys, best));
        }
        System.out.println();

        // 50 limit and 50 divisor (0.02-step width) = 0.02, 0.04, ..., 1.0
        for (Double[] best : bests1) {
            bests2.addAll(fit1(xys, 50, 50, new double[]{best[0], best[1], best[2], best[3]}));
        }

        shrink(xys, bests2);

        for (Double[] best : bests2) {
            System.out.println(Arrays.toString(best));
            System.out.println(calcE(xys, best));
        }
        System.out.println();

        return bests2;
    }

    public static void main(String[] args) {
        fit2(new double[][]{{0, 4.5}, {4, 43}, {8, 80}, {10, 99}, {12, 100}});
        fit2(new double[][]{{0, 1}, {4, 30}, {8, 49}, {10, 64}, {12, 100}});
    }
}

ArrayList<Double[]>
----------^^^^^^

Hier nicht die Wrapper-Klasse zu verwenden, sondern zum Beispiel nur double[], lässt sich nicht umgehen, oder?

Weil dann könnte ich überall den Double[]-Parameter durch etwas „Günstigeres“ ersetzen …

Falls du glaubst, dass man mit double[] eine bessere Performance erreichen kann als mit Double[]: Theoretisch ja. Praktisch ist das wirklich das kleinste Problem.

Wenn man ganz fancy werden und ein paar Größenordnungen abstrakter werden will, kann man über ein DoubleTuple interface nachdenken, aber … hier? Nein.

@Marco13 Hast du eine Idee, wie es besser ginge? Abgesehen davon, dass mathematische Berechnungen immer schwer zu lesen sind?

Der Code ist ja nur einen Monat alt, und ich habe jetzt schon das Problem, dass ich nicht mehr genau weiß, was ich da gemacht hatte. Du auch?

Falls du erwartest, dass ich jetzt zum 1001. Mal den Code durchgehe und all die Banalitäten ankreide, die schon in 1000 anderen Threads durchgekaut wurden, wo du irgendwelchen Murxcode gepostet hast, hast du dich geschnitten. Schreib’ ihn so, dass du ihn nach einem Monat noch verstehst, was auch immer das bedeutet. Viele Fragen würden sich damit schon erübrigen.

1 „Gefällt mir“

Ist schon ok. Mach, was du für richtig hältst. Nimm am besten Martin gleich mit.