Kegagalan broadcasting

Bentuk yang tidak kompatibel dan cara membaca pesan error.

Daftar isi

Broadcasting menolak bentuk yang tidak dapat diselaraskan. Pada kasus tersebut NumPy menghentikan operasi dengan ValueError sebelum perhitungan dimulai, dan pesannya memuat kedua bentuk yang bertabrakan. Topik ini membahas dua pola kegagalan yang paling sering ditemui, cara membaca pesan errornya, dan cara memperbaiki bentuk operand dengan reshape atau np.newaxis.

Dua pola kegagalan#

Kegagalan terjadi apabila dua dimensi yang sejajar berbeda dan tidak ada yang bernilai 1. Pola pertama adalah vektor satu dimensi yang panjangnya tidak cocok dengan dimensi terakhir matriks. Bentuk (3, 4) bertemu (3,) gagal karena angka 3 pada (3,) berada di posisi dimensi terakhir sehingga harus dibandingkan dengan 4. Angka 3 pada (3,) tidak pernah dibandingkan dengan angka 3 pada dimensi pertama (3, 4), karena penyelarasan dilakukan dari kanan.

Pola kedua adalah dua array satu dimensi dengan panjang berbeda. Bentuk (4,) dan (3,) tidak memiliki dimensi bernilai 1 yang dapat diperluas, sehingga tidak ada cara menyelamatkan operasinya. Kegagalan kedua jenis ini hanya dapat diperbaiki dengan mengubah bentuk operand atau dengan meninjau kembali datanya, bukan dengan mengatur ulang penyelarasan.

Aturan yang sama berlaku pada bentuk yang lebih panjang. Bentuk (2, 3, 4) dapat disiarkan dengan (3, 1) maupun (4,) karena penyelarasan dari kanannya berhasil, tetapi gagal dengan (2, 3) karena dimensi terakhirnya 4 bertemu 3. Memeriksa rencana broadcasting dengan np.broadcast_shapes sebelum operasi mempercepat penemuan pasangan bentuk yang bermasalah.

Kegagalan broadcasting juga bersifat menyeluruh, bukan parsial. NumPy tidak menghitung sebagian elemen lalu melanjutkan sisanya, sehingga tidak ada hasil parsial yang perlu dibersihkan setelah ValueError muncul.

Membaca pesan error#

Pesan error broadcasting selalu menyebutkan bentuk kedua operand sebagaimana adanya, tanpa pelapisan dimensi 1. Pada eksperimen, operasi yang gagal perlu dibungkus try dan except agar program tetap berjalan dan pesannya dapat dicetak untuk diperiksa.

python
import numpy as np

a = np.ones((3, 4))
b = np.ones(3)
try:
    hasil = a + b
except ValueError as e:
    print(f"{type(e).__name__}: {e}")
text Keluaran
ValueError: operands could not be broadcast together with shapes (3,4) (3,) 

Pesan operands could not be broadcast together with shapes (3,4) (3,) menampilkan kedua bentuk berdampingan. Struktur pesannya dapat diurai menjadi tiga bagian, yaitu pernyataan operands could not be broadcast together, kata with shapes, lalu daftar kedua bentuk. NumPy tidak menyebutkan dimensi mana yang bertabrakan secara eksplisit, sehingga daftar bentuk itulah yang diperiksa dengan penyelarasan dari kanan. Pemeriksaannya menemukan angka 4 pada (3,4) bertemu angka 3 pada (3,), dan keduanya berbeda tanpa ada yang bernilai 1. Pada titik itu NumPy langsung berhenti tanpa mengeksekusi penjumlahan.

Pola kedua muncul pada dua array satu dimensi dengan panjang berbeda.

python
import numpy as np

try:
    np.ones(4) + np.ones(3)
except ValueError as e:
    print(f"{type(e).__name__}: {e}")
text Keluaran
ValueError: operands could not be broadcast together with shapes (4,) (3,) 

Kegagalan kedua ini tidak dapat diselesaikan dengan mengubah bentuk, sebab kedua vektor memang panjangnya berbeda dan tidak ada dimensi 1 yang dapat diperluas. Satu-satunya perbaikan yang benar adalah meninjau data atau logika yang menghasilkan kedua array tersebut. Pesan untuk pola kedua mengikuti struktur yang sama, sehingga cara membacanya pun sama.

