Chapter NaN dan Infinity menunjukkan betapa mudahnya satu nan meracuni hasil agregasi: sum, mean, sampai std ikut menjadi nan tanpa pesan error. Membuang nan lebih dulu lalu menghitung memang bisa, tetapi NumPy menyediakan jalan yang lebih pendek: keluarga fungsi nan-aware yang mengabaikan nan saat menghitung.
Nama fungsinya mengikuti pola yang mudah ditebak — awalan nan ditempelkan pada fungsi agregasi biasa: np.nansum, np.nanmean, np.nanmedian, np.nanmin, np.nanmax, dan np.nanstd. Bab ini membandingkan keduanya berdampingan, membuktikan kesetaraan hasilnya, dan menutup dengan jebakan yang jarang disangka: array yang isinya nan semua.
Perbandingan Langsung dengan Versi Biasa #
import numpy as np
a = np.array([80.0, np.nan, 90.0, 70.0, np.nan, 85.0])
print("sum :", a.sum(), "|", np.nansum(a))
print("mean :", a.mean(), "|", np.nanmean(a))
print("median:", np.median(a), "|", np.nanmedian(a))
print("min :", a.min(), "|", np.nanmin(a))
print("max :", a.max(), "|", np.nanmax(a))
print("std :", a.std(), "|", np.nanstd(a))Output yang Dihasilkan:
sum : nan | 325.0
mean : nan | 81.25
median: nan | 82.5
min : nan | 70.0
max : nan | 90.0
std : nan | 7.39509972887452Setiap pasangan dihitung dari array yang sama — enam elemen, dua di antaranya nan:
| Pasangan fungsi | Versi biasa | Versi nan-aware |
|---|---|---|
sum → nansum | nan | 325.0 |
mean → nanmean | nan | 81.25 |
median → nanmedian | nan | 82.5 |
min → nanmin | nan | 70.0 |
max → nanmax | nan | 90.0 |
std → nanstd | nan | 7.39509972887452 |
Mari kita bedah:
- Baris 3: array penilaian enam elemen; posisi ke-1 dan ke-4 tidak terisi (
nan). - Baris 4 (
a.sum()vsnp.nansum(a)): versi biasa terkontaminasinan, sedangkannansummenjumlahkan hanya empat nilai valid (80 + 90 + 70 + 85 = 325.0). - Baris 5-6:
nanmeanmembagi total valid dengan banyaknya nilai valid (325/4 = 81.25), bukan dengana.size; median juga dihitung atas empat nilai valid saja. - Baris 9 (
nanstd): simpangan baku dihitung terhadap mean versi nan-aware, dengan pembagi 4 (ddof bawaan 0, sama sepertistd).
Kesetaraan dengan Subset Valid #
Fungsi nan-aware tidak menyimpan kejutan: hasilnya sama dengan menghitung atas subset yang valid secara manual. Kita bisa membuktikannya:
import numpy as np
a = np.array([80.0, np.nan, 90.0, 70.0, np.nan, 85.0])
print(np.nanmean(a) == a[~np.isnan(a)].mean())
print(np.nanstd(a) == a[~np.isnan(a)].std())Output yang Dihasilkan:
True
TruePenjelasan singkat:
- Baris 4 (
a[~np.isnan(a)]): seleksi boolean dari Chapter Boolean Indexing mengambil empat nilai valid saja. - Baris 4-5: mean dan std atas subset valid itu dibandingkan langsung dengan
nanmeandannanstd— keduanya identik (True).
Artinya, memilih antara dua cara ini soal keterbacaan, bukan kebenaran. Untuk array besar, fungsi nan-aware juga lebih hemat karena tidak perlu membuat array perantara hasil seleksi. Untuk statistik lain seperti quantile, pola subset-valid yang sama berlaku — lihat Chapter mean, median, dan percentile.
Mengabaikan NaN per Baris dan Kolom #
Pada array dua dimensi, parameter axis bekerja seperti agregasi biasa (dibahas pada Chapter Operasi Berdasarkan Axis):
import numpy as np
suhu = np.array([
[27.5, np.nan, 28.1],
[26.9, 27.3, np.nan],
])
print(np.nanmean(suhu, axis=0))
print(np.nanmean(suhu, axis=1))Output yang Dihasilkan:
[27.2 27.3 28.1]
[27.8 27.1]Mari kita baca:
- Baris 7 (
axis=0): rata-rata per kolom, mengabaikannandi kolom masing-masing. Kolom 0 punya dua nilai valid (27.5 dan 26.9 → 27.2), sedangkan kolom 1 dan 2 tinggal satu nilai valid sehingga rata-ratanya nilai itu sendiri. - Baris 8 (
axis=1): rata-rata per baris; tiap baris kehilangan satu pembacaan, dannanmeantetap menghasilkan angka dari dua nilai yang tersisa.
Jebakan Data yang Semuanya NaN #
Perilaku nan-aware pada data yang valid-nya nol elemen berbeda-beda antar fungsi, dan di sinilah letak jebakannya:
import numpy as np
import warnings
kosong = np.array([np.nan, np.nan])
print("nansum :", np.nansum(kosong))
with warnings.catch_warnings(record=True) as terekam:
warnings.simplefilter("always")
rata = np.nanmean(kosong)
for w in terekam:
print(w.category.__name__, "->", w.message)
print("nanmean :", rata)Output yang Dihasilkan:
nansum : 0.0
RuntimeWarning -> Mean of empty slice
nanmean : nanMari kita telaah:
- Baris 5 (
np.nansum(kosong)): jumlah dari nol nilai valid dikembalikan sebagai0.0— konvensi jumlah kosong — bukannan. - Baris 6-8:
nanmeanatas rata-rata kosong tidak punya nilai yang bisa dikembalikan secara bermakna, sehingga hasilnyanandan NumPy mengirimRuntimeWarning. - Baris 9-10: loop mencetak kategori dan pesan tiap peringatan yang tertangkap —
Mean of empty slice— sehingga pesan itu bisa diverifikasi sebagai output teruji.
Sebagai penutup, keluarga ini mencakup hampir semua agregasi yang dibahas pada section Agregasi dan Statistika — nansum, nanprod, nancumsum, dan nancumprod juga tersedia. Aturannya satu: versi nan-aware mengabaikan nan, tetapi tetap memerlukan minimal satu nilai valid agar hasilnya bermakna.
Posisi Ekstrem: nanargmax dan nanargmin #
Pasangan np.argmax dan np.argmin pada Chapter min, max, argmin, dan argmax mencari posisi (indeks) nilai ekstrem, dan keduanya tidak NaN-aware: pada array yang mengandung nan, indeks yang dikembalikan justru menunjuk ke elemen nan itu sendiri. Versi nan-aware-nya, np.nanargmax dan np.nanargmin, mengabaikan nan terlebih dahulu, lalu mengembalikan indeks nilai ekstrem yang sesungguhnya.
import numpy as np
penjualan = np.array([500, np.nan, 650, 200, 480])
print("argmax :", np.argmax(penjualan))
print("nanargmax :", np.nanargmax(penjualan))
print("argmin :", np.argmin(penjualan))
print("nanargmin :", np.nanargmin(penjualan))
print("nilai terbesar:", penjualan[np.nanargmax(penjualan)])
try:
np.nanargmax(np.array([np.nan, np.nan]))
except ValueError as e:
print("ValueError:", e)Output yang Dihasilkan:
argmax : 1
nanargmax : 2
argmin : 1
nanargmin : 3
nilai terbesar: 650.0
ValueError: All-NaN slice encounteredMari kita baca:
- Baris 3 (
np.argmax): hasilnya1, indeks elemennan— perbandingan yang tersentuhnanikut terkontaminasi, sehingga pencarian maksimum berhenti di situ alih-alih di nilai 650. - Baris 4-6:
np.nanargmaxmengabaikannandan mengembalikan indeks2(nilai 650), sedangkannp.nanargminmengembalikan indeks3(nilai 200). Indeks itu bisa langsung dipakai mengambil nilainya:650.0. - Baris 8-10: bila semua elemen
nan, tidak ada indeks yang bermakna, maka kedua fungsi ini melemparValueErrorberpesanAll-NaN slice encountered— perilaku yang ditangkaptry/exceptagar skrip tetap berjalan.