Program numerik punya karakteristik yang membuat pengujian biasa kurang pas: hasilnya array berukuran ratusan elemen, nilainya floating point yang tak pernah persis, dan kegagalan sering berupa selisih kecil yang tak terlihat mata. Modul numpy.testing dirancang khusus untuk situasi ini — asersinya memahami array, menoleransi galat floating point bila diminta, dan mencetak laporan selisih yang rinci ketika pengujian tidak lulus.
Bab ini menjelaskan mengapa assert biasa tidak memadai, lalu menuntun kita menulis asersi pertama dengan numpy.testing dan memetakan fungsi-fungsi utamanya. Tiga bab berikutnya memperdalam fungsi yang paling sering dipakai: assert_array_equal dan assert_allclose, diikuti perancangan kasus uji numerik yang utuh.
Masalah dengan assert Biasa #
Cara yang tampak alami — memakai assert bawaan Python pada hasil perbandingan array — justru berakhir di error yang membingungkan:
import numpy as np
hasil = np.array([0.1 + 0.2, 0.5])
harapan = np.array([0.3, 0.5])
try:
assert hasil == harapan
print("lulus")
except ValueError as e:
print("ValueError:", e)Output yang Dihasilkan:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()Bedah baris demi baris:
- Baris 3-4:
hasilmemuat nilai hasil hitung danharapannilai acuannya; keduanya array dua elemen. - Baris 6 (
assert hasil == harapan): pernyataanassertmengevaluasi kebenaranhasil == harapansebagai satu nilai. Perbandingan array menghasilkan array boolean dua elemen, dan interpreter tidak berani memutuskan “kebenaran” sebuah array dengan banyak elemen — itulah makna pesan ambiguous. - Baris 7-10: errornya
ValueError, bukanAssertionError; blokexceptmenangkap dan mencetaknya sehingga pola masalahnya terlihat tanpa menghentikan script.
Solusi jangka pendeknya adalah (hasil == harapan).all() — tetapi pendekatan itu tetap tidak memberi tahu elemen mana yang salah dan seberapa jauh melesetnya. Tugas itulah yang diambil alih numpy.testing.
Asersi Pertama dengan assert_array_equal #
Fungsi np.testing.assert_array_equal membandingkan dua array secara elemen demi elemen. Saat lulus, ia diam; saat tidak lulus, ia mencetak laporan selisih yang detail:
import numpy as np
from numpy.testing import assert_array_equal
hasil = np.array([0.1 + 0.2, 0.5, 0.75])
harapan = np.array([0.3, 0.5, 0.75])
try:
assert_array_equal(hasil, harapan)
print("Pengujian lulus")
except AssertionError as e:
print("AssertionError:", e)Output yang Dihasilkan:
AssertionError:
Arrays are not equal
Mismatched elements: 1 / 3 (33.3%)
Max absolute difference among violations: 5.55111512e-17
Max relative difference among violations: 1.85037171e-16
ACTUAL: array([0.3 , 0.5 , 0.75])
DESIRED: array([0.3 , 0.5 , 0.75])Mari kita bedah:
- Baris 3-4: kasus yang sama seperti sebelumnya, kini dengan tiga elemen dan pembanding dari
numpy.testing— diimpor lewatfrom numpy.testing import assert_array_equal. - Baris 6-7: pembanding menemukan satu elemen tidak sama persis dan memunculkan
AssertionError; bila lulus, fungsi tidak mencetak apa pun — keheningan adalah tanda keberhasilan. - Laporan kesalahan: baris
Mismatched elements: 1 / 3 (33.3%)menghitung cakupan kesalahan, dua baris berikutnya mengukur selisih maksimum secara absolut (5.55e-17) dan relatif, laluACTUALdanDESIREDmencetak kedua array berdampingan.
Dari laporan itu langsung terlihat bahwa selisihnya murni galat floating point 0.1 + 0.2, bukan kesalahan logika. Keputusan berikutnya — melonggarkan perbandingan dengan toleransi — dibahas pada Chapter assert_allclose.
Peta Fungsi numpy.testing #
Modul ini berisi keluarga fungsi yang saling melengkapi. Tabel berikut memetakan fungsi yang paling sering dipakai sepanjang section ini:
| Fungsi | Menguji | Catatan |
|---|---|---|
assert_array_equal | kesamaan persis elemen demi elemen | NaN dianggap sama bila posisinya sama |
assert_allclose | kedekatan dengan toleransi rtol/atol | pilihan utama untuk hasil floating point |
assert_array_almost_equal | kedekatan sampai decimal digit desimal | gaya lama, satu parameter presisi |
assert_array_less | actual < desired untuk semua elemen | cocok untuk pemeriksaan batas |
assert_raises | exception yang diharapkan muncul | dipakai sebagai context manager |
assert_equal | kesamaan objek Python umum | mengerti list, dict, dan array |
assert_array_almost_equal dan assert_raises #
Dua fungsi dari tabel di atas layak dicoba langsung. assert_array_almost_equal bekerja dengan parameter decimal — jumlah digit desimal yang harus sama — sedangkan assert_raises memastikan suatu exception memang muncul:
import numpy as np
from numpy.testing import assert_array_almost_equal
ukur = np.array([9.81234567, 9.76543210])
teori = np.array([9.81234566, 9.76543211])
try:
assert_array_almost_equal(ukur, teori, decimal=7)
print("decimal=7 -> lulus")
except AssertionError:
print("decimal=7 -> tidak lulus")
try:
assert_array_almost_equal(ukur, teori, decimal=9)
print("decimal=9 -> lulus")
except AssertionError:
print("decimal=9 -> tidak lulus")Output yang Dihasilkan:
decimal=7 -> lulus
decimal=9 -> tidak lulusimport numpy as np
from numpy.testing import assert_raises
with assert_raises(ValueError):
np.arange(3) + np.arange(4)
print("ValueError muncul sesuai harapan")
with assert_raises(np.linalg.LinAlgError):
np.linalg.inv(np.array([[1.0, 2.0], [2.0, 4.0]]))
print("LinAlgError muncul sesuai harapan")Output yang Dihasilkan:
ValueError muncul sesuai harapan
LinAlgError muncul sesuai harapanPenjelasan kedua blok:
- Blok pertama, baris 6-9: selisih kedua elemen adalah
1e-8; ambangdecimal=7mengizinkan selisih hingga sekitar1.5e-7sehingga lulus, sementaradecimal=9menuntut ketepatan sampai1e-9dan pengujian tidak lulus. Semakin besardecimal, semakin ketat ujiannya. - Blok kedua, baris 3-5:
assert_raisesdipakai sebagai context manager; kode di dalamwithdiharapkan memunculkanValueError— penjumlahan array(3,)dengan(4,)yang memang error. - Blok kedua, baris 7-10: kasus kedua memastikan
np.linalg.invpada matriks singular memunculkanLinAlgError. Bila kode di dalamwithtidak memunculkan exception apa pun,assert_raisessendiri yang gagal.
Satu catatan penutup: assert_array_almost_equal masih banyak dipakai di kode lama, tetapi untuk kode baru pilihlah assert_allclose karena parameter rtol/atol-nya jauh lebih mudah ditafsirkan. Detail parameter itu — termasuk rumus toleransinya — menjadi topik penuh pada Chapter assert_allclose, sementara perilaku persis assert_array_equal dibedah pada Chapter assert_array_equal.