Pembacaan sensor sering membawa kode kegagalan: alat yang gagal mengukur menulis -99, file CSV menandai sel kosong dengan nilai tertentu, atau perhitungan menghasilkan nan dan inf. Chapter NaN dan Infinity membahas penanganannya untuk data float — tetapi ada dua masalah yang tidak terjawab di sana: satu nan saja membuat agregasi ikut menjadi nan, dan array integer sama sekali tidak bisa menyimpan nan.

Masked array dari modul np.ma memecahkan keduanya. Datanya tetap utuh, tetapi setiap elemen dibekali flag boolean — mask — yang menandai elemen tersebut boleh diabaikan. Semua operasi NumPy yang disediakan np.ma menghormati flag itu: elemen yang dimasking tetap tersimpan, namun tidak ikut menghitung.

Membuat Masked Array dengan masked_where #

Fungsi np.ma.masked_where(kondisi, array) memasangkan setiap elemen dengan nilai kondisi. Nilai pengganti kegagalan sensor -99.0 pada contoh berikut tetap tersimpan di dalam data, hanya ditandai:

python
import numpy as np

pembacaan = np.array([27.5, -99.0, 26.8, 28.1, -99.0])
m = np.ma.masked_where(pembacaan == -99.0, pembacaan)
print(m)
print(m.data)
print(m.mask)

Output yang Dihasilkan:

text
[27.5 -- 26.8 28.1 --]
[ 27.5 -99.   26.8  28.1 -99. ]
[False  True False False  True]

Mari kita bedah:

  1. Baris 4 (np.ma.masked_where(...)): kondisi pembacaan == -99.0 menghasilkan mask boolean, dan fungsi tersebut menyatukannya dengan data menjadi objek MaskedArray.
  2. Baris 5 (print(m)): elemen yang dimasking ditampilkan sebagai -- — tanda bahwa nilainya diabaikan, bukan dihapus.
  3. Baris 6 (m.data): atribut data menampung array asli; -99.0 masih ada di posisi asalnya.
  4. Baris 7 (m.mask): mask boolean memetakan posisi yang diabaikan; True berarti “jangan ikutkan”.

Operasi Agregasi yang Menghormati Mask #

Manfaat utamanya terasa saat menghitung. Bandingkan rata-rata array biasa yang tercemar nilai sentinel dengan rata-rata masked array:

python
import numpy as np

pembacaan = np.array([27.5, -99.0, 26.8, 28.1, -99.0])
m = np.ma.masked_where(pembacaan == -99.0, pembacaan)
print(pembacaan.mean())
print(m.mean())
print(m.max())

Output yang Dihasilkan:

text
-23.119999999999997
27.46666666666667
28.1

Penjelasannya:

  1. Baris 5 (pembacaan.mean()): dua nilai -99.0 ikut dihitung, sehingga rata-rata jatuh ke -23.12... — angka yang tidak bermakna untuk suhu.
  2. Baris 6 (m.mean()): fungsi agregasi versi np.ma menjumlahkan hanya elemen yang tidak dimasking dan membaginya dengan jumlah elemen valid, menghasilkan 27.47....
  3. Baris 7 (m.max()): max juga sadar mask, sehingga -99.0 tidak pernah dipilih sebagai nilai terbesar.

masked_invalid untuk nan dan inf #

Untuk data float yang sudah mengandung nan atau inf, fungsi np.ma.masked_invalid memasang mask pada semua nilai tersebut sekaligus:

python
import numpy as np

f = np.array([1.5, np.nan, 2.5, np.inf])
mf = np.ma.masked_invalid(f)
print(mf)
print(mf.mean())

Output yang Dihasilkan:

text
[1.5 -- 2.5 --]
2.0

Bandingkan dengan pendekatan np.nanmean pada Chapter NaN-aware Aggregation: hasil hitungnya sama, tetapi masked array menyimpan flag secara eksplisit, sehingga posisi yang bermasalah tetap dapat diperiksa lewat mf.mask kapan saja.

Ketika Array Integer Tidak Bisa Memuat NaN #

Array integer tidak memiliki representasi nan. NumPy tidak menolak saat kita menulis nan di dalam list — ia diam-diam menaikkan seluruh array menjadi float, dan tipe integer aslinya hilang:

python
import numpy as np

nilai = np.array([80, 75, 88])
coba = np.array([80, np.nan])
print(coba.dtype)
mn = np.ma.masked_values(nilai, 75)
print(mn)
print(mn.mean())
print(mn.compressed())
print(mn.filled(0))

Output yang Dihasilkan:

text
float64
[80 -- 88]
84.0
[80 88]
[80  0 88]

Bedah baris demi baris:

  1. Baris 4 (coba.dtype): campuran 80 dan np.nan menghasilkan array float64 — integer tidak pernah bisa memuat nan.
  2. Baris 5 (np.ma.masked_values(nilai, 75)): pada array int32 asli, nilai yang harus diabaikan ditandai dengan pola nilai tertentu — di sini 75 sebagai contoh kode kosong.
  3. Baris 7-8: agregasi menghasilkan 84.0 dari dua elemen valid saja.
  4. Baris 9 (mn.compressed()): mengembalikan salinan berisi elemen valid saja, mask beserta elemen tersembunyinya dilepas.
  5. Baris 10 (mn.filled(0)): mengembalikan array biasa dengan elemen tersembunyi diganti nilai isian 0.

Kapan memilih np.ma daripada pendekatan nan? Ringkasnya:

SituasiPendekatan nanPendekatan np.ma
Data float, analisis statistiknp.nanmean dan kawan-kawan cukupjuga bisa, dengan mask eksplisit
Data integer bertanda kosongtidak didukung (nan memaksa float)satu-satunya pilihan bawaan NumPy
Perlu menelusuri posisi bermasalahvia np.isnan terpisahlangsung dari atribut mask