Bab-bab sebelumnya sudah beberapa kali memakai parameter axis tanpa membahasnya secara tuntas. Saatnya sekarang. Pada matriks penjualan tiga cabang x empat produk, “total penjualan per produk” dan “total penjualan per cabang” adalah dua pertanyaan berbeda yang dijawab fungsi yang sama; parameter axis yang menentukan arah perhitungannya.

Bab ini membedah cara kerja axis pada array dua dimensi: aturan membentuk hasil dari shape, makna axis=None, pembuktian arah perhitungan dengan perulangan biasa, lalu axis negatif dan pratinjau keepdims.

Aturan Dasar: axis adalah Sumbu yang Dihilangkan #

Cara paling andal memahami axis adalah lewat shape. Agregasi menghilangkan satu sumbu dari bentuk array, dan sumbu yang dihilangkan adalah sumbu yang diberikan ke axis:

python
import numpy as np

penjualan = np.array([
    [120, 85, 200, 65],
    [90, 150, 110, 40],
    [175, 60, 95, 130],
])
print(penjualan.shape)
print(penjualan.sum(axis=0))
print(penjualan.sum(axis=0).shape)
print(penjualan.sum(axis=1))
print(penjualan.sum(axis=1).shape)

Output yang Dihasilkan:

text
(3, 4)
[385 295 405 235]
(4,)
[470 390 460]
(3,)

Dari output di atas, kita bisa menurunkan hasilnya dengan tiga langkah:

  1. Shape asli (3, 4): sumbu 0 berisi 3 baris (cabang), sumbu 1 berisi 4 kolom (produk).
  2. axis=0: sumbu 0 dihilangkan dari shape, sisa (4,). Karena tinggal satu nilai per kolom, hasilnya adalah total per produk.
  3. axis=1: sumbu 1 dihilangkan, sisa (3,). Tinggal satu nilai per baris, hasilnya total per cabang.

Tabel berikut merangkum keduanya:

PemanggilanSumbu yang dilipatBentuk hasilMakna pada data cabang x produk
sum(axis=0)baris (cabang)(4,)total per produk
sum(axis=1)kolom (produk)(3,)total per cabang

axis=None: Seluruh Elemen Menjadi Satu Nilai #

Ketika axis tidak diberikan, agregasi berjalan atas seluruh elemen dan menghasilkan satu scalar. Menuliskan axis=None secara eksplisit memberi hasil yang sama, karena None memang default-nya:

python
import numpy as np

penjualan = np.array([
    [120, 85, 200, 65],
    [90, 150, 110, 40],
    [175, 60, 95, 130],
])
print(penjualan.sum())
print(penjualan.sum(axis=None))
print(penjualan.mean(axis=0))
print(penjualan.mean(axis=1))
print(penjualan.min(axis=1))

Output yang Dihasilkan:

text
1320
1320
[128.33333333  98.33333333 135.          78.33333333]
[117.5  97.5 115. ]
[65 40 60]

Dua baris pertama sama-sama menghasilkan 1320: total seluruh 12 sel. Tiga baris terakhir memakai fungsi lain dengan aturan shape yang identik. mean(axis=0) menghasilkan rata-rata per produk — misalnya 385 / 3 = 128.33333333 — sedangkan mean(axis=1) rata-rata per cabang: 470 / 4 = 117.5. min(axis=1) mencari produk dengan penjualan terendah di tiap cabang: [65 40 60].

Karena aturannya seragam, pemahaman axis yang dibangun di bab ini berlaku untuk mean, min, max, var, std, argmax, hingga cumsum pada Chapter Cumulative Sum dan Product.

Membuktikan Arah Perhitungan dengan Perulangan #

Bila aturan bentuk masih terasa rancu, kita buktikan bahwa sum(axis=0) memang sama dengan menjumlahkan tiap kolom secara manual — memakai slicing yang dibahas pada Chapter Slicing Array:

python
import numpy as np

penjualan = np.array([
    [120, 85, 200, 65],
    [90, 150, 110, 40],
    [175, 60, 95, 130],
])
per_kolom = [penjualan[:, k].sum() for k in range(4)]
print(np.array_equal(penjualan.sum(axis=0), per_kolom))
per_baris = [penjualan[b, :].sum() for b in range(3)]
print(np.array_equal(penjualan.sum(axis=1), per_baris))

Output yang Dihasilkan:

text
True
True

Bedah baris demi baris:

  1. Baris 8 (per_kolom = ...): penjualan[:, k] mengambil satu kolom penuh (semua baris, kolom ke-k). List comprehension menjumlahkan empat kolom satu per satu, meniru proses “berjalan ke bawah”.
  2. Baris 9 (np.array_equal(...)): membandingkan isi sum(axis=0) dengan daftar total kolom manual; hasilnya True, keduanya identik.
  3. Baris 10-11: pola yang sama untuk baris — penjualan[b, :] mengambil satu baris penuh — dan sum(axis=1) juga cocok sempurna.

Dengan pembuktian ini, “axis=0 melipat baris, hasilnya per kolom” bukan konvensi yang dihafal, melainkan konsekuensi yang bisa diturunkan sendiri kapan pun.

Axis Negatif dan Pratinjau keepdims #

axis juga menerima nilai negatif yang dihitung dari sumbu terakhir: axis=-1 berarti sumbu terakhir, axis=-2 sumbu sebelumnya. Untuk array dua dimensi, keduanya memetakan ke axis=1 dan axis=0:

python
import numpy as np

penjualan = np.array([
    [120, 85, 200, 65],
    [90, 150, 110, 40],
    [175, 60, 95, 130],
])
print(penjualan.sum(axis=-1))
print(penjualan.sum(axis=-2))
dengan = penjualan.sum(axis=1, keepdims=True)
print(dengan.shape)
print(dengan)

Output yang Dihasilkan:

text
[470 390 460]
[385 295 405 235]
(3, 1)
[[470]
 [390]
 [460]]

Dua baris pertama mengonfirmasi pemetaan: axis=-1 sama dengan axis=1 ([470 390 460]), dan axis=-2 sama dengan axis=0 ([385 295 405 235]). Pada array tiga dimensi atau lebih, kebiasaan menghitung dari belakang membantu menghindari salah hitung sumbu.

Parameter keepdims=True mengubah nasib sumbu yang dilipat: sumbu itu tidak dihilangkan, melainkan menyusut menjadi ukuran 1. Bentuk hasil (3, 4) dengan axis=1 berubah dari (3,) menjadi (3, 1) — terlihat sebagai vektor kolom [[470] [390] [460]].

Untuk apa bentuk (3, 1) ini berguna? Vektor kolom tersebut siap di-broadcast kembali ke bentuk (3, 4) asal, misalnya untuk mengurangkan rata-rata baris dari tiap sel barisnya. Mekanisme broadcasting itu sendiri dibahas pada Chapter Pengenalan Broadcasting, dan pemakaian keepdims yang berguna diperlihatkan pada Chapter Broadcasting dengan Dimensi Baru.