Memperbaiki bentuk operand#

Apabila maksud operasinya jelas, kegagalan biasanya berarti salah satu operand kekurangan satu dimensi. Menambahkan b[i] ke baris ke-i dari matriks (3, 4) memerlukan b berbentuk (3, 1), dan perbaikannya adalah menyisipkan dimensi baru dengan np.newaxis.

python
import numpy as np

a = np.ones((3, 4))
b = np.arange(3)
diperbaiki = b[:, np.newaxis]
hasil = a + diperbaiki
print("bentuk hasil:", hasil.shape)
print(hasil)
text Keluaran
bentuk hasil: (3, 4)
[[1. 1. 1. 1.]
 [2. 2. 2. 2.]
 [3. 3. 3. 3.]]

Setelah b berbentuk (3, 1), penyelarasan dari kanan membandingkan 4 dengan 1 terlebih dahulu, lalu 3 dengan 3, sehingga operasi berhasil dan setiap baris a bertambah sesuai indeksnya. Alternatif dengan hasil sama adalah b.reshape(-1, 1). Kuncinya adalah menentukan dimensi mana yang menjadi pasangan b, lalu menyisipkan dimensi 1 pada posisi yang tepat, bukan sekadar mencoba bentuk sampai errornya hilang. Pesan yang dicetak pada pola try dan except adalah objek exception yang dikonversi menjadi teks, sehingga isinya persis seperti yang tampil pada terminal.

Sebelum mengubah bentuk, bedakan dua jenis masalahnya. Apabila maksud operasinya memang menambahkan b[i] ke baris ke-i, masalahnya murni penyelarasan dan perbaikan bentuk menyelesaikannya. Apabila panjang b memang seharusnya 4, maka vektor (3,) adalah masalah data, dan mengubah bentuknya justru menyembunyikan kesalahan itu. Perubahan bentuk hanya menyelesaikan masalah penyelarasan, bukan masalah data.

Setelah operasi berhasil, bentuk hasil tetap perlu dicocokkan dengan rencana, karena keberhasilan eksekusi tidak menjamin arah perluasan yang benar.

Kesalahan umum#

Kesalahan lain yang sering terjadi adalah mencampuradukkan aturan broadcasting dengan aturan perkalian matriks. Operator @ tidak melapisi dimensi dengan 1, sehingga bentuk yang berhasil pada penjumlahan biasa tetap gagal pada @, dan pesan kegagalannya pun berbeda dari pesan broadcasting. Perbaikan yang tepat karenanya bergantung pada operasi yang dimaksud, bukan sekadar mengubah bentuk operand.

python
import numpy as np

m = np.arange(12).reshape(3, 4)
b = np.arange(3)
try:
    hasil = m @ b
except ValueError as e:
    print(f"{type(e).__name__}: {e}")
text Keluaran
ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 3 is different from 4)

Pesan ini menyebut Input operand 1 dan ukuran 3 yang berbeda dari 4. Kegagalannya terjadi karena perkalian matriks (3, 4) @ (3,) mensyaratkan dimensi terakhir m bertemu dimensi pertama b pada angka yang sama, bukan karena penyelarasan broadcasting. Dua jenis pesan ini perlu dibedakan agar perbaikannya diarahkan ke aturan yang tepat. Sebagai pembanding, (3, 4) @ (4,) berhasil karena angka 4 pada kedua operand bertemu pada dimensi inti yang sama. Kaidah praktisnya: apabila operasi yang dimaksud adalah perkalian matriks, dimensi terakhir operand kiri wajib sama dengan dimensi pertama operand kanan, sedangkan apabila yang dimaksud operasi per elemen, aturan broadcasting-lah yang berlaku.

Ringkasan#

  • Broadcasting gagal dengan ValueError apabila dua dimensi sejajar berbeda dan tidak ada yang bernilai 1.
  • Pesan error menampilkan kedua bentuk asli, sehingga tabrakan dapat dilacak dengan menyelaraskan keduanya dari kanan.
  • Kegagalan yang lazim diperbaiki dengan menyisipkan dimensi 1 melalui np.newaxis atau reshape sesuai dimensi yang dimaksudkan, sedangkan perbedaan panjang data sungguhan harus diperbaiki pada sumber datanya.

Referensi#