Setelah data rapi, pertanyaan berikutnya biasanya pencarian: pada posisi berapa suhu pertama kali melebihi 30 derajat? Elemen mana saja yang tidak nol? Di posisi berapa nilai baru harus disisipkan agar daftar harga tetap terurut? NumPy menjawab ketiganya tanpa loop Python: argmax, nonzero/argwhere, dan searchsorted.

Bab ini menutup section Manipulasi dan Penggabungan Array dengan pola yang paling sering dipakai pada pekerjaan data sehari-hari: pipeline filter — susun mask baris, pilih baris yang lolos kondisi, lalu urutkan hasilnya.

Trik argmax untuk Kemunculan Pertama #

np.argmax mengembalikan posisi nilai terbesar pada array. Pada array boolean, nilai terbesar adalah True, sehingga np.argmax(mask) mengembalikan posisi True pertama — trik populer untuk mencari kemunculan pertama suatu kondisi.

python
import numpy as np

suhu = np.array([27.5, 30.2, 29.8, 31.0, 28.4])
mask = suhu > 30.0
print(mask)
print(np.argmax(mask))

tidak_ada = suhu > 40.0
print(tidak_ada.any(), np.argmax(tidak_ada))

Output yang Dihasilkan:

text
[False  True False  True False]
1
False 0

Penjelasannya:

  1. Baris 4 (mask = suhu > 30.0): perbandingan menghasilkan array boolean; 30.2 dan 31.0 melampaui ambang, keduanya berada di posisi 1 dan 3.
  2. Baris 6 (np.argmax(mask)): True setara 1 dan False setara 0, sehingga nilai maksimum pertama berada di posisi 1 — yaitu suhu 30.2, kemunculan pertama di atas 30 derajat.
  3. Baris 9 (tidak_ada.any(), np.argmax(tidak_ada)): jebakan terlihat di sini. Ketika tidak ada satu pun True, tidak_ada.any() bernilai False, tetapi np.argmax tetap mengembalikan 0 — posisi elemen pertama, bukan tanda “tidak ditemukan”.

nonzero dan argwhere: Dua Bentuk Hasil #

np.nonzero dan np.argwhere menemukan semua posisi elemen yang tidak nol (atau True). Keduanya memuat informasi yang sama, tetapi bentuk hasilnya berbeda dan masing-masing nyaman untuk keperluan yang berbeda.

python
import numpy as np

matriks = np.array([
    [4, 0, 7],
    [0, 9, 0],
])
print(np.nonzero(matriks))
print(np.argwhere(matriks))
print(np.argwhere(matriks).shape)

Output yang Dihasilkan:

text
(array([0, 0, 1]), array([0, 2, 1]))
[[0 0]
 [0 2]
 [1 1]]
(3, 2)

Perbedaan bentuknya:

  1. Baris 7 (np.nonzero(matriks)): hasilnya tuple berisi satu array per axis — elemen tak nol berada di baris [0 0 1] dan kolom [0 2 1]. Pasangan array ini siap dipakai untuk fancy indexing, misalnya matriks[np.nonzero(matriks)] untuk mengambil nilai-nilainya.
  2. Baris 8-9 (np.argwhere(matriks)): hasilnya array dua dimensi berukuran (3, 2) — tiga elemen tak nol, dua koordinat per elemen. Setiap baris adalah satu koordinat (baris, kolom).
  3. Tiga posisi yang ditemukan: (0, 0) untuk 4, (0, 2) untuk 7, dan (1, 1) untuk 9.
FungsiBentuk hasilPaling nyaman untuk
np.nonzero(a)tuple berisi array indeks per axismengindeks ulang: a[np.nonzero(a)]
np.argwhere(a)array 2-D berukuran (n, ndim)membaca daftar koordinat atau loop per titik

searchsorted: Posisi Sisip pada Array Terurut #

np.searchsorted mencari posisi di mana nilai baru sebaiknya disisipkan agar array terurut tetap terurut. Pencariannya memakai binary search, sehingga biayanya O(log n) — jauh lebih hemat daripada memeriksa elemen satu per satu pada array besar.

python
import numpy as np

harga = np.array([5000, 9000, 12000, 20000])
print(np.searchsorted(harga, 11000))
print(np.searchsorted(harga, 9000, side="left"))
print(np.searchsorted(harga, 9000, side="right"))

Output yang Dihasilkan:

text
2
1
2

Rinciannya:

  1. Baris 4: 11000 harus masuk pada indeks 2 — di antara 9000 dan 12000 — agar urutan tetap menaik.
  2. Baris 5 (side="left"): untuk nilai yang sudah ada seperti 9000, side="left" mengembalikan posisi sebelum elemen yang sama, yaitu indeks 1. Ini perilaku default.
  3. Baris 6 (side="right"): mengembalikan posisi setelah semua elemen yang sama, yaitu indeks 2. Perbedaan keduanya berguna untuk menghitung isi rentang: searchsorted(harga, 12000, side="right") - searchsorted(harga, 9000, side="left") bernilai 2, yaitu banyaknya elemen pada rentang 9000 hingga 12000.

Pipeline Filter: Mask, Seleksi, lalu Urutkan #

Teknik dari bab-bab section ini bergabung menjadi pola kerja yang paling sering dipakai untuk menyiapkan data: buat mask boolean dari kondisi satu kolom, pilih baris yang lolos, kemudian urutkan hasilnya.

python
import numpy as np

penjualan = np.array([
    [120, 85, 200, 65],
    [90, 150, 110, 40],
    [175, 60, 95, 130],
])
mask = penjualan[:, 0] > 100
terpilih = penjualan[mask]
print(mask)
print(terpilih)

urutan = np.argsort(terpilih[:, 0])[::-1]
print(terpilih[urutan])

Output yang Dihasilkan:

text
[ True False  True]
[[120  85 200  65]
 [175  60  95 130]]
[[175  60  95 130]
 [120  85 200  65]]

Langkah demi langkah:

  1. Baris 8 (mask = penjualan[:, 0] > 100): slice :, 0 mengambil kolom pertama (produk Buku), lalu perbandingannya menghasilkan mask per baris [ True False True].
  2. Baris 9 (terpilih = penjualan[mask]): boolean row mask memilih baris-baris utuh yang mask-nya True; hasilnya array baru dan baris kedua tidak ikut. Detailnya ada pada Chapter Boolean Indexing.
  3. Baris 13 (urutan = np.argsort(terpilih[:, 0])[::-1]): argsort mengurutkan kolom Buku menaik, lalu [::-1] membaliknya menjadi menurun sehingga 175 mendahului 120. Konsepnya dibahas pada Chapter Sorting Array.
  4. Baris 14 (terpilih[urutan]): fancy indexing menerapkan urutan tersebut ke seluruh baris, sehingga kolom lain tetap konsisten dengan barisnya. Perilaku ini dijelaskan pada Chapter Fancy Indexing.

Pola mask → seleksi → urutkan adalah jembatan menuju analisis data yang lebih kompleks: ganti kondisi pada Baris 8 dan seluruh pipeline mengikuti tanpa perubahan lain.