자바의 확률

1. 개요

이 자습서에서는 Java로 확률을 구현할 수있는 방법에 대한 몇 가지 예를 살펴 보겠습니다.

2. 기본 확률 시뮬레이션

자바에서 확률을 시뮬레이션하기 위해 가장 먼저해야 할 일은 난수를 생성하는 것입니다. 다행히 Java는 많은 난수 생성기를 제공 합니다.

이 경우 고품질 임의성을 제공하고 상대적으로 빠르기 때문에 SplittableRandom 클래스를 사용합니다 .

SplittableRandom random = new SplittableRandom();

그런 다음 범위에서 숫자를 생성하고 해당 범위에서 선택한 다른 숫자와 비교해야합니다. 범위의 모든 숫자는 똑같이 그려 질 가능성이 있습니다. 범위를 알기 때문에 선택한 숫자를 그릴 확률을 알고 있습니다. 그런 식으로 우리는 확률을 제어합니다 .

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

이 예에서는 0에서 9까지의 숫자를 그렸습니다. 따라서 0을 그릴 확률은 10 %와 같습니다. 이제 난수를 가져 와서 선택한 숫자가 그려진 숫자보다 낮은 지 테스트 해 봅시다.

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

여기서 우리는 1에서 100까지의 숫자를 그렸습니다. 임의의 숫자가 50보다 작거나 같을 확률은 정확히 50 %입니다.

3. 균일 한 분포

이 시점까지 생성 된 값은 균등 분포에 속합니다. 이것은 예를 들어 주사위에서 어떤 숫자를 굴리는 것과 같은 모든 이벤트가 발생할 확률이 동일하다는 것을 의미합니다 .

3.1. 주어진 확률로 함수 호출

이제 우리가 때때로 작업을 수행하고 그 확률을 제어하고 싶다고 가정 해 보겠습니다. 예를 들어, 우리는 전자 상거래 사이트를 운영하고 있으며 사용자의 10 %에게 할인을 제공하려고합니다.

이를 위해 세 가지 매개 변수를 사용하는 메서드를 구현해 보겠습니다. 일부 경우에 호출 할 공급자, 나머지 경우에 호출 할 두 번째 공급자, 확률입니다.

첫째, 우리는 우리의 선언 SplittableRandom 같은 게으른가 Vavr를 사용합니다. 이렇게하면 첫 번째 요청에서 한 번만 인스턴스화합니다.

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

그런 다음 확률 관리 기능을 구현합니다.

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. Monte Carlo 방법을 사용한 샘플링 확률

이전 섹션에서 본 과정을 반대로 해보겠습니다. 이를 위해 Monte Carlo 방법을 사용하여 확률을 측정합니다. 대량의 무작위 이벤트를 생성하고 제공된 조건을 충족하는 이벤트의 수를 계산합니다. 확률이 분석적으로 계산하기 어렵거나 불가능할 때 유용합니다.

예를 들어 6면 주사위를 보면 특정 숫자를 굴릴 확률이 1/6이라는 것을 알 수 있습니다. 하지만 변의 수를 알 수없는 신비한 주사위가 있다면 확률이 얼마인지 알기 어려울 것입니다. 주사위를 분석하는 대신 여러 번 굴려서 특정 이벤트가 발생하는 횟수를 계산할 수 있습니다.

이 접근 방식을 어떻게 구현할 수 있는지 살펴 보겠습니다. 먼저, 10 % 확률로 백만 번의 숫자 1을 생성하고 세어 보겠습니다.

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

그런 다음 생성 된 수의 합계를 샘플 수로 나눈 값이 이벤트 확률의 근사치가됩니다.

int monteCarloProbability = (howManyTimesInvoked * 100) / numberOfSamples; 

계산 된 확률은 근사치입니다. 샘플 수가 많을수록 근사치가 더 좋아집니다.

4. 기타 배포

균일 분포는 게임과 같은 모델링에 적합합니다. 게임이 공정 해지려면 모든 이벤트가 동일한 발생 확률을 가져야하는 경우가 많습니다.

그러나 실제 생활에서는 일반적으로 배포가 더 복잡합니다. 다른 일이 일어날 확률은 같지 않습니다.

예를 들어, 극히 키가 작은 사람은 거의없고 키가 큰 사람은 거의 없습니다. 대부분의 사람들은 평균 키이며, 이는 사람들의 키가 정규 분포를 따른다는 것을 의미합니다. 임의의 인간 높이를 생성해야하는 경우 임의의 피트 수를 생성하는 것으로는 충분하지 않습니다.

다행스럽게도 기본 수학적 모델을 직접 구현할 필요는 없습니다. 예를 들어 통계 데이터 를 사용하여 사용할 배포 및 구성 방법을 알아야 합니다.

Apache Commons 라이브러리는 여러 배포판에 대한 구현을 제공합니다. 이것으로 정규 분포를 구현해 보겠습니다.

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); 

이 API를 사용하는 것은 매우 간단합니다. 샘플 메서드는 분포에서 임의의 숫자를 가져옵니다.

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

마지막으로 프로세스를 뒤집어 보겠습니다.

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

결과적으로 우리는 사람이 두 경계 사이의 키를 가질 확률을 얻습니다. 이 경우 낮은 높이와 높은 높이입니다.

5. 결론

이 기사에서는 랜덤 이벤트를 생성하는 방법과 이벤트 발생 확률을 계산하는 방법을 배웠습니다. 다양한 상황을 모델링하기 위해 균일 분포와 정규 분포를 사용했습니다.

전체 예제는 GitHub에서 찾을 수 있습니다.