Setelah deteksi pada bab-bab sebelumnya, tindakan paling umum adalah membuang nilai yang tidak valid dari array. Caranya memadukan dua materi: mask boolean dari Chapter Boolean Indexing sebagai selektor, dan detektor np.isnan/np.isfinite dari Chapter isfinite, isnan, dan isinf sebagai pembuat mask.

Bab ini membahas filtering satu dimensi, perbedaan membuang nan saja versus membuang nan sekaligus inf, dua sifat penting hasil filter (selalu satu dimensi dan selalu copy), sampai penyaringan baris pada array dua dimensi.

Membuang NaN dengan ~np.isnan #

python
import numpy as np

suhu = np.array([27.5, np.nan, 29.1, np.nan, 26.8])
bersih = suhu[~np.isnan(suhu)]
print(bersih)
print(bersih.shape)
print(np.nanmean(suhu) == bersih.mean())

Output yang Dihasilkan:

text
[27.5 29.1 26.8]
(3,)
True

Mari kita bedah:

  1. Baris 4 (~np.isnan(suhu)): np.isnan menandai posisi nan, lalu ~ membalik mask sehingga True berarti “nilai layak simpan”.
  2. Baris 4 (suhu[mask]): mask dipakai sebagai selektor; hasilnya hanya tiga pembacaan valid, dalam urutan aslinya.
  3. Baris 6: pembuktian silang — nanmean pada data asli sama persis dengan mean pada data hasil filter (True). Dua jalan berbeda, satu angka yang sama; pola ini dibahas juga pada Chapter NaN-aware Aggregation.

isfinite Membuang NaN dan inf Sekaligus #

Bila data berpotensi memuat tak hingga, filter berbasis isnan tidak cukup — inf lolos begitu saja:

python
import numpy as np

a = np.array([1.5, np.nan, np.inf, 2.0, -np.inf])
print(a[~np.isnan(a)])
print(a[np.isfinite(a)])

Output yang Dihasilkan:

text
[ 1.5  inf  2.  -inf]
[1.5 2. ]

Penjelasan singkat:

  1. Baris 4 (~np.isnan(a)): hanya nan yang dibuang; inf dan -inf masih ikut dalam hasil.
  2. Baris 5 (np.isfinite(a)): mask ini True hanya untuk nilai berhingga, sehingga nan, inf, dan -inf tersaring sekaligus.

Pemilihan filter dapat diringkas sebagai berikut:

  1. Data hanya berpotensi memuat nan → gunakan a[~np.isnan(a)].
  2. Data bisa memuat inf (misalnya dari pembagian nol) → gunakan a[np.isfinite(a)].
  3. Ingin tahu dulu berapa yang akan dibuang → hitung dengan pola Chapter Memeriksa Nilai Valid: (~np.isfinite(a)).sum().

Hasil Filter Selalu 1-D dan Berupa Copy #

Boolean mask pada array dua dimensi tidak mengembalikan matriks — hasilnya selalu array satu dimensi berisi elemen yang lolos, dan selalu array baru:

python
import numpy as np

m = np.array([[1.0, np.nan], [np.inf, 4.0]])
hasil = m[np.isfinite(m)]
print(hasil)
print(hasil.shape)
print(np.shares_memory(hasil, m))

Output yang Dihasilkan:

text
[1. 4.]
(2,)
False

Mari kita telaah:

  1. Baris 4 (m[np.isfinite(m)]): mask dua dimensi memilih elemen yang lolos menyusuri baris, dari kiri ke kanan; 1.0 dan 4.0 tersisa.
  2. Baris 5: bentuk (2,) menegaskan hasil filter selalu satu dimensi — baris dan kolom asal tidak dipertahankan.
  3. Baris 6 (np.shares_memory(...)): False berarti hasil adalah array baru (copy); mengubah hasil tidak memengaruhi m. Perbedaan view dan copy dibahas penuh pada Chapter View vs Copy.

Menyaring Baris pada Array Dua Dimensi #

Untuk data tabel — misalnya log stasiun cuaca dengan beberapa kolom pengukuran — yang biasanya dibuang adalah baris, bukan elemen lepas. Mask baris dibentuk dengan any(axis=1) atau all(axis=1):

python
import numpy as np

pengukuran = np.array([
    [27.5, 28.1, 26.9],
    [np.nan, np.nan, np.nan],
    [28.3, np.nan, 27.7],
])
print(np.isnan(pengukuran).any(axis=1))
print(pengukuran[~np.isnan(pengukuran).any(axis=1)])
print(pengukuran[~np.isnan(pengukuran).all(axis=1)])

Output yang Dihasilkan:

text
[False  True  True]
[[27.5 28.1 26.9]]
[[27.5 28.1 26.9]
 [28.3  nan 27.7]]

Mari kita bedah:

  1. Baris 3-7: matriks tiga baris pembacaan; baris tengah tidak terisi sama sekali, baris ketiga kehilangan satu pembacaan.
  2. Baris 8 (any(axis=1)): tiap baris diperiksa “apakah memuat minimal satu nan” — hasilnya [False True True].
  3. Baris 9: dengan negasi, hanya baris pertama yang lolos; satu nan saja cukup untuk membuang seluruh barisnya.
  4. Baris 10 (all(axis=1)): kebalikannya — hanya baris yang nan di semua kolom yang dibuang, sehingga baris ketiga tetap dipertahankan walau satu pembacaannya hilang.
EkspresiBaris yang dibuang
a[~np.isnan(a).any(axis=1)]baris yang memuat minimal satu NaN
a[~np.isnan(a).all(axis=1)]baris yang NaN di semua kolom

Filtering bukan satu-satunya pilihan: bila nilai yang hilang masih bisa digantikan dengan angka yang masuk akal, bab berikutnya — Mengganti Nilai Tertentu — menunjukkan caranya.