Sandsynlighed i Java

1. Oversigt

I denne vejledning ser vi på et par eksempler på, hvordan vi kan implementere sandsynlighed med Java.

2. Simulering af grundlæggende sandsynlighed

For at simulere sandsynlighed i Java er det første, vi skal gøre, at generere tilfældige tal. Heldigvis giver Java os masser af tilfældige talgeneratorer.

I dette tilfælde bruger vi SplittableRandom klasse, fordi det giver tilfældighed i høj kvalitet og er relativt hurtig:

SplittableRandom tilfældig = ny SplittableRandom ();

Så er vi nødt til at generere et tal i et interval og sammenligne det med et andet nummer valgt fra det område. Hvert nummer i området har lige chance for at blive trukket. Da vi kender rækkevidden, ved vi sandsynligheden for at tegne vores valgte nummer. På den måde kontrollerer vi sandsynligheden:

boolsk sandsynligvis Falsk = random.nextInt (10) == 0

I dette eksempel trak vi tal fra 0 til 9. Derfor er sandsynligheden for at tegne 0 lig med 10%. Lad os nu få et tilfældigt tal og teste, om det valgte tal er lavere end det tegnede nummer:

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

Her trak vi tal fra 1 til 100. Chancen for, at vores tilfældige tal er mindre eller lig med 50 er nøjagtigt 50%.

3. Ensartet fordeling

Værdier, der genereres indtil dette tidspunkt, falder ind under den ensartede fordeling. Det betyder at hver begivenhed, for eksempel at kaste et nummer på en terning, har lige chance for at ske.

3.1. Påkald af en funktion med en given sandsynlighed

Lad os nu sige, at vi fra tid til anden vil udføre en opgave og kontrollere dens sandsynlighed. For eksempel driver vi et e-handelswebsted, og vi vil give 10% af vores brugere en rabat.

Lad os implementere en metode, der tager tre parametre: en leverandør, der skal påberåbes i nogle procentdele, en anden leverandør, der påberåbes i resten af ​​tilfældene, og sandsynligheden.

Først erklærer vi vores SplittableRandom som Doven ved hjælp af Vavr. På denne måde instantierer vi det kun én gang på en første anmodning:

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

Derefter implementerer vi sandsynlighedsstyringsfunktionen:

offentlig med sandsynlighed (leverandør positivCase, leverandør negativCase, int sandsynlighed) {SplittableRandom tilfældig = this.random.get (); hvis (random.nextInt (1, 101) <= sandsynlighed) {return positiveCase.get (); } andet {return negativeCase.get (); }}

3.2. Prøveudtagnings sandsynlighed med Monte Carlo-metoden

Lad os vende den proces, vi så i det foregående afsnit. For at gøre det måler vi sandsynligheden ved hjælp af Monte Carlo-metoden. Det genererer et stort volumen af ​​tilfældige begivenheder og tæller, hvor mange af dem der opfylder den angivne tilstand. Det er nyttigt, når sandsynligheden er vanskelig eller umulig at beregne analytisk.

For eksempel, hvis vi ser på seks-sidede terninger, ved vi, at sandsynligheden for at kaste et bestemt antal er 1/6. Men hvis vi har en mystisk terning med et ukendt antal sider, ville det være svært at fortælle, hvad sandsynligheden ville være. I stedet for at analysere terningerne kunne vi bare kaste den adskillige gange og tælle, hvor mange gange visse begivenheder finder sted.

Lad os se, hvordan vi kan implementere denne tilgang. Først prøver vi at generere nummeret 1 med sandsynligheden på 10% en million gange og tælle dem:

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

Derefter vil summen af ​​genererede tal divideret med antallet af prøver være en tilnærmelse af sandsynligheden for begivenheden:

int monteCarloProbability = (howManyTimesInvoked * 100) / numberOfSamples; 

Husk, at den beregnede sandsynlighed er tilnærmet. Jo højere antallet af prøver, jo bedre er tilnærmelsen.

4. Andre distributioner

Den ensartede distribution fungerer godt til modellering af ting som spil. For at spillet skal være retfærdigt, skal alle begivenheder ofte have den samme sandsynlighed for at det sker.

I det virkelige liv er distributioner normalt mere komplicerede. Chancerne er ikke lige for forskellige ting at ske.

For eksempel er der meget få ekstremt korte mennesker og meget få ekstremt høje. De fleste mennesker har en gennemsnitlig højde, hvilket betyder, at menneskers højde følger normalfordelingen. Hvis vi har brug for at generere tilfældige menneskelige højder, er det ikke tilstrækkeligt at generere et tilfældigt antal fødder.

Heldigvis behøver vi ikke selv at implementere den underliggende matematiske model. Vi har brug for at vide, hvilken distribution vi skal bruge, og hvordan vi konfigurerer denf.eks. ved hjælp af statistiske data.

Apache Commons-biblioteket giver os implementeringer til flere distributioner. Lad os implementere normalfordelingen med det:

privat statisk endelig dobbelt MEAN_HEIGHT = 176.02; privat statisk endelig dobbelt STANDARD_DEVIATION = 7.11; privat statisk NormalDistribution distribution = ny NormalDistribution (MEAN_HEIGHT, STANDARD_DEVIATION); 

Brug af denne API er meget ligetil - prøvemetoden trækker et tilfældigt tal fra fordelingen:

offentlig statisk dobbelt generereNormalHøjde () {return distribution.sample (); }

Lad os endelig vende processen om:

offentlig statisk dobbelt sandsynlighedOfHeightBetween (dobbelt heightLowerExclusive, dobbelt heightUpperInclusive) {return distribution.probability (heightLowerExclusive, heightUpperInclusive); }

Som et resultat får vi sandsynligheden for, at en person har en højde mellem to grænser. I dette tilfælde er den nedre og den øverste højde.

5. Konklusion

I denne artikel lærte vi, hvordan man genererer tilfældige begivenheder, og hvordan man beregner sandsynligheden for, at de sker. Vi brugte ensartede og normale distributioner til at modellere forskellige situationer.

Det fulde eksempel kan findes på GitHub.