API Generator

default_rng sebagai antarmuka angka acak modern.

Daftar isi

Topik ini membahas antarmuka pembangkitan angka acak modern pada NumPy yang berpusat pada fungsi np.random.default_rng() dan objek Generator. Cakupannya meliputi cara membuat Generator, metode utama untuk menghasilkan bilangan acak, konsep state yang tersimpan di dalam objek tersebut, serta alasan API ini menggantikan fungsi global warisan.

Masalah API global warisan#

NumPy dahulu menyediakan pembangkitan angka acak melalui fungsi-fungsi global seperti np.random.rand(), np.random.randn(), dan np.random.randint(). Fungsi-fungsi tersebut membaca dan mengubah satu state global yang digunakan bersama oleh seluruh bagian program. Akibatnya, urutan angka yang dihasilkan bergantung pada riwayat pemanggilan dari seluruh program, bukan hanya pada baris kode yang sedang dilihat. Menambahkan satu pemanggilan fungsi acak di tempat lain dapat menggeser seluruh angka berikutnya, sehingga hasil eksperimen sulit direproduksi.

State global juga tidak aman digunakan bersama oleh beberapa alur eksekusi (thread). Pada program paralel, dua alur yang bersamaan mengubah state yang sama dapat saling mengganggu urutannya. Atas dua alasan tersebut, dokumentasi NumPy merekomendasikan API modern berbasis Generator untuk semua kode baru.

API warisan yang dibangun di atas kelas RandomState tetap tersedia dan tidak akan dihapus. Perilakunya dibekukan demi kompatibilitas dengan kode lama, sehingga program yang sudah ada tetap menghasilkan angka yang sama seperti sebelumnya. Kode baru tidak lagi menggunakan API tersebut, dan sisa topik ini sepenuhnya menggunakan Generator.

Membuat Generator dengan default_rng#

Fungsi np.random.default_rng() membuat dan mengembalikan sebuah objek Generator. Parameter seed bersifat opsional dan menetapkan titik awal urutan angka. Objek yang sama dapat dipanggil berulang kali, dan setiap pemanggilan metodenya melanjutkan urutan yang sudah berjalan. Objek Generator inilah yang menggantikan peran fungsi global warisan, sehingga seluruh kebutuhan angka acak program diarahkan ke objek yang sama dan fungsi global tidak dipanggil lagi. Alur dari seed menuju array hasil dirangkum pada diagram berikut.

Alur pembangkitan angka acak NumPyseednilai awaldefault_rngGeneratoralgoritma PCG64metodearrayhasilrandom, integers, normal, choice
Alur dari seed menuju array hasil melalui objek Generator
python Membuat Generator dan mengambil dua bilangan
import numpy as np

rng = np.random.default_rng(seed=42)

print(type(rng))
print(rng.random())
print(rng.random())
text Keluaran
<class 'numpy.random._generator.Generator'>
0.7739560485559633
0.4388784397520523

Baris pertama keluaran menampilkan kelas lengkap objek yang dikembalikan. Dua pemanggilan rng.random() berikutnya menghasilkan bilangan yang berbeda karena setiap pemanggilan memajukan state di dalam Generator. Dengan seed yang sama, eksekusi yang berbeda menghasilkan bilangan yang persis sama. Keempat metode pada tabel di bawah mengembalikan array baru tanpa mengubah argumennya, sehingga pemanggilannya mudah dirangkai.

Metode utama objek Generator#

Objek Generator menyediakan satu metode untuk setiap distribusi yang didukung. Empat metode berikut mencakup kebutuhan pengambilan sampel yang paling umum.

MetodeHasil sampelParameter utama
randombilangan real seragam pada [0,1) [0, 1) size
integersbilangan bulat dari satu rentanglow, high, size
normalsampel distribusi normalloc, scale, size
choicesampel dari kumpulan nilai yang tersediaa, size, replace, p

Blok berikut memanggil keempat metode tersebut melalui satu Generator yang sama.

python Empat metode utama Generator
import numpy as np

rng = np.random.default_rng(seed=42)

print(rng.random(size=3))
print(rng.integers(low=1, high=7, size=5))
print(rng.normal(loc=0.0, scale=1.0, size=4))
print(rng.choice(["A", "B", "C", "D"], size=3, replace=False))
text Keluaran
[0.77395605 0.43887844 0.85859792]
[1 5 2 1 4]
[ 0.1278404  -0.31624259 -0.01680116 -0.85304393]
['D' 'C' 'B']

