Laporan penjualan biasanya tidak berhenti pada angka total. Pemilik toko ingin tahu bagaimana total itu terbentuk: berapa akumulasi omzet sampai hari ketiga, pada hari keberapa kas melewati satu juta rupiah, dan seberapa cepat akumulasi tersebut tumbuh dari bulan ke bulan. NumPy menjawab kebutuhan semacam ini dengan dua fungsi akumulasi: np.cumsum untuk penjumlahan berjalan dan np.cumprod untuk perkalian berjalan.

Berbeda dengan np.sum yang menciutkan seluruh array menjadi satu angka, cumsum dan cumprod menghasilkan array baru yang bentuknya sama dengan input. Setiap elemen hasil menyimpan akumulasi dari elemen pertama hingga posisi tersebut. Bab ini membahas mekanisme kedua fungsi, penggunaan axis pada array 2-D, serta perbedaan bentuk hasil antara agregasi dan akumulasi.

Dari sum ke Akumulasi Berjalan #

Secara matematis, elemen ke-i dari np.cumsum(a) adalah a[0] + a[1] + ... + a[i]. Tidak ada elemen yang dibuang; setiap tahap penjumlahan justru disimpan sebagai hasil. Mari kita bandingkan langsung dengan np.sum pada data setoran kasir harian:

python
import numpy as np

setoran = np.array([150, 200, 120, 180, 250])  # ribu rupiah per hari

total = np.sum(setoran)
saldo = np.cumsum(setoran)

print("total :", total)
print("saldo :", saldo)
print("shape total:", total.shape)
print("shape saldo:", saldo.shape)
print("saldo akhir == total:", saldo[-1] == total)

Output yang Dihasilkan:

text
total : 900
saldo : [150 350 470 650 900]
shape total: ()
shape saldo: (5,)
saldo akhir == total: True

Mari kita bedah apa yang dilakukan interpreter pada kode di atas:

  1. Baris 3 (np.array(...)): interpreter membuat array 1-D bertipe int64 dengan lima elemen setoran harian dalam ribu rupiah.
  2. Baris 5 (np.sum(setoran)): seluruh elemen diringkas menjadi satu nilai skalar 900 dengan bentuk ().
  3. Baris 6 (np.cumsum(setoran)): menghasilkan array lima elemen; elemen ke-0 adalah 150, elemen ke-1 adalah 150 + 200 = 350, dan seterusnya hingga 900.
  4. Baris 10-11 (total.shape, saldo.shape): perbandingan bentuk memperlihatkan perbedaan mendasar — agregasi menciutkan ke (), akumulasi mempertahankan (5,).
  5. Baris 12 (saldo[-1] == total): elemen terakhir hasil cumsum selalu sama dengan total; identitas ini berguna sebagai pemeriksa cepat kebenaran perhitungan.

cumprod untuk Pertumbuhan Berantai #

Pertumbuhan persentase tidak boleh dijumlahkan, melainkan dikalikan. Kenaikan 5% dinyatakan sebagai faktor 1.05 dan penurunan 2% sebagai faktor 0.98. Untuk melacak indeks berjalan dari serangkaian faktor tersebut, kita memakai np.cumprod:

python
import numpy as np

faktor_bulanan = np.array([1.0, 1.05, 1.05, 0.98, 1.02])

indeks = np.cumprod(faktor_bulanan)

print("faktor :", faktor_bulanan)
print("indeks :", indeks)
print("indeks akhir:", indeks[-1])

Output yang Dihasilkan:

text
faktor : [1.   1.05 1.05 0.98 1.02]
indeks : [1.       1.05     1.1025   1.08045  1.102059]
indeks akhir: 1.102059

Tiga hal yang perlu kita amati:

  1. Baris 3: array faktor pengali bulanan; bulan pertama menjadi acuan sehingga faktornya 1.0.
  2. Baris 5 (np.cumprod(...)): akumulasi perkalian berjalan — 1.0, lalu 1.05, lalu 1.05 × 1.05 = 1.1025, lalu 1.1025 × 0.98 = 1.08045, dan terakhir 1.08045 × 1.02 = 1.102059.
  3. Baris 9: elemen terakhir adalah faktor pengali total lima bulan; penjualan akhir bulan kelima setara dengan kenaikan sekitar 10,2% dibanding bulan acuan.

Akumulasi pada Array 2-D dengan axis #

Sama seperti fungsi agregasi lain, cumsum menerima parameter axis. Arah axis menentukan sepanjang garis mana akumulasi dijalankan: axis=0 mengakumulasi ke bawah (antar baris dalam satu kolom), sedangkan axis=1 mengakumulasi ke kanan (antar kolom dalam satu baris). Tanpa axis, array diratakan menjadi 1-D terlebih dahulu:

python
import numpy as np

penjualan = np.array([
    [50, 65, 40],
    [70, 55, 80],
    [45, 60, 75],
])  # baris: cabang, kolom: hari

print("axis=0 (akumulasi ke bawah):")
print(np.cumsum(penjualan, axis=0))
print("axis=1 (akumulasi ke kanan):")
print(np.cumsum(penjualan, axis=1))
print("tanpa axis (diratakan):")
print(np.cumsum(penjualan))

Output yang Dihasilkan:

text
axis=0 (akumulasi ke bawah):
[[ 50  65  40]
 [120 120 120]
 [165 180 195]]
axis=1 (akumulasi ke kanan):
[[ 50 115 155]
 [ 70 125 205]
 [ 45 105 180]]
tanpa axis (diratakan):
[ 50 115 155 225 280 360 405 465 540]

Pada axis=0, baris kedua hasil adalah penjumlahan baris pertama dan kedua data (120 = 50 + 70 untuk kolom pertama), dan baris ketiga hasil menumpuk tiga baris data (165 = 50 + 70 + 45). Pada axis=1, kolom kedua hasil adalah penjumlahan dua kolom pertama data per baris (115 = 50 + 65). Versi tanpa axis meratakan sembilan elemen mengikuti urutan C, lalu mengakumulasi semuanya menjadi array (9,). Semantik axis yang lebih umum sudah dibahas pada Chapter Operasi Berdasarkan Axis.

Sebagai penutup, tabel berikut merangkum perbedaan fungsi agregasi dan akumulasi yang kita pakai sejak Chapter sum dan prod:

FungsiPertanyaan yang dijawabBentuk hasil
np.sumBerapa total seluruh elemen?menciutkan (skalar untuk 1-D)
np.prodBerapa hasil kali seluruh elemen?menciutkan (skalar untuk 1-D)
np.cumsumBerapa total berjalan sampai titik ini?sama dengan input
np.cumprodBerapa perkalian berjalan sampai titik ini?sama dengan input