6.6. Pengindeksan dan slicing¶
Sebuah ndarray dialamatkan dengan empat cara: indeks tunggal, slice, boolean mask, dan bentuk penugasan dari masing-masing.
6.6.1. Elemen tunggal¶
Pengindeksan kurung siku mengembalikan nilai pada posisi yang diberikan:
a = np.arange(10, dtype=np.uint8)
print(a[0], a[-1]) # 0 9
print(a[1], a[-2]) # 1 8
Indeks negatif dihitung dari akhir, sama seperti pada Python list. Indeks di luar jangkauan memunculkan IndexError.
Untuk array berperingkat lebih tinggi, setiap sumbu mengambil indeks. Indeks diletakkan di dalam satu set kurung, dipisahkan oleh koma:
m = np.arange(9, dtype=np.uint8).reshape((3, 3))
print(m[1, 1]) # 4
print(m[2, 0]) # 6
Ketika lebih sedikit indeks daripada sumbu yang disediakan, sumbu yang tidak terindeks dibiarkan utuh. Hasilnya adalah reduced-rank view dari sumbernya:
print(m[0]) # the first row, as a 1-D view of m
6.6.2. Slice¶
Slice start:stop:step mengembalikan view dari array. View berbagi buffer data yang mendasari dengan sumber; menulis melalui view menulis ke sumber:
a = np.arange(10, dtype=np.uint8)
v = a[::2] # array([0, 2, 4, 6, 8], dtype=uint8)
v[0] = 99
print(a)
# array([99, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=uint8)
Ketika buffer independen diperlukan, copy() menghasilkannya secara eksplisit.
Slicing meluas secara alami ke dimensi yang lebih tinggi. Setiap sumbu mengambil slice-nya sendiri:
m = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]], dtype=np.uint8)
m[0] # first row
m[0, :2] # first two elements of row 0
m[:, 0] # column 0 (still 2-D in ulab)
m[-1] # last row
m[::2, ::2] # every other row, every other column
Mencampur integer (indeks tunggal, membuang sumbu) dan slice (mempertahankan sumbu) diperbolehkan dan merupakan cara penulisan akses baris-tunggal / kolom-tunggal yang biasa.
6.6.3. Boolean mask¶
Array boolean dengan bentuk yang sama dengan sumber memilih elemen di mana mask adalah True. Pengindeksan boolean saat ini bekerja pada array 1-D; input berperingkat lebih tinggi memunculkan NotImplementedError
a = np.arange(9, dtype=np.float)
mask = a < 5
print(a[mask])
Output:
array([0.0, 1.0, 2.0, 3.0, 4.0], dtype=float)
Mask adalah bool ndarray biasa, sehingga ekspresi apa pun yang menghasilkannya bekerja:
b = np.array([4, 4, 4, 3, 3, 3, 13, 13, 13], dtype=np.uint8)
a = np.arange(9, dtype=np.uint8)
print(a[a * a > np.sin(b) * 100.0])
Pengindeksan boolean mengembalikan copy. Elemen yang dipilih berada pada posisi apa pun di mana mask bernilai True -- bukan pada stride reguler melalui sumber -- sehingga tidak ada deskriptor yang dapat digunakan view untuk mengalamatkannya, dan hasilnya dimaterialisasikan ke dalam buffernya sendiri.
6.6.4. Pengindeksan array integer¶
Melewatkan list atau array indeks dalam kurung memilih elemen-elemen tersebut dalam satu langkah:
a = np.array([10, 20, 30, 40, 50], dtype=np.uint8)
a[[0, 2, 4]]
# array([10, 30, 50], dtype=uint8)
Hasilnya adalah copy; elemen yang dipilih tidak lagi berbagi penyimpanan dengan sumber. Bentuk yang sama bekerja di sisi kiri penugasan:
a[[0, 2, 4]] = 0
# array([0, 20, 0, 40, 0], dtype=uint8)
take() (dibahas di Seleksi dan penataan ulang) adalah bentuk fungsi dari operasi yang sama dan menerima kata kunci out= untuk penggunaan bebas-alokasi dalam loop streaming.
6.6.5. Penugasan slice¶
Slice dan mask muncul di sisi kiri penugasan maupun sisi kanan. Sisi kanan bisa berupa skalar, array lain, atau view:
m = np.zeros((3, 3), dtype=np.uint8)
m[0] = 1 # whole row 0 set to 1
m[:, 2] = 3 # whole column 2 set to 3
m[1, 1:3] = [7, 8] # row 1, columns 1 and 2
Boolean mask di sisi kiri menggantikan elemen yang memenuhi kondisi:
a = np.arange(9, dtype=np.uint8)
a[a < 3] = 99
# array([99, 99, 99, 3, 4, 5, 6, 7, 8], dtype=uint8)
a = np.arange(9, dtype=np.uint8)
b = np.array(range(9)) + 12
a[b < 15] = b[b < 15]
# array([12, 13, 14, 3, 4, 5, 6, 7, 8], dtype=uint8)
6.6.6. Mengapa penugasan slice penting pada kamera¶
Penugasan slice menulis melalui array yang sudah ada. Tidak ada array baru yang dialokasikan. Itulah perbedaan antara:
out = a + b # makes a new array the size of a
out = out * 2 # makes another new array
dan:
out[:] = a # writes into the existing out
out += b # in place
out *= 2 # in place
Versi pertama meminta kamera untuk dua array baru senilai RAM; versi kedua tidak meminta apa pun. Pada mikrokontroler dengan RAM terbatas, perbedaan itu sering kali menjadi perbedaan antara skrip yang berjalan dengan nyaman dan yang kehabisan memori.
Performa membahas pola ini secara rinci. Aturan penting untuk saat ini adalah bahwa penugasan slice, operator aritmetika in-place (+=, *=, ...), dan kata kunci out= pada fungsi universal adalah tiga alat yang memungkinkan pembaruan bebas-alokasi.