Pemanggilan random(size=3) menghasilkan tiga bilangan real seragam. Pemanggilan integers(low=1, high=7, size=5) menghasilkan lima bilangan bulat yang meniru lima lemparan dadu, dan batas atas 7 tidak ikut diambil. Pemanggilan normal menghasilkan sampel yang mengelompok di sekitar loc dengan sebaran scale. Terakhir, choice memilih tiga dari empat nilai tanpa pengembalian, sehingga tidak ada nilai yang muncul dua kali pada keluarannya.

State tersimpan dalam objek Generator#

State urutan angka tersimpan di dalam objek Generator, bukan di dalam fungsi yang dipanggil. Dua Generator yang dibuat dengan seed sama menghasilkan urutan yang identik, sedangkan urutan keduanya berjalan terpisah setelah objek dibuat. Blok berikut menunjukkan perilaku tersebut.

python Dua Generator dengan seed sama
import numpy as np

rng_a = np.random.default_rng(seed=42)
rng_b = np.random.default_rng(seed=42)

print(rng_a.random(size=3))
print(rng_b.random(size=3))
print(rng_a.random(size=3))
text Keluaran
[0.77395605 0.43887844 0.85859792]
[0.77395605 0.43887844 0.85859792]
[0.69736803 0.09417735 0.97562235]

Dua baris pertama keluaran identik karena kedua Generator dimulai dari seed yang sama. Baris ketiga adalah lanjutan urutan milik rng_a, dan nilainya berbeda dari dua baris sebelumnya karena state rng_a sudah maju tiga langkah. Perpindahan state pada rng_a tidak memengaruhi rng_b, sehingga urutan masing-masing objek berjalan mandiri. State hanya maju melalui metode milik objek itu sendiri, dan tidak ada jalur lain yang mengubahnya, sehingga tidak ada state tersembunyi yang digeser dari luar objek. Sifat inilah yang membuat satu Generator dapat diteruskan sebagai parameter fungsi: fungsi yang menerima Generator menjadi deterministik terhadap seed yang dipilih, sementara keacakuan bagian program lain tetap tidak tergeser.

Kesalahan umum#

Menganggap random() menerima parameter rentang seperti uniform. Metode random() hanya menghasilkan bilangan real pada [0,1) [0, 1) , dan argumen yang biasa diisi hanyalah size. Pemanggilan dengan kata kunci low atau high memicu TypeError, sebagaimana ditunjukkan blok berikut. Apabila rentang selain [0,1) [0, 1) diperlukan, gunakan metode uniform.

python Pemanggilan random dengan argumen rentang yang keliru
import numpy as np

rng = np.random.default_rng(seed=42)

try:
    rng.random(low=0.0, high=1.0)
except TypeError as e:
    print(f"{type(e).__name__}: {e}")
text Keluaran
TypeError: random() got an unexpected keyword argument 'low'

Membuat Generator baru di dalam fungsi tanpa seed pada setiap pemanggilan. Pola ini menghilangkan reproduktibilitas karena setiap pemanggilan memperoleh urutan yang berbeda. Gejala yang menyertainya adalah hasil yang berubah setiap fungsi dipanggil kembali, padahal masukannya sama. Buat Generator sekali di awal program, lalu teruskan objeknya sebagai parameter. Disiplin seeding dibahas lebih lanjut pada topik seeding modul ini.

Mengharapkan batas atas ikut diambil pada integers. Rentang integers(low, high) bersifat setengah terbuka, sehingga integers(1, 7) menghasilkan nilai 1 sampai 6. Konvensi ini memudahkan peniruan dadu, tetapi sering dianggap keliru oleh pembaca yang mengharapkan 7 ikut terambil. Keluaran dadu yang memuat nilai 0 merupakan tanda bahwa rentangnya tergeser satu. Gunakan endpoint=True apabila batas atas perlu disertakan.

Ringkasan#

  • np.random.default_rng(seed) membuat objek Generator yang menyimpan state urutan angkanya sendiri.
  • Metode random, integers, normal, dan choice mencakup kebutuhan sampel seragam real, bulat, normal, dan pemilihan nilai.
  • State yang tersimpan per objek membuat urutan setiap Generator berjalan mandiri dan dapat direproduksi melalui seed.
  • API warisan RandomState hanya dipertahankan untuk kode lama dan tidak digunakan pada kode baru.

Referensi#