Bagian 2 berakhir dengan dataset bersih 1305 baris; 45 kombinasi tanggal, komoditas, dan kota tidak memiliki baris sama sekali. Penghitungan perubahan harga membandingkan harga hari ini dengan hari sebelumnya, sehingga tanggal yang hilang memutus perbandingan. Bagian ini membentuk matriks harga harian 90 hari x 5 komoditas, mengisi sel kosong dengan interpolasi, lalu mengukur perubahan harga memakai pct_change(), diff(), dan resample(). Hasilnya menjawab pertanyaan inti proyek: komoditas mana yang naik paling tajam, kapan lonjakan terbesar terjadi, dan seberapa besar perubahan tiga bulan.

Matriks Harga Harian dan Interpolasi #

Dataset bersih tersimpan dalam format panjang: satu baris per kombinasi tanggal-komoditas-kota. Untuk mengukur perubahan antar hari, format panjang diputar menjadi matriks lebar dengan pivot_table() — materi section Menggabungkan dan Membentuk Data — dengan tanggal sebagai index dan komoditas sebagai columns. Setiap komoditas memiliki tiga harga kota pada satu tanggal, sehingga aggfunc="mean" merata-ratakannya menjadi satu harga harian per sel. reindex() menyusun index ke kalender 90 hari penuh dan menyisipkan baris untuk tanggal yang hilang. Hasilnya matriks 90 x 5 dengan 15 sel NaN: 45 baris hilang dibagi tiga kota.

Interpolasi linear dari chapter Interpolasi Data mengisi sel yang terjepit dua harga, sedangkan ffill() dan bfill() dari chapter Forward Fill dan Backward Fill menutup sel di tepi periode; setelahnya matriks bebas NaN, syarat perhitungan berikutnya.

Menjalankan Analisis Perubahan Harga #

Skrip perubahan_harga.py memakai ulang fungsi buat_dataset() dan bersihkan() dari buat_dataset.py di folder yang sama, lalu menjalankan: membangun matriks, memverifikasi dua jalur persentase, menghitung perubahan total dan harian, merangkum ritme mingguan.

python
"""Menganalisis perubahan harga harian dan mingguan per komoditas."""
from pathlib import Path
import tempfile

import pandas as pd

from buat_dataset import bersihkan, buat_dataset


def matriks_harian(bersih: pd.DataFrame) -> pd.DataFrame:
    """Matriks harga rata-rata harian antar kota (baris = tanggal, kolom = komoditas)."""
    harian = bersih.pivot_table(
        index="tanggal", columns="komoditas", values="harga", aggfunc="mean"
    )
    kalender = pd.date_range("2026-01-01", "2026-03-31", freq="D")
    harian = harian.reindex(kalender)
    harian.index.name = "tanggal"
    return harian


if __name__ == "__main__":
    with tempfile.TemporaryDirectory() as folder:
        berkas = Path(folder) / "harga_komoditas.csv"
        buat_dataset().to_csv(berkas, index=False)
        mentah = pd.read_csv(berkas)

    df = bersihkan(mentah)
    harian = matriks_harian(df)
    print(f"matriks harian: {harian.shape[0]} hari x {harian.shape[1]} komoditas")
    print(f"sel NaN sebelum interpolasi: {harian.isna().sum().sum()}")
    harian = harian.interpolate().ffill().bfill()
    print(f"sel NaN setelah interpolasi: {harian.isna().sum().sum()}")

    panjang = harian.stack().rename("harga").reset_index()
    panjang = panjang.sort_values(["komoditas", "tanggal"], ignore_index=True)
    panjang["pct_grup"] = panjang.groupby("komoditas")["harga"].pct_change()
    ulang = panjang.pivot_table(index="tanggal", columns="komoditas", values="pct_grup")
    cocok = (ulang - harian.pct_change()).abs().max().max() < 1e-9
    print(f"pct_change groupby cocok dengan matriks: {cocok}")

    perubahan = harian.pct_change() * 100
    total = (harian.iloc[-1] / harian.iloc[0] - 1) * 100
    print("\n== Perubahan total 1 Jan - 31 Mar 2026 (persen) ==")
    print(total.sort_values(ascending=False).round(2).to_string())

    print("\n== Kenaikan harian terbesar (idxmax) ==")
    for nama in harian.columns:
        print(
            f"{nama:24s} +{perubahan[nama].max():.1f}% "
            f"pada {perubahan[nama].idxmax():%d %b}"
        )

    print("\n== Penurunan harian terbesar (idxmin) ==")
    for nama in harian.columns:
        print(
            f"{nama:24s} {perubahan[nama].min():.1f}% "
            f"pada {perubahan[nama].idxmin():%d %b}"
        )

    lonjakan = perubahan.stack()
    tanggal, nama = lonjakan.idxmax()
    print(f"\nlonjakan terbesar : {nama} +{lonjakan.max():.1f}% pada {tanggal:%d %b %Y}")
    tanggal, nama = lonjakan.idxmin()
    print(f"koreksi terdalam  : {nama} {lonjakan.min():.1f}% pada {tanggal:%d %b %Y}")

    selisih_rupiah = harian.diff()
    tanggal, nama = selisih_rupiah.abs().stack().idxmax()
    nilai = selisih_rupiah.loc[tanggal, nama]
    arah = "naik" if nilai > 0 else "turun"
    print(
        f"perubahan Rp terbesar: {nama} {arah} Rp{abs(nilai):,.0f} pada {tanggal:%d %b %Y}"
    )

    mingguan = harian.resample("W").mean()
    perubahan_mingguan = mingguan.pct_change() * 100
    kolom = perubahan_mingguan["Cabai Merah Keriting"]
    print(f"\nminggu (resample W)  : {len(mingguan)} periode")
    print(f"minggu terbaik cabai : {kolom.idxmax():%d %b} (+{kolom.max():.1f}%)")
    print(f"minggu terburuk cabai: {kolom.idxmin():%d %b} ({kolom.min():.1f}%)")

