Probabilitas di Jawa

1. Ikhtisar

Dalam tutorial ini, kita akan melihat beberapa contoh bagaimana kita dapat mengimplementasikan probabilitas dengan Java.

2. Mensimulasikan Probabilitas Dasar

Untuk mensimulasikan probabilitas di Java, hal pertama yang perlu kita lakukan adalah membuat bilangan acak. Untungnya, Java memberi kita banyak generator angka acak .

Dalam kasus ini, kita akan menggunakan kelas SplittableRandom karena memberikan keacakan berkualitas tinggi dan relatif cepat:

SplittableRandom random = new SplittableRandom();

Kemudian kita perlu membuat angka dalam satu rentang dan membandingkannya dengan angka lain yang dipilih dari rentang itu. Setiap angka dalam jangkauan memiliki peluang yang sama untuk ditarik. Seperti yang kita ketahui jangkauannya, kita tahu kemungkinan menggambar angka yang kita pilih. Dengan cara itu kami mengontrol probabilitas :

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

Dalam contoh ini, kami menggambar angka dari 0 hingga 9. Oleh karena itu, probabilitas menggambar 0 sama dengan 10%. Sekarang, mari kita dapatkan nomor acak dan uji apakah nomor yang dipilih lebih rendah dari yang ditarik:

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

Di sini, kami menarik angka dari 1 hingga 100. Kemungkinan angka acak kami lebih kecil atau sama dengan 50 adalah tepat 50%.

3. Distribusi Seragam

Nilai yang dihasilkan hingga saat ini termasuk dalam distribusi seragam. Ini berarti bahwa setiap peristiwa, misalnya melempar beberapa angka pada dadu, memiliki peluang yang sama untuk terjadi.

3.1. Memanggil Fungsi dengan Probabilitas yang Diberikan

Sekarang, katakanlah kita ingin melakukan tugas dari waktu ke waktu dan mengontrol kemungkinannya. Misalnya, kami mengoperasikan situs e-niaga dan kami ingin memberikan diskon kepada 10% pengguna kami.

Untuk melakukannya, mari kita terapkan metode yang akan mengambil tiga parameter: pemasok yang akan dipanggil dalam beberapa persentase kasus, pemasok kedua untuk dipanggil dalam kasus lainnya, dan probabilitas.

Pertama, kami menyatakan SplittableRandom kami sebagai Malas menggunakan Vavr. Dengan cara ini kami hanya akan membuat instance sekali, pada permintaan pertama:

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

Kemudian, kami akan menerapkan fungsi pengelolaan probabilitas:

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. Peluang Sampling Dengan Metode Monte Carlo

Mari kita balikkan proses yang kita lihat di bagian sebelumnya. Untuk melakukannya, kami akan mengukur probabilitas menggunakan metode Monte Carlo. Ini menghasilkan sejumlah besar peristiwa acak dan menghitung berapa banyak dari mereka yang memenuhi kondisi yang disediakan. Ini berguna ketika probabilitasnya sulit atau tidak mungkin untuk dihitung secara analitik.

Misalnya, jika kita melihat dadu bersisi enam, kita tahu bahwa probabilitas untuk melempar angka tertentu adalah 1/6. Tetapi, jika kita memiliki dadu misterius dengan jumlah sisi yang tidak diketahui, akan sulit untuk mengatakan berapa kemungkinannya. Alih-alih menganalisis dadu, kami hanya bisa melempar berkali-kali dan menghitung berapa kali peristiwa tertentu terjadi.

Mari kita lihat bagaimana kita dapat menerapkan pendekatan ini. Pertama, kita akan mencoba menghasilkan angka 1 dengan probabilitas 10% untuk satu juta kali dan menghitungnya:

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

Kemudian, jumlah bilangan yang dihasilkan dibagi dengan jumlah sampel akan menjadi perkiraan probabilitas kejadian:

int monteCarloProbability = (howManyTimesInvoked * 100) / numberOfSamples; 

Ingatlah bahwa, probabilitas yang dihitung didekati. Semakin tinggi jumlah sampel, semakin baik perkiraannya.

4. Distribusi Lainnya

Distribusi seragam berfungsi dengan baik untuk memodelkan hal-hal seperti game. Agar permainan menjadi adil, semua peristiwa sering kali harus memiliki kemungkinan yang sama untuk terjadi.

Namun, dalam kehidupan nyata, distribusi biasanya lebih rumit. Peluangnya tidak sama untuk berbagai hal terjadi.

For example, there are very few extremely short people and very few extremely tall. Most people are of average height, which means that the height of people follows the normal distribution. If we need to generate random human heights, then it won't suffice to generate a random number of feet.

Fortunately, we don't need to implement the underlying mathematical model ourselves. We need to know which distribution to use and how to configure it, for example, using statistical data.

The Apache Commons library provides us with implementations for several distributions. Let's implement the normal distribution with it:

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

Using this API is very straightforward – the sample method draws a random number from the distribution:

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

Finally, let's invert the process:

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

Hasilnya, kita akan mendapatkan probabilitas seseorang memiliki ketinggian di antara dua batas. Dalam hal ini, ketinggian bawah dan atas.

5. Kesimpulan

Dalam artikel ini, kita belajar bagaimana membuat kejadian acak dan bagaimana menghitung kemungkinan kejadiannya. Kami menggunakan distribusi seragam dan normal untuk memodelkan situasi yang berbeda.

Contoh lengkapnya dapat ditemukan di GitHub.