Banyak persoalan pemrograman tidak berjalan dengan angka yang pasti: berapa peluang pelanggan datang dalam satu menit, sampel mana yang diambil dari dataset, urutan soal mana yang tampil pada kuis, atau nilai awal apa yang diberikan pada bobot sebuah model machine learning. Modul numpy.random adalah bagian NumPy yang menyediakan pembangkit angka acak untuk kebutuhan semacam itu, lengkap dengan hasil berbentuk array yang cepat dihitung.

Penting dipahami sejak awal: angka yang dihasilkan modul ini sebenarnya pseudorandom. Nilainya ditentukan oleh algoritme yang deterministik, tetapi deretnya lulus uji statistik keacakan sehingga layak dipakai sebagai angka acak. Sifat deterministik ini justru menguntungkan: dengan menetapkan seed (titik awal urutan), kita dapat mengulang hasil yang sama persis — fondasi dari reproducibility.

Bab ini memetakan cakupan section Bilangan Acak:

  • Dua API dalam numpy.random: API lama berbasis fungsi global dan API modern berbasis objek Generator.
  • Struktur dua lapis pembangkit angka: BitGenerator dan Generator.
  • Contoh pertama pemakaian Generator beserta sifat urutannya.

Dua API dalam numpy.random #

Hingga NumPy 1.17, satu-satunya cara memakai numpy.random adalah fungsi global: program memanggil np.random.seed(42) untuk menyetel keadaan pembangkit, lalu menarik angka lewat np.random.rand(), np.random.randint(), dan kawan-kawannya. Semua fungsi tersebut berbagi satu keadaan global yang tersembunyi, sehingga bagian program yang berbeda saling memengaruhi urutan angka satu sama lain. NumPy 1.17 memperkenalkan API modern berbasis objek Generator yang dibuat melalui np.random.default_rng(). API lama tetap tersedia demi kompatibilitas, tetapi dokumentasi NumPy menyarankan API modern untuk kode baru.

Tabel berikut memetakan fungsi lama ke padanannya pada objek Generator:

KebutuhanAPI lama (fungsi global)API modern (Generator)
Menyetel sumber acak ber-seednp.random.seed(42)rng = np.random.default_rng(42)
Uniform pada [0, 1)np.random.rand(3)rng.random(3)
Uniform pada rentang a sampai bnp.random.uniform(a, b)rng.uniform(a, b)
Bilangan bulat acaknp.random.randint(0, 10)rng.integers(0, 10)
Distribusi normalnp.random.randn(3)rng.normal(size=3)
Sampling anggota arraynp.random.choice(data)rng.choice(data)

Perbedaan terpenting bukan pada nama method, melainkan pada pemilikan keadaan. Pada API lama, np.random.seed() menyetel keadaan global yang dipakai seluruh program; pada API modern, setiap objek Generator menyimpan keadaannya sendiri sehingga dapat diteruskan antar fungsi tanpa saling mengganggu.

Generator dan BitGenerator #

API modern bekerja dua lapis. Lapis bawah adalah BitGenerator: mesin yang menghasilkan deretan bit mentah yang acak secara statistik. Lapis atas adalah Generator: penerjemah yang mengubah bit mentah menjadi angka sesuai distribusi yang kita minta — integer, uniform, normal, dan lainnya. Alur pembuatan generator modern dapat dirangkum:

  1. np.random.default_rng(seed) membuat objek Generator.
  2. Objek Generator tersebut ditopang BitGenerator bawaan, yaitu PCG64.
  3. Setiap pemanggilan method (integers, random, normal, …) meminta bit mentah dari BitGenerator, lalu mengubahnya menjadi angka berdistribusi yang diminta.
LapisanTugasContoh
BitGeneratormenghasilkan bit mentahPCG64 (default), MT19937, Philox, SFC64
Generatormengubah bit menjadi angka berdistribusi tertentuintegers, random, normal, choice

Pemisahan lapisan membuat kita dapat mengganti mesin pembangkit tanpa mengubah cara pemanggilan distribusi — detail yang jarang dibutuhkan pemula, tetapi berguna ketika hasil riset harus dicocokkan dengan mesin tertentu.

Contoh Pertama Generator #

Kita buat sebuah Generator ber-seed lalu menarik tiga jenis angka sekaligus:

python
import numpy as np

rng = np.random.default_rng(42)
print(rng.integers(0, 10, size=5))
print(rng.random(3))
print(rng.normal(loc=27.5, scale=2.0, size=3))

Output yang Dihasilkan:

text
[0 7 6 4 4]
[0.69736803 0.09417735 0.97562235]
[27.75568081 26.86751482 27.46639768]

Bedah baris demi baris:

  1. Baris 3 (rng = np.random.default_rng(42)): fungsi default_rng membuat objek Generator yang ditopang BitGenerator PCG64. Angka 42 adalah seed, yaitu titik awal urutan — pembahasannya lengkap pada Chapter Reproducibility dan Random Seed.
  2. Baris 4 (rng.integers(0, 10, size=5)): lima bilangan bulat acak pada rentang 0 sampai 9. Batas atas bersifat eksklusif, aturan yang dibedah tuntas pada Chapter Random Integer dan Sampling.
  3. Baris 5 (rng.random(3)): tiga angka pecahan berdistribusi uniform pada interval [0, 1) — topik utama Chapter Uniform Distribution.
  4. Baris 6 (rng.normal(...)): tiga angka pecahan berdistribusi normal dengan rata-rata 27.5 dan simpangan baku 2.0, layaknya fluktuasi suhu ruangan. Chapter Normal Distribution membahas distribusi ini lebih dalam.

Satu Generator, Satu Urutan #

Satu objek Generator memegang satu urutan angka. Setiap pemanggilan method melanjutkan urutan tersebut, bukan mengulangnya dari awal:

python
import numpy as np

rng = np.random.default_rng(0)
print(rng.integers(0, 10, size=4))
print(rng.integers(0, 10, size=4))
print(rng.integers(0, 10, size=4))

Output yang Dihasilkan:

text
[8 6 5 2]
[3 0 0 0]
[1 8 6 9]

Ketiga pemanggilan identik secara kode, tetapi ketiga hasilnya berbeda: generator sudah maju ke posisi berikutnya di dalam urutannya setiap kali angka ditarik. Konsekuensinya, urutan pemanggilan method ikut menentukan nilai yang keluar. Jika hasil yang sama persis dibutuhkan di setiap eksekusi program, alatnya adalah seed — bahasan utama Chapter Reproducibility dan Random Seed.