Output yang Dihasilkan:

text
matriks harian: 90 hari x 5 komoditas
sel NaN sebelum interpolasi: 15
sel NaN setelah interpolasi: 0
pct_change groupby cocok dengan matriks: True

== Perubahan total 1 Jan - 31 Mar 2026 (persen) ==
komoditas
Beras Premium            6.42
Cabai Merah Keriting     6.28
Gula Pasir               3.37
Bawang Merah             0.90
Minyak Goreng Kemasan    0.06

== Kenaikan harian terbesar (idxmax) ==
Bawang Merah             +3.6% pada 10 Jan
Beras Premium            +2.5% pada 28 Jan
Cabai Merah Keriting     +8.8% pada 15 Feb
Gula Pasir               +2.3% pada 22 Mar
Minyak Goreng Kemasan    +2.2% pada 15 Jan

== Penurunan harian terbesar (idxmin) ==
Bawang Merah             -2.8% pada 09 Jan
Beras Premium            -2.6% pada 29 Jan
Cabai Merah Keriting     -9.1% pada 21 Feb
Gula Pasir               -2.0% pada 01 Feb
Minyak Goreng Kemasan    -1.5% pada 28 Mar

lonjakan terbesar : Cabai Merah Keriting +8.8% pada 15 Feb 2026
koreksi terdalam  : Cabai Merah Keriting -9.1% pada 21 Feb 2026
perubahan Rp terbesar: Cabai Merah Keriting turun Rp8,590 pada 21 Feb 2026

minggu (resample W)  : 14 periode
minggu terbaik cabai : 15 Feb (+24.6%)
minggu terburuk cabai: 08 Mar (-21.8%)

Mari kita telaah bagian-bagian pentingnya:

  1. matriks_harian(): pivot_table() memutar data ke format lebar, reindex() menyusun kalender 90 hari; matriks 90 x 5 dengan 15 sel NaN sebelum interpolasi, 0 sesudahnya.
  2. Verifikasi dua jalur: persentase dihitung pada format panjang lewat groupby("komoditas")["harga"].pct_change(), lalu diputar kembali ke matriks; selisih maksimumnya di bawah 1e-9, hasil True — untuk grid lengkap kedua jalur setara.
  3. Perubahan total: harian.iloc[-1] / harian.iloc[0] - 1 membandingkan harga 31 Maret dengan 1 Januari; hasil diurutkan menurun, Beras Premium (+6.42%) di atas.
  4. idxmax() dan idxmin(): setiap kolom diuji untuk menemukan tanggal kenaikan dan penurunan harian terbesar; cabai +8.8% pada 15 Feb dan -9.1% pada 21 Feb.
  5. stack(): matriks persentase dipipihkan menjadi Series pasangan (tanggal, komoditas); idxmax() mengembalikan tuple: lonjakan terbesar cabai +8.8% pada 15 Feb 2026.
  6. diff(): selisih rupiah antar hari; abs().stack().idxmax() menemukan pergerakan Rp terbesar, yaitu cabai turun Rp8,590 pada 21 Feb 2026.
  7. resample("W"): harga dirata-ratakan per minggu menghasilkan 14 periode; pct_change() antar minggu menunjukkan minggu terbaik cabai +24.6% dan minggu terburuk -21.8%.

Membaca Temuan Perubahan Harga #

Tabel perubahan total merangkum cerita tiga bulan:

KomoditasPerubahan totalLonjakan harianPenurunan terdalam
Beras Premium+6.42%+2.5% (28 Jan)-2.6% (29 Jan)
Cabai Merah Keriting+6.28%+8.8% (15 Feb)-9.1% (21 Feb)
Gula Pasir+3.37%+2.3% (22 Mar)-2.0% (1 Feb)
Bawang Merah+0.90%+3.6% (10 Jan)-2.8% (9 Jan)
Minyak Goreng Kemasan+0.06%+2.2% (15 Jan)-1.5% (28 Mar)

Cabai bergerak paling tajam per hari, tetapi perubahan totalnya nyaris sama dengan beras yang naik pelan dan konsisten; dua pola ini baru terlihat dalam matriks bersih. Keputusan Bagian 2 mempertahankan lonjakan cabai kini terbukti tepat: lonjakan itu jadi sinyal utama analisis, bukan kebisingan data.

Matriks lengkap kini sudah bercerita: perubahan total, lonjakan harian, koreksi terdalam, dan ritme mingguan telah terukur. Pertanyaan berikutnya membandingkan komoditas berbeda skala harga: rata-rata bulanan, kenaikan sejak titik awal yang sama, dan ketergerakan antar komoditas. Bagian 4 menjawabnya dengan resample("ME"), indeks basis 100, dan korelasi, lalu menutup proyek dengan ringkasan siap ekspor.

Sumber bacaan resmi: pandas.DataFrame.pct_change , pandas.DataFrame.diff , dan pandas.DataFrame.resample .