Mengacak urutan data adalah kebutuhan rutin: mengocok kartu, menomori ulang soal ujian, atau memecah dataset menjadi train dan test dengan urutan yang tercampur. Generator menyediakan dua method untuk itu — permutation() dan shuffle(). Keduanya menghasilkan urutan acak yang sama efektifnya, tetapi berbeda cara menanganannya: satu mengembalikan salinan, satu mengubah array asli.
Perbedaan copy versus in-place sudah pernah disinggung pada Chapter View vs Copy dalam konteks slicing. Di bab ini perbedaan yang sama muncul lagi dalam bentuk method acak, dan pilihan yang salah bisa membuat data asli berubah tanpa sengaja.
permutation: Salinan yang Teracak #
Method rng.permutation(x) menerima array x dan mengembalikan array baru berisi elemen yang sama dengan urutan teracak. Jika argumennya bilangan bulat n, method menganggapnya sebagai arange(n) — sehingga dua bentuk pemanggilan ini ekuivalen:
import numpy as np
rng = np.random.default_rng(42)
a = rng.permutation(5)
rng = np.random.default_rng(42)
b = rng.permutation(np.arange(5))
print(a)
print(b)
print(np.array_equal(a, b))Output yang Dihasilkan:
[4 2 3 1 0]
[4 2 3 1 0]
TrueBaris a = rng.permutation(5) menghasilkan arange(5) yang diacak, yaitu [0 1 2 3 4] yang urutannya ditukar menjadi [4 2 3 1 0]. Dengan seed yang sama, rng.permutation(np.arange(5)) menghasilkan susunan yang persis identik — bukti bahwa permutation(5) hanyalah jalan pintas untuk permutation(np.arange(5)).
Sekarang bagian terpenting: array asli tidak ikut berubah.
import numpy as np
rng = np.random.default_rng(42)
x = np.arange(6)
y = rng.permutation(x)
print("Salinan teracak:", y)
print("Asli :", x)
print("Berbagi memori :", np.shares_memory(x, y))Output yang Dihasilkan:
Salinan teracak: [3 2 5 4 1 0]
Asli : [0 1 2 3 4 5]
Berbagi memori : Falsenp.shares_memory mengembalikan False — y menempati memori sendiri, sehingga mengubah y ke depannya tidak akan memengaruhi x sedikit pun.
shuffle: Mengubah Array Langsung #
Method rng.shuffle(x) bekerja in-place: urutan x langsung ditukar di memori aslinya, dan method mengembalikan None.
import numpy as np
rng = np.random.default_rng(42)
x = np.arange(6)
kopi_x = x.copy()
rng.shuffle(x)
print("Sebelum :", kopi_x)
print("Sesudah :", x)
print("Nilai kembali shuffle:", rng.shuffle(np.arange(3)))Output yang Dihasilkan:
Sebelum : [0 1 2 3 4 5]
Sesudah : [3 2 5 4 1 0]
Nilai kembali shuffle: NoneBedah baris demi baris:
- Baris 5 (
kopi_x = x.copy()): salinan dibuat sebelum shuffle hanya untuk keperluan pembanding di output; tanpa salinan, urutan asli sudah tidak bisa ditampilkan lagi. - Baris 6 (
rng.shuffle(x)): method menukar elemenxlangsung di memori yang sama; array asli berubah menjadi[3 2 5 4 1 0]. - Baris 9: pemanggilan
rng.shuffle(np.arange(3))mencetakNone— bukti bahwashuffle()tidak mengembalikan array baru.
Perhatikan urutan [3 2 5 4 1 0]: dengan seed 42 yang sama, hasilnya identik dengan permutation(x) pada contoh sebelumnya. Di dalamnya, permutation() memang menyalin array lalu menjalankan shuffle pada salinan tersebut — bedanya hanya di mana hasil berhenti: pada salinan yang dikembalikan, atau pada array aslinya.
Ringkas perbedaannya:
| Aspek | permutation | shuffle |
|---|---|---|
| Argumen | array, atau int n (setara arange(n)) | array; int tidak diterima |
| Array asli | tidak berubah | urutannya langsung ditukar |
| Nilai kembali | salinan array yang sudah teracak | None |
| Pemakaian aman | simpan hasil ke variabel baru | hasil memang di array itu sendiri |
Contoh: Mengocok Setumpuk Kartu #
Contoh penerapan yang utuh: 52 kartu dibentuk dari 13 angka × 4 suit, diacak sekali, lalu lima kartu teratas diambil sebagai pembagian pertama:
import numpy as np
rng = np.random.default_rng(7)
angka = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"]
suit = ["Hati", "Wajik", "Keriting", "Sekop"]
deck = np.array([f"{k}-{s}" for s in suit for k in angka])
rng.shuffle(deck)
print(deck[:5])
print(deck.shape)Output yang Dihasilkan:
['J-Hati' '8-Sekop' 'A-Keriting' 'J-Keriting' 'J-Sekop']
(52,)Bedah baris demi baris:
- Baris 6 (
deck = np.array([...])): list comprehension menyusun 52 string dengan formatangka-suit, misalnyaJ-Hatiuntuk Jack hati;np.arraymengubahnya menjadi array 1-D berisi 52 elemen. - Baris 7 (
rng.shuffle(deck)): seluruh tumpukan diacak in-place; karenadeckmemang dibuat untuk dikocok, tidak ada salinan yang dibutuhkan. - Baris 8 (
print(deck[:5])): lima kartu pertama hasil kocokan, tetap berurutan sesuai posisi mereka setelah shuffle.
Untuk mengulang kocokan yang sama persis di lain eksekusi, cukup tetapkan seed yang sama seperti pada Chapter Reproducibility dan Random Seed.