Pada bab-bab sebelumnya kita mengambil satu elemen atau rentang elemen yang berurutan. Sering kali posisi data yang dibutuhkan justru tersebar: “ambil harga produk ke-0, ke-2, dan ke-4”, atau “tampilkan baris Cabang Medan dan Cabang Bandung dalam urutan itu”. Menulis slice untuk tiap posisi tentu merepotkan. Untuk kebutuhan ini NumPy menyediakan fancy indexing (juga disebut integer array indexing): mengindeks array menggunakan list atau array yang berisi banyak indeks sekaligus.
Bab ini membahas empat hal: seleksi banyak elemen pada array satu dimensi, pola pasangan indeks pada array dua dimensi yang sering disalahpahami, pola grid untuk mengambil submatriks, dan sifat hasil fancy indexing yang selalu berupa copy.
Memilih Banyak Elemen dengan Daftar Indeks #
Cukup berikan daftar indeks di dalam tanda kurung siku ganda, dan NumPy mengembalikan elemen-elemen pada posisi tersebut dalam urutan daftar.
import numpy as np
harga = np.array([15000, 4500, 20000, 3000, 12500])
print(harga[[0, 2, 4]])
print(harga[[-1, -2]])
print(harga[[0, 2, 4]].shape)Output yang Dihasilkan:
[15000 20000 12500]
[12500 3000]
(3,)Mari kita periksa baris demi baris:
- Baris 3 (
harga[[0, 2, 4]]): daftar Python[0, 2, 4]otomatis diubah menjadi array indeks. Hasilnya[15000 20000 12500]— urutan hasil mengikuti urutan daftar indeks, bukan urutan asli data. - Baris 4 (
harga[[-1, -2]]): indeks negatif juga sah dalam fancy indexing, sehingga[-1, -2]mengambil dua elemen terakhir dalam urutan terbalik. - Baris 5 (
harga[[0, 2, 4]].shape): bentuk hasil ditentukan oleh bentuk daftar indeks; daftar satu dimensi berisi tiga angka menghasilkan(3,).
Pola Pasangan Baris-Kolom pada Array Dua Dimensi #
Ketika array dua dimensi diindeks dengan dua array indeks, NumPy memasangkan elemen kedua array satu per satu (pairwise), lalu mengambil elemen pada tiap pasangan koordinat tersebut. Perilaku ini sering disalahpahami oleh pemula.
import numpy as np
penjualan = np.array([
[120, 85, 200, 65],
[90, 150, 110, 40],
[175, 60, 95, 130],
])
print(penjualan[[0, 2], [1, 3]])
print(penjualan[[0, 2], [1, 3]].shape)Output yang Dihasilkan:
[ 85 130]
(2,)Penjelasannya:
- Baris 7 (
penjualan[[0, 2], [1, 3]]): array indeks baris[0, 2]dipasangkan dengan array indeks kolom[1, 3]menjadi dua pasangan koordinat:(0, 1)dan(2, 3). Hasilnya elemenpenjualan[0, 1]yaitu85, danpenjualan[2, 3]yaitu130. - Baris 8: bentuk hasil
(2,)mengikuti panjang pasangan, bukan(2, 2).
Mengambil Submatriks dengan Pola Grid #
Untuk mendapatkan submatriks berukuran dua-kali-dua, lakukan seleksi dalam dua langkah: pilih dulu baris-barisnya dengan fancy indexing, lalu pilih kolomnya dari hasil tersebut dengan slice.
import numpy as np
penjualan = np.array([
[120, 85, 200, 65],
[90, 150, 110, 40],
[175, 60, 95, 130],
])
sub = penjualan[[0, 2]][:, [1, 3]]
print(sub)
print(sub.shape)Output yang Dihasilkan:
[[ 85 65]
[ 60 130]]
(2, 2)Rincian langkahnya:
- Bagian
penjualan[[0, 2]](dievaluasi lebih dulu): mengambil baris ke-0 dan ke-2 utuh, menghasilkan array sementara berbentuk(2, 4). - Bagian
[:, [1, 3]]: pada array sementara itu, slice:mengambil semua baris dan fancy indexing[1, 3]mengambil kolom ke-1 dan ke-3. Hasilnya submatriks[[ 85 65] [ 60 130]]berbentuk(2, 2). - Baris 8-9: hasil akhirnya benar-benar matriks dua dimensi — berbeda dengan pola pasangan pada bagian sebelumnya yang menghasilkan
(2,).
Hasil Fancy Indexing Selalu Copy #
Berbeda dengan basic slicing yang menghasilkan view, fancy indexing selalu menyalin data ke buffer baru. Kita dapat membuktikannya dengan pola ubah-dan-amati beserta atribut base.
import numpy as np
penjualan = np.array([
[120, 85, 200, 65],
[90, 150, 110, 40],
[175, 60, 95, 130],
])
salin = penjualan[[0, 2]]
salin[0, 0] = 999
print(salin)
print(penjualan[0, 0])
print(penjualan[[0, 2]].base)Output yang Dihasilkan:
[[999 85 200 65]
[175 60 95 130]]
120
NoneYang perlu kita perhatikan:
- Baris 8 (
salin = penjualan[[0, 2]]): fancy indexing menyalin baris ke-0 dan ke-2 ke array baru bernamasalin. - Baris 9 (
salin[0, 0] = 999): kita mengubah elemen pertama miliksalin. - Baris 10-11 (
print): perubahan hanya terjadi padasalin;penjualan[0, 0]tetap120. Data asli aman karena tidak berbagi memori. - Baris 12 (
...base): atributbasemilik hasil fancy indexing bernilaiNone, artinya array tersebut memiliki buffer sendiri dan bukan view dari array lain. Pembandingnya, hasil slice memilikibaseyang menunjuk ke array aslinya.
Karena selalu menghasilkan copy, fancy indexing aman dipakai ketika hasil seleksi akan dimodifikasi. Perbandingan lengkap antara operasi yang berbagi memori dan yang tidak dibahas pada Chapter View vs Copy.