Sebuah vektor harga (3,) kadang perlu diperlakukan sebagai matriks satu baris (1, 3) atau satu kolom (3, 1) — misalnya saat harga harus dijumlahkan dengan potongan per wilayah yang berbentuk matriks. Operasi aritmetika antar array menuntut kesesuaian sumbu, dan sumbu itu kadang harus kita sisipkan sendiri.

np.expand_dims(a, axis) menyisipkan sumbu baru berukuran satu pada posisi axis. Bentuk array berubah, jumlah elemen tidak. Bab ini juga membahas padanan indexed-nya, np.newaxis, serta alasan utama keduanya dipakai: menyiapkan broadcasting.

Menyisipkan Sumbu Baru #

Posisi axis menentukan di mana sumbu berukuran satu disisipkan: axis=0 di depan, axis=1 di belakang untuk array 1-D.

python
import numpy as np

harga = np.array([15000, 20000, 25000])
print(harga.shape)
baris = np.expand_dims(harga, axis=0)
kolom = np.expand_dims(harga, axis=1)
print(baris.shape, kolom.shape)
print(kolom)

Output yang Dihasilkan:

text
(3,)
(1, 3) (3, 1)
[[15000]
 [20000]
 [25000]]

Baris demi baris:

  1. Baris 3: harga adalah array 1-D berbentuk (3,).
  2. Baris 5 (expand_dims(harga, axis=0)): sumbu baru disisipkan di depan, menghasilkan (1, 3) — satu baris, tiga kolom.
  3. Baris 6 (expand_dims(harga, axis=1)): sumbu baru disisipkan di belakang, menghasilkan (3, 1) — tiga baris, satu kolom.
  4. Baris 8 (print(kolom)): nilai ditampilkan bertumpuk ke bawah; inilah yang disebut vektor kolom.

Kedua hasil memuat nilai yang sama; yang berbeda hanyalah orientasinya. axis=-1 juga sah dan berarti menyisipkan di posisi paling belakang, sama seperti axis=1 untuk array 1-D. Blok berikut membuktikan kedua hal itu sekaligus, termasuk sifat view dari hasilnya:

python
import numpy as np

harga = np.array([15000, 20000, 25000])
d = np.expand_dims(harga, axis=-1)
print(d.shape)
print(np.shares_memory(d, harga))

Output yang Dihasilkan:

text
(3, 1)
True

Penjelasan:

  1. Baris 4 (axis=-1): posisi negatif dihitung dari belakang, sehingga sumbu baru disisipkan setelah sumbu terakhir; bentuknya (3, 1), sama seperti axis=1 pada array 1-D.
  2. Baris 6 (np.shares_memory): hasil expand_dims adalah view yang berbagi buffer dengan harga, sehingga tercetak True. Menyisipkan sumbu tidak menyalin data sama sekali.

Padanannya dengan np.newaxis #

Indexed array dengan np.newaxis menghasilkan array yang sama tanpa memanggil fungsi. np.newaxis hanyalah alias untuk None; sumbu baru muncul di posisi di mana np.newaxis ditulis.

python
import numpy as np

harga = np.array([15000, 20000, 25000])
b1 = harga[np.newaxis, :]
k1 = harga[:, np.newaxis]
print(b1.shape, k1.shape)
print(np.array_equal(b1, np.expand_dims(harga, axis=0)))
print(np.array_equal(k1, np.expand_dims(harga, axis=1)))

Output yang Dihasilkan:

text
(1, 3) (3, 1)
True
True

Penjelasan:

  1. Baris 4 (harga[np.newaxis, :]): np.newaxis di posisi pertama menambah sumbu depan; hasilnya (1, 3).
  2. Baris 5 (harga[:, np.newaxis]): np.newaxis di posisi kedua menambah sumbu belakang; hasilnya (3, 1).
  3. Baris 7-8: np.array_equal memastikan hasil indexing identik dengan hasil expand_dims, sehingga keduanya tercetak True.

Tabel berikut memetakan keduanya:

EkspresiBentuk hasilSumbu baru berada di
harga[np.newaxis, :](1, 3)depan
harga[:, np.newaxis](3, 1)belakang
np.expand_dims(harga, axis=0)(1, 3)depan
np.expand_dims(harga, axis=1)(3, 1)belakang

Persiapan Broadcasting #

Motivasi terbesar sumbu berukuran satu adalah broadcasting: NumPy mengembangkan sumbu berukuran satu agar operasi aritmetika antar bentuk berbeda tetap berjalan. Dengan mengubah vektor harga menjadi kolom dan vektor potongan menjadi baris, satu penjumlahan menghasilkan seluruh kombinasi.

python
import numpy as np

harga = np.array([15000, 20000, 25000])
potongan = np.array([500, 1000])
kombinasi = harga[:, np.newaxis] + potongan[np.newaxis, :]
print(kombinasi.shape)
print(kombinasi)

Output yang Dihasilkan:

text
(3, 2)
[[15500 16000]
 [20500 21000]
 [25500 26000]]

Mari kita bedah:

  1. Baris 4: harga[:, np.newaxis] berbentuk (3, 1); setiap harga menempati satu baris.
  2. Baris 4 (lanjutan): potongan[np.newaxis, :] berbentuk (1, 2); dua nilai potongan berada dalam satu baris.
  3. Baris 5 (penjumlahan): NumPy mengembangkan (3, 1) menjadi (3, 2) dan (1, 2) menjadi (3, 2), lalu menjumlahkan; hasilnya (3, 2). Baris pertama adalah 15000 + 500 dan 15000 + 1000, dan seterusnya.

Aturan kapan pengembangan ini boleh terjadi akan dibahas lebih lanjut pada Chapter Memeriksa Kompatibilitas Bentuk dan diperdalam pada Section Broadcasting dan Vectorization. Sebagai gambaran awal: 3 melawan 2 tidak memenuhi syarat karena keduanya lebih besar dari satu dan tidak sama, sehingga penjumlahan harga + potongan tanpa penyesuaian sumbu akan ditolak NumPy. Sumbu berukuran satu pada (3, 1) dan (1, 2) itulah yang memberi izin kepada NumPy untuk mengembangkan kedua sisi menjadi (3, 2).

Orientasi juga menentukan makna hasil: harga[:, np.newaxis] menjadikan setiap harga satu baris (satu harga, banyak potongan), sedangkan harga[np.newaxis, :] menjadikan setiap harga satu kolom. Salah orientasi tidak selalu error; kadang hanya menghasilkan tabel yang tertransposkan dari maksud kita, maka biasakan mencetak hasilnya untuk diperiksa.