Wahrscheinlichkeit in Java

1. Übersicht

In diesem Tutorial sehen wir uns einige Beispiele an, wie wir Wahrscheinlichkeit mit Java implementieren können.

2. Grundwahrscheinlichkeit simulieren

Um die Wahrscheinlichkeit in Java zu simulieren, müssen wir zunächst Zufallszahlen generieren. Glücklicherweise bietet uns Java viele Zufallszahlengeneratoren .

In diesem Fall verwenden wir die SplittableRandom- Klasse, da sie eine hohe Zufälligkeit bietet und relativ schnell ist:

SplittableRandom random = new SplittableRandom();

Dann müssen wir eine Zahl in einem Bereich generieren und sie mit einer anderen Zahl vergleichen, die aus diesem Bereich ausgewählt wurde. Jede Zahl im Bereich hat die gleiche Chance, gezogen zu werden. Da wir den Bereich kennen, kennen wir die Wahrscheinlichkeit, unsere gewählte Zahl zu ziehen. Auf diese Weise kontrollieren wir die Wahrscheinlichkeit :

boolean probablyFalse = random.nextInt(10) == 0

In diesem Beispiel haben wir Zahlen von 0 bis 9 gezeichnet. Daher beträgt die Wahrscheinlichkeit, 0 zu zeichnen, 10%. Lassen Sie uns nun eine Zufallszahl erhalten und testen, ob die gewählte Zahl niedriger als die gezeichnete ist:

boolean whoKnows = random.nextInt(1, 101) <= 50

Hier haben wir Zahlen von 1 bis 100 gezogen. Die Wahrscheinlichkeit, dass unsere Zufallszahl kleiner oder gleich 50 ist, beträgt genau 50%.

3. Gleichmäßige Verteilung

Bis zu diesem Zeitpunkt erzeugte Werte fallen in die Gleichverteilung. Dies bedeutet, dass jedes Ereignis, zum Beispiel das Würfeln einer Zahl auf einem Würfel, die gleiche Chance hat.

3.1. Aufrufen einer Funktion mit einer bestimmten Wahrscheinlichkeit

Nehmen wir nun an, wir möchten von Zeit zu Zeit eine Aufgabe ausführen und ihre Wahrscheinlichkeit kontrollieren. Zum Beispiel betreiben wir eine E-Commerce-Website und möchten 10% unserer Nutzer einen Rabatt gewähren.

Implementieren wir dazu eine Methode, die drei Parameter verwendet: einen Lieferanten, der in einem bestimmten Prozentsatz der Fälle aufgerufen wird, einen zweiten Lieferanten, der in den übrigen Fällen aufgerufen wird, und die Wahrscheinlichkeit.

Zuerst deklarieren wir unser SplittableRandom mit Vavr als Lazy . Auf diese Weise werden wir es bei einer ersten Anfrage nur einmal instanziieren:

private final Lazy random = Lazy.of(SplittableRandom::new); 

Dann implementieren wir die Wahrscheinlichkeitsverwaltungsfunktion:

public  withProbability(Supplier positiveCase, Supplier negativeCase, int probability) { SplittableRandom random = this.random.get(); if (random.nextInt(1, 101) <= probability) { return positiveCase.get(); } else { return negativeCase.get(); } }

3.2. Stichprobenwahrscheinlichkeit mit der Monte-Carlo-Methode

Kehren wir den Prozess um, den wir im vorherigen Abschnitt gesehen haben. Dazu messen wir die Wahrscheinlichkeit mit der Monte-Carlo-Methode. Es erzeugt ein hohes Volumen an zufälligen Ereignissen und zählt, wie viele von ihnen die bereitgestellte Bedingung erfüllen. Dies ist nützlich, wenn die Wahrscheinlichkeit schwer oder unmöglich analytisch zu berechnen ist.

Wenn wir zum Beispiel sechsseitige Würfel betrachten, wissen wir, dass die Wahrscheinlichkeit, eine bestimmte Zahl zu würfeln, 1/6 beträgt. Aber wenn wir einen mysteriösen Würfel mit einer unbekannten Anzahl von Seiten haben, ist es schwer zu sagen, wie hoch die Wahrscheinlichkeit sein würde. Anstatt die Würfel zu analysieren, könnten wir sie einfach mehrmals würfeln und zählen, wie oft bestimmte Ereignisse auftreten.

Mal sehen, wie wir diesen Ansatz umsetzen können. Zuerst werden wir versuchen, die Nummer 1 mit einer Wahrscheinlichkeit von 10% millionenfach zu generieren und sie zu zählen:

int numberOfSamples = 1_000_000; int probability = 10; int howManyTimesInvoked = Stream.generate(() -> randomInvoker.withProbability(() -> 1, () -> 0, probability)) .limit(numberOfSamples) .mapToInt(e -> e) .sum();

Dann ist die Summe der erzeugten Zahlen geteilt durch die Anzahl der Abtastwerte eine Annäherung an die Wahrscheinlichkeit des Ereignisses:

int monteCarloProbability = (howManyTimesInvoked * 100) / numberOfSamples; 

Beachten Sie, dass die berechnete Wahrscheinlichkeit angenähert wird. Je höher die Anzahl der Abtastwerte ist, desto besser ist die Annäherung.

4. Andere Distributionen

Die gleichmäßige Verteilung eignet sich gut zum Modellieren von Dingen wie Spielen. Damit das Spiel fair ist, müssen alle Ereignisse häufig die gleiche Wahrscheinlichkeit haben.

Im wirklichen Leben sind Verteilungen jedoch normalerweise komplizierter. Die Chancen sind nicht gleich, dass verschiedene Dinge passieren.

Zum Beispiel gibt es sehr wenige extrem kleine Leute und sehr wenige extrem große. Die meisten Menschen sind durchschnittlich groß, was bedeutet, dass die Größe der Menschen der Normalverteilung folgt. Wenn wir zufällige menschliche Höhen erzeugen müssen, reicht es nicht aus, eine zufällige Anzahl von Fuß zu erzeugen.

Glücklicherweise müssen wir das zugrunde liegende mathematische Modell nicht selbst implementieren. Wir müssen wissen, welche Distribution verwendet werden soll und wie sie konfiguriert werden muss , beispielsweise mithilfe statistischer Daten.

Die Apache Commons-Bibliothek bietet uns Implementierungen für verschiedene Distributionen. Implementieren wir damit die Normalverteilung:

private static final double MEAN_HEIGHT = 176.02; private static final double STANDARD_DEVIATION = 7.11; private static NormalDistribution distribution = new NormalDistribution(MEAN_HEIGHT, STANDARD_DEVIATION); 

Die Verwendung dieser API ist sehr einfach - die Beispielmethode zieht eine Zufallszahl aus der Verteilung:

public static double generateNormalHeight() { return distribution.sample(); }

Lassen Sie uns zum Schluss den Prozess umkehren:

public static double probabilityOfHeightBetween(double heightLowerExclusive, double heightUpperInclusive) { return distribution.probability(heightLowerExclusive, heightUpperInclusive); }

Als Ergebnis erhalten wir die Wahrscheinlichkeit, dass eine Person eine Größe zwischen zwei Grenzen hat. In diesem Fall die untere und die obere Höhe.

5. Schlussfolgerung

In diesem Artikel haben wir gelernt, wie zufällige Ereignisse generiert und die Wahrscheinlichkeit ihres Auftretens berechnet werden. Wir haben einheitliche und normale Verteilungen verwendet, um verschiedene Situationen zu modellieren.

Das vollständige Beispiel finden Sie auf GitHub.