Level harga seperti “beras Rp15 000” nyaris tidak bercerita; analis pasar justru hidup dari perubahannya — berapa rupiah naiknya, berapa persen turunnya, dan sebesar apa fluktuasinya. Bagian ini menghitung tiga besaran itu langsung dari array harga yang dibangun pada Bagian 1: Menyiapkan Data Harga: perubahan persentase harian dari perbandingan array bergeser, perubahan rupiah dari np.diff, serta volatilitas dari simpangan baku perubahan persentase.

Seluruh perhitungan berjalan pada dua dimensi sekaligus (360 hari × 3 komoditas) tanpa satu pun loop eksplisit. Pola yang dipakai adalah vektorisasi biasa — pasangan slice a[1:] dan a[:-1] dari Chapter Slicing Array, agregasi axis=0 dari Chapter Operasi Berdasarkan Axis.

Perubahan Persentase Harian #

Perubahan persentase hari ke t didefinisikan sebagai harga[t]/harga[t-1] - 1. Padanan vektorisasinya menumpuk dua slice: harga[1:] (hari kedua sampai terakhir) dibagi harga[:-1] (hari pertama sampai kedua terakhir):

python
import numpy as np

# Pembangun deret harga 2025 (identik dengan Bagian 1).
rng = np.random.default_rng(42)
awal = np.array([15000.0, 45000.0, 18000.0])
drift = np.array([0.0003, 0.0012, 0.0004])
sigma = np.array([0.006, 0.030, 0.010])
musim = 1 - np.array([0.01, 0.15, 0.03]) * np.cos(2 * np.pi * np.arange(360) / 360)[:, None]
guncangan = drift + rng.normal(0.0, sigma, (360, 3))
harga = awal * np.cumprod(1 + guncangan, axis=0) * musim

pct = harga[1:] / harga[:-1] - 1
print("shape:", pct.shape)
print(np.round(pct[:3], 4))

Output yang Dihasilkan:

text
shape: (359, 3)
[[ 0.0059 -0.0573 -0.0126]
 [ 0.0011 -0.0082  0.0002]
 [-0.0048  0.0277  0.0082]]

Mekanismenya:

  1. harga[1:] / harga[:-1]: dua view berukuran 359 × 3 dibagi per elemen; baris ke-i hasilnya adalah rasio harga hari i+1 terhadap hari i — satu hari lebih pendek daripada deret asal, karena hari pertama tidak punya pendahulu.
  2. - 1: mengubah rasio menjadi fraksi perubahan; 0.0059 berarti beras naik 0.59% pada hari kedua, sedangkan cabai turun 5.73% pada hari yang sama — lonjakan pembuka yang khas komoditas bervolatilitas tinggi.
  3. np.round(pct[:3], 4): tiga baris pertama ditampilkan empat desimal; fraksi ini nanti dikalikan 100 jika ingin ditulis sebagai persen.

Perhatikan bahwa pct bukan sekadar angka baru: ia menggabungkan efek drift, guncangan, dan rasio faktor musiman antar dua hari berurutan. Deret inilah bahan mentah statistik sisa bagian ini.

Perubahan Rupiah dengan np.diff #

Untuk beberapa keperluan — margin pedagang, anggaran rumah tangga — perubahan dalam rupiah lebih bermakna. np.diff menghitung selisih berurutan di sepanjang axis yang dipilih, dan bersama argmax/argmin (Chapter min, max, argmin, dan argmax) kita bisa menemukan hari kenaikan serta penurunan terbesar tiap komoditas:

python
import numpy as np

# Pembangun deret harga 2025 (identik dengan Bagian 1).
rng = np.random.default_rng(42)
awal = np.array([15000.0, 45000.0, 18000.0])
drift = np.array([0.0003, 0.0012, 0.0004])
sigma = np.array([0.006, 0.030, 0.010])
musim = 1 - np.array([0.01, 0.15, 0.03]) * np.cos(2 * np.pi * np.arange(360) / 360)[:, None]
guncangan = drift + rng.normal(0.0, sigma, (360, 3))
harga = awal * np.cumprod(1 + guncangan, axis=0) * musim

selisih = np.diff(harga, axis=0)
print("shape:", selisih.shape)
tanggal = np.arange(np.datetime64("2025-01-01"), np.datetime64("2025-12-27"))
nama = np.array(["beras", "cabai", "minyak goreng"])
i_naik = np.argmax(selisih, axis=0)
i_turun = np.argmin(selisih, axis=0)
for k in range(3):
    i, j = i_naik[k], i_turun[k]
    print(f"{nama[k]:<14} naik  {tanggal[i + 1]}  {selisih[i, k]:+10.2f}")
    print(f"{nama[k]:<14} turun {tanggal[j + 1]}  {selisih[j, k]:+10.2f}")

Output yang Dihasilkan:

text
shape: (359, 3)
beras          naik  2025-10-10     +300.04
beras          turun 2025-06-18     -280.07
cabai          naik  2025-02-16    +3043.55
cabai          turun 2025-11-13    -3744.06
minyak goreng  naik  2025-06-09     +540.76
minyak goreng  turun 2025-11-12     -532.10

Yang perlu diperhatikan:

  1. np.diff(harga, axis=0): selisih antar baris berurutan; hasilnya 359 × 3, satu baris lebih pendek, sama seperti pct.
  2. np.argmax(selisih, axis=0): mencari posisi nilai maksimum per kolom, sehingga satu indeks keluar untuk tiap komoditas tanpa loop.
  3. tanggal[i + 1]: baris ke-i dari selisih adalah perubahan dari hari i ke hari i+1, maka tanggal peristiwanya adalah tanggal[i + 1] — rincian satu-per satu ini paling sering keliru saat manual.
  4. Kenaikan cabai Rp3 043,55 pada 16 Februari: setara sekitar +7.5% dalam sehari; pada komoditas yang harganya 45 ribuan, guncangan harian 3% memang mudah menghasilkan lompatan ribuan rupiah.

Volatilitas dan Arah Harian #

Volatilitas harian didefinisikan sebagai simpangan baku pct per kolom (Chapter Variance dan Standard Deviation). Pasangannya adalah statistik arah: berapa hari harga naik dan berapa hari turun, yang dihitung dari mask boolean (Chapter Counting dan Frekuensi):

python
import numpy as np

# Pembangun deret harga 2025 (identik dengan Bagian 1).
rng = np.random.default_rng(42)
awal = np.array([15000.0, 45000.0, 18000.0])
drift = np.array([0.0003, 0.0012, 0.0004])
sigma = np.array([0.006, 0.030, 0.010])
musim = 1 - np.array([0.01, 0.15, 0.03]) * np.cos(2 * np.pi * np.arange(360) / 360)[:, None]
guncangan = drift + rng.normal(0.0, sigma, (360, 3))
harga = awal * np.cumprod(1 + guncangan, axis=0) * musim

pct = harga[1:] / harga[:-1] - 1
vol = pct.std(axis=0, ddof=1)
nama = np.array(["beras", "cabai", "minyak goreng"])
for k in range(3):
    print(f"{nama[k]:<14} vol {vol[k]:.4f}   hari naik {np.sum(pct[:, k] > 0):3d}   hari turun {np.sum(pct[:, k] < 0):3d}")

Output yang Dihasilkan:

text
beras          vol 0.0062   hari naik 186   hari turun 173
cabai          vol 0.0290   hari naik 179   hari turun 180
minyak goreng  vol 0.0096   hari naik 187   hari turun 172

Pembacaan hasilnya:

  1. pct.std(axis=0, ddof=1): simpangan baku dengan pembagi n - 1 — estimasi tak biasa dari 359 sampel; ddof=0 bawaan akan memberi angka sedikit lebih kecil.
  2. Volatilitas cabai 0.0290: hampir lima kali volatilitas beras (0.0062) — angka ringkas yang menjelaskan mengapa harga cabai paling sering menjadi berita.
  3. np.sum(pct[:, k] > 0): mask boolean dijumlahkan per komoditas; hari naik dan turun hampir berimbang (sekitar 50:50) — arah rata-rata memang ditentukan drift yang kecil, bukan oleh kecenderungan harian.

Tiga besaran di bagian ini — pct, selisih, dan vol — tersimpan rapi sebagai array dan siap dipakai Bagian 3: Menganalisis Statistik. Dalam struktur proyek, seluruhnya kita kemas sebagai src/perubahan.py dengan satu fungsi per besaran.