Model probabilitas pada Bagian 1 baru berupa aturan; Monte Carlo baru bergerak ketika aturan itu diberi sampel acak dalam jumlah besar. Kita memakai satu disiplin yang sama untuk seluruh proyek: setiap blok membentuk generator dengan np.random.default_rng(42) — API modern yang dibahas pada Chapter default_rng dan Generator. Seed 42 yang selalu sama membuat deret angka yang dibangkitkan ikut sama, sehingga setiap tabel output proyek ini dapat direproduksi ulang tanpa sedikit pun perbedaan (lihat Chapter Reproducibility dan Random Seed).

Tiga jenis sampel yang kita bangkitkan mengikuti peta model:

ModelMethod GeneratorBentuk sampel
Lingkaran dalam persegirng.random()koordinat (x, y) uniform
Dua dadurng.integers(1, 7)matriks n × 2 berisi muka 1–6
Integral sin(x)rng.random()bilangan uniform di [0, π)

Titik Uniform di Dalam Persegi #

Untuk model lingkaran, kita perlu titik yang tersebar merata. Method rng.random() menghasilkan bilangan uniform pada [0, 1) — perilakunya dibahas tuntas pada Chapter Uniform Distribution. Kita mulai dari lima titik agar mudah diperiksa mata, lalu langsung memasang pemeriksaan batas dengan np.all:

python
import numpy as np

rng = np.random.default_rng(42)
x = rng.random(5)
y = rng.random(5)
print("x =", np.round(x, 4))
print("y =", np.round(y, 4))
print("Semua x dalam [0, 1) :", np.all((x >= 0.0) & (x < 1.0)))
print("Semua y dalam [0, 1) :", np.all((y >= 0.0) & (y < 1.0)))

Output yang Dihasilkan:

text
x = [0.774  0.4389 0.8586 0.6974 0.0942]
y = [0.9756 0.7611 0.7861 0.1281 0.4504]
Semua x dalam [0, 1) : True
Semua y dalam [0, 1) : True

Mari kita bedah:

  1. Baris 3-5: satu Generator ber-seed 42 membangkitkan dua array lima elemen; deretnya pasti sama di setiap eksekusi.
  2. Baris 6-7 (np.round(x, 4)): pembulatan hanya untuk tampilan; nilai di memori tetap presisi penuh, dan hal ini penting saat sampel dipakai menghitung.
  3. Baris 8-9 (np.all(...)): mask boolean (x >= 0.0) & (x < 1.0) menguji tiap elemen, lalu np.all memastikan tidak ada satu pun titik di luar [0, 1) — pemeriksaan kewarasan sebelum sampel dipercaya.

Pasangan Dadu dengan integers #

Sampel dadu dibangkitkan dengan rng.integers(1, 7, size=(5, 2)). Ingat aturan pada Chapter Random Integer dan Sampling: batas atas bersifat eksklusif, sehingga integers(1, 7) menghasilkan muka 1 sampai 6. Argumen size=(5, 2) membuat setiap baris mewakili satu lemparan dua dadu sekaligus:

python
import numpy as np

rng = np.random.default_rng(42)
lemparan = rng.integers(1, 7, size=(5, 2))
print(lemparan)
print("Nilai terkecil :", lemparan.min(), "| terbesar:", lemparan.max())
print("Semua nilai dalam 1..6 :", np.all((lemparan >= 1) & (lemparan <= 6)))

Output yang Dihasilkan:

text
[[1 5]
 [4 3]
 [3 6]
 [1 5]
 [2 1]]
Nilai terkecil : 1 | terbesar: 6
Semua nilai dalam 1..6 : True

Penjelasan tiap baris:

  1. Baris 4 (size=(5, 2)): matriks 5×2; kolom pertama adalah dadu pertama, kolom kedua dadu kedua — lima lemparan berpasangan dalam satu panggilan.
  2. Baris 6 (lemparan.min() dan lemparan.max()): nilai terkecil 1 dan terbesar 6, sesuai ruang nilai yang diharapkan.
  3. Baris 7 (np.all(...)): pemeriksaan batas yang sama seperti titik uniform; hasil True menandakan tidak ada muka di luar 1..6.

Distribusi Frekuensi 10.000 Lemparan #

Lima lemparan terlalu kecil untuk melihat pola. Kini kita naik ke n = 10.000 lemparan, jumlahkan tiap pasangan dengan sum(axis=1) (lihat Chapter Operasi Berdasarkan Axis), lalu hitung frekuensi tiap nilai jumlah dengan np.unique(..., return_counts=True) seperti pada Chapter Counting dan Frekuensi:

python
import numpy as np

rng = np.random.default_rng(42)
n = 10_000
dadu = rng.integers(1, 7, size=(n, 2))
jumlah = dadu.sum(axis=1)
nilai, frekuensi = np.unique(jumlah, return_counts=True)
for v, f in zip(nilai, frekuensi):
    print(f"jumlah = {v:>2} : {f:>4} kali ({f / n:.4f})")

Output yang Dihasilkan:

text
jumlah =  2 :  279 kali (0.0279)
jumlah =  3 :  575 kali (0.0575)
jumlah =  4 :  906 kali (0.0906)
jumlah =  5 : 1079 kali (0.1079)
jumlah =  6 : 1408 kali (0.1408)
jumlah =  7 : 1645 kali (0.1645)
jumlah =  8 : 1351 kali (0.1351)
jumlah =  9 : 1109 kali (0.1109)
jumlah = 10 :  858 kali (0.0858)
jumlah = 11 :  514 kali (0.0514)
jumlah = 12 :  276 kali (0.0276)

Mari kita telaah:

  1. Baris 6 (dadu.sum(axis=1)): penjumlahan sepanjang axis 1 merangkum tiap baris menjadi satu angka — jumlah dua dadu untuk lemparan tersebut; hasilnya array 1-D berisi 10.000 nilai.
  2. Baris 7 (np.unique(..., return_counts=True)): np.unique mengurutkan nilai unik (2 sampai 12) dan mengembalikan frekuensi kemunculannya secara sejajar.
  3. Baris 8-9: format {v:>2} dan {f:>4} meratakan kolom ke kanan, dan {f / n:.4f} mencetak proporsi empat desimal; keduanya membuat tabel 11 baris mudah dibandingkan.

Pola distribusinya terlihat jelas: frekuensi memuncak di jumlah 7 (1645 kali) dan menurun simetris ke ujung 2 dan 12 — sesuai bentuk model peluang pada Bagian 1.

Membandingkan Sampel dengan Model #

Terakhir, kita sorot hanya jumlah 7 dan bandingkan langsung dengan ekspektasi teoretis 6/36 × n:

python
import numpy as np

rng = np.random.default_rng(42)
n = 10_000
jumlah = rng.integers(1, 7, size=(n, 2)).sum(axis=1)
frekuensi_7 = np.count_nonzero(jumlah == 7)
print("Frekuensi jumlah = 7 :", frekuensi_7)
print("Proporsi empiris     :", frekuensi_7 / n)
print("Ekspektasi teoretis  :", round(6 / 36 * n, 2), "kali")
print("Selisih              :", round(frekuensi_7 - 6 / 36 * n, 2))

Output yang Dihasilkan:

text
Frekuensi jumlah = 7 : 1645
Proporsi empiris     : 0.1645
Ekspektasi teoretis  : 1666.67 kali
Selisih              : -21.67

Penjelasan singkat:

  1. Baris 5: rantai panggilan yang sama seperti blok sebelumnya; karena seed 42 dan ukuran sampel juga sama, deret dadunya identik dan frekuensinya kembali 1645.
  2. Baris 7-8: frekuensi dan proporsi empiris dicetak — 0.1645 melawan 0.1667 pada model.
  3. Baris 9-10: selisih -21.67 lemparan, sekitar 1.3% dari ekspektasi; untuk n = 10.000, angka sekecil itu wajar.

Sampel uniform, pasangan dadu, dan distribusi frekuensinya kini siap. Pada Bagian 3, ukuran sampel dinaikkan ke 100.000 dan ketiga estimator dieksekusi penuh.