Fancy indexing adalah pengindeksan dengan array integer sebagai indeks, sehingga banyak elemen dapat diambil sekaligus dalam satu penulisan dengan urutan bebas. Topik ini membahas notasi dasarnya, pengurutan ulang baris dan indeks berpasangan pada array dua dimensi, pengambilan sampel acak yang dapat direproduksi, serta sifat hasilnya, yaitu selalu berupa salinan baru.
Mengindeks dengan array integer#
Pada fancy indexing, daftar posisi yang ingin diambil dituliskan sebagai array integer di dalam kurung siku, misalnya a[[0, 2, 4]]. Urutan hasil mengikuti urutan daftar indeks, dan satu indeks boleh muncul lebih dari satu kali sehingga satu elemen dapat dimunculkan berulang pada hasil. Panjang hasil sama dengan panjang array indeksnya, bukan panjang array sumbernya.
import numpy as np
a = np.array([40, 10, 70, 20, 90])
print(a[[0, 2, 4]])
print(a[[3, 1, 3, 1]])[40 70 90]
[20 10 20 10]Pemanggilan pertama mengambil elemen pada indeks 0, 2, dan 4 sehingga menghasilkan [40 70 90]. Pemanggilan kedua menunjukkan dua kemampuan yang tidak dimiliki slicing, yaitu indeks yang tidak berurutan dan indeks yang berulang, sehingga satu array empat elemen dapat disusun hanya dari dua nilai sumber. Pola ini menjadi dasar untuk menyusun ulang data dengan urutan apa pun.
Istilah fancy hanya menandai bahwa indeksnya berupa array, bukan bilangan tunggal, dan tidak ada aturan baru yang menyertainya. Indeks negatif tetap diterima, sehingga a[[-1, 0]] mengambil elemen terakhir terlebih dahulu, lalu elemen pertama. Daftar Python biasa juga diterima NumPy dan dikonversi menjadi array secara internal, sehingga penulisan a[[0, 2]] dan a[np.array([0, 2])] memberikan hasil yang sama.
Pengurutan ulang baris dan indeks berpasangan#
Pada array dua dimensi, fancy indexing dengan satu array integer bekerja pada sumbu baris dan menyusun baris-baris terpilih mengikuti urutan indeks yang diberikan. Bentuk a[[2, 0, 1]] mengambil baris ketiga terlebih dahulu, kemudian baris pertama, lalu baris kedua, sehingga seluruh urutan baris dapat diputar tanpa perulangan.
import numpy as np
a = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
print(a[[2, 0, 1]])[[7 8 9]
[1 2 3]
[4 5 6]]Apabila dua array integer dituliskan dalam satu kurung siku, keduanya dipasangkan elemen demi elemen. Pemanggilan a[[0, 1, 2], [2, 0, 1]] berarti mengambil a[0, 2], kemudian a[1, 0], lalu a[2, 1], sehingga hasilnya adalah array satu dimensi berisi tiga elemen yang tersebar. Panjang kedua array indeks wajib sama karena pasangan dibentuk posisi demi posisi.
import numpy as np
a = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
print(a[[0, 1, 2], [2, 0, 1]])[3 4 8]Pengambilan sampel dengan rng.choice#
Pengambilan sampel acak dari array lazim dinyatakan sebagai fancy indexing, yaitu angka acak dipakai untuk memilih indeks, kemudian indeks dipakai untuk mengambil nilainya. Fungsi rng.choice pada objek hasil np.random.default_rng mengerjakan kedua langkah itu sekaligus. Dengan seed yang sama, urutan sampelnya tetap identik pada setiap eksekusi, sehingga contoh berikut dapat direproduksi apa adanya.
import numpy as np
rng = np.random.default_rng(42)
a = np.array([12, 7, 25, 3, 18])
sampel = rng.choice(a, size=3, replace=False)
print(sampel)[18 12 3]Parameter replace=False melarang satu elemen terpilih dua kali, sehingga ketiga nilai sampel selalu berbeda. Opsi replace=True merupakan nilai bakunya dan mengizinkan pengulangan. Bentuk hasil mengikuti parameter size, sehingga size=3 memberikan array satu dimensi berisi tiga sampel, dan parameter tersebut dapat diisi bentuk lain bila sampel bertingkat diperlukan. Pengaturan seed dan variasi distribusi lainnya dibahas lebih lanjut pada modul Angka acak, sedangkan di sini yang penting adalah pola bahwa sampel acak pun berupa salinan array baru.
Fancy indexing menghasilkan salinan#
Sama seperti penyaringan dengan mask, fancy indexing menghasilkan salinan baru yang tidak berbagi memori dengan array asalnya. Salinan dibuat karena elemen terpilih tidak berdampingan dalam memori dan urutannya bebas, sehingga tidak ada satu potongan kontinu yang dapat dipinjam. Mengubah isi hasil fancy indexing karenanya tidak berdampak pada array asalnya. Sifat ini berlaku baik pada indeks satu dimensi maupun indeks berpasangan.
import numpy as np
a = np.array([40, 10, 70, 20, 90])
terpilih = a[[0, 2]]
print(np.shares_memory(a, terpilih))
terpilih[0] = 99
print(a)False
[40 10 70 20 90]Fungsi np.shares_memory mengembalikan False, dan penugasan pada terpilih tidak mengubah a. Apabila hasil pengindeksan memang perlu dituliskan kembali ke array asal, gunakan penugasan dengan indeks yang sama, misalnya a[[0, 2]] = nilai_baru. Perbandingan lengkap antara operasi yang menghasilkan view dan operasi yang menghasilkan salinan dibahas pada topik View versus salinan. Salinan juga menjadikan hasil fancy indexing aman diproses lebih lanjut, karena pengubahan urutannya tidak pernah merusak sumbernya, sedangkan penulisan kembali ke array asal tetap dapat dilakukan dengan penugasan memakai indeks yang sama.
Kesalahan umum#
- Menggunakan indeks yang melewati batas. Satu indeks keliru di dalam array indeks cukup untuk memunculkan
IndexErrorsebagaimana kode di bawah, meskipun indeks lainnya sah. Perbaikannya adalah memeriksa panjang array sumber sebelum menyusun daftar indeks, terutama bila indeksnya berasal dari perhitungan. - Mengira hasil fancy indexing adalah view yang terikat pada array asal. Mutasi pada hasilnya ternyata tidak terbawa ke mana pun karena hasilnya salinan. Perbaikannya adalah menuliskan kembali hasilnya ke array asal melalui penugasan, atau menggunakan slicing bila elemen yang diambil memang berdampingan.
- Membaca indeks berpasangan sebagai irisan matriks. Penulisan
a[[0, 1], [2, 0]]mengambil dua elemen tersebar, bukan submatriks dua kali dua. Perbaikannya adalah memilih alat sesuai kebutuhan, yaitu slicing untuk irisan dan array berpasangan untuk elemen tersebar.
import numpy as np
a = np.array([40, 10, 70, 20, 90])
try:
print(a[[0, 2, 9]])
except IndexError as e:
print(f"IndexError: {e}")IndexError: index 9 is out of bounds for axis 0 with size 5Ringkasan#
- Fancy indexing menggunakan array integer sebagai indeks, sehingga banyak elemen diambil sekaligus dengan urutan bebas dan indeks yang boleh berulang.
- Pada array dua dimensi, satu array integer menyusun ulang baris, sedangkan dua array integer dipasangkan elemen demi elemen menjadi array satu dimensi.
rng.choicedengan seed tetap menghasilkan sampel yang dapat direproduksi, danreplace=Falsemelarang satu elemen terpilih dua kali.- Hasil fancy indexing adalah salinan baru, sehingga mutasi padanya tidak memengaruhi array asal.
Referensi#
- Indexing on ndarrays — NumPy — Panduan resmi fancy indexing, termasuk indeks berpasangan pada array multidimensi.
- Indexing routines — NumPy — Rujukan teknis pengindeksan dengan array integer beserta aturan bentuk hasilnya.