Proyek kedua Course ini membawa kita ke dapur sebuah warung nasi. Kita menganalisis pergerakan harga komoditas pangan secara utuh: memahami konteks data harga, mengumpulkan data historis, memvalidasi dan membersihkan nilai tidak wajar, menganalisis statistik harga serta pola tren dan musiman, membandingkan antar komoditas, lalu mengemas temuan menjadi laporan yang dapat ditindaklanjuti. Seluruh alur dikerjakan bertahap dalam sepuluh bagian, dan setiap angka pada laporan akhir dihitung oleh pipeline yang sama sehingga hasilnya dapat diulang siapa pun.

Cerita: Warung Nasi Bu Warni #

Bu Warni mengelola warung nasi kecil di Surabaya. Menu andalannya bertumpu pada lima bahan: beras, cabai merah, bawang merah, ayam broiler, dan gula pasir. Selama delapan pekan — M1 sampai M8, dari pekan yang dimulai 5 Januari 2026 hingga pekan yang dimulai 23 Februari 2026 — ia mencatat harga rata-rata tiap bahan per pekan dari catatan belanja mingguannya dan harga di pasar sekitar warung. Hasilnya satu berkas CSV kecil yang ternyata tidak sepenuhnya bersih, persis seperti data dunia nyata.

Yang ingin diketahui Bu Warni sederhana tetapi berdampak langsung pada penghasilannya: bahan mana yang harganya paling tidak menentu, kapan sebaiknya ia menambah stok, menu apa yang perlu digeser saat harga bahan tertentu melonjak, dan bagaimana menetapkan harga jual agar tidak merugi saat bahan mahal. Proyek ini menjawab pertanyaan-pertanyaan tersebut dengan data, bukan dengan perasaan.

Isi Proyek Ini #

Proyek tersusun atas tiga berkas pendukung dan sepuluh bagian pengerjaan:

BerkasPeran
data/harga_komoditas.csvDataset mentah: catatan harga 8 pekan untuk 5 komoditas
src/analisis_harga.pyPipeline utuh dari muat data sampai penulisan laporan
laporan/laporan-akhir.txtLaporan akhir yang ditulis otomatis oleh pipeline
part-1-… sampai part-10-…Tahapan pengerjaan berurutan, satu topik per bagian

Dataset mentah mengandung beberapa masalah kecil yang sengaja kita biarkan apa adanya, lalu kita temukan pada Bagian 3 dan perbaiki pada Bagian 4 — karena itulah cara kerja proyek data nyata: data diperiksa dulu, baru dipercaya.

Untuk menjalankan pipeline di komputer Anda, unduh ketiga berkas pendukung dari halaman ini (tautan unduh ada pada kepala tiap blok kode di bawah), susun dengan struktur folder yang sama, lalu jalankan dari folder proyek:

bash
python3 src/analisis_harga.py

Pipeline ini deterministik: tanpa akses jaringan, tanpa pembacaan jam sistem, dan selalu menghasilkan laporan yang identik dari data yang sama.

Dataset Harga Komoditas #

Berkas data/harga_komoditas.csv berbentuk panjang: satu baris per pekan per komoditas, dengan tiga kolom.

KolomMakna
mingguPenanda pekan M1–M8; M1 adalah pekan yang dimulai 5 Januari 2026
komoditasNama bahan: beras, cabai merah, bawang merah, ayam broiler, atau gula pasir
harga_rata_ribuHarga rata-rata pekan tersebut, dalam ribu rupiah per kilogram

Berikut isi lengkapnya — perhatikan bahwa jumlah barisnya lebih banyak daripada 8 pekan × 5 komoditas:

csv
minggu,komoditas,harga_rata_ribu
M1,beras,13.0
M1,cabai merah,38.0
M1,bawang merah,30.0
M1,ayam broiler,33.0
M1,gula pasir,17.5
M2,beras,13.2
M2,cabai merah,40.0
M2,bawang merah,34.0
M2,ayam broiler,33.5
M2,gula pasir,17.6
M3,beras,13.1
M3,cabai merah,42.0
M3,cabai merah,42.0
M3,bawang merah,31.0
M3,ayam broiler,33.2
M3,gula pasir,17.5
M4,beras,13.3
M4,cabai merah,65.0
M4,bawang merah,36.0
M4,ayam broiler,33.8
M4,gula pasir,17.7
M5,beras,13.2
M5,cabai merah,78.0
M5,bawang merah,33.0
M5,ayam broiler,34.0
M5,gula pasir,17.6
M6,beras,13.4
M6,cabai merah,55.0
M6,bawang merah,-
M6,ayam broiler,34.5
M6,gula pasir,17.8
M7,beras,13.3
M7,Cabai Merah,44.0
M7,bawang merah,32.0
M7,ayam broiler,34.8
M7,gula pasir,17.7
M8,beras,13.5
M8,cabai merah,40.0
M8,bawang merah,35.0
M8,ayam broiler,35.2
M8,gula pasir,17.8

Pipeline Analisis #

Seluruh analisis dirangkai dalam satu skrip, src/analisis_harga.py. Skrip ini memuat data, memeriksa masalahnya, membersihkannya, menghitung statistik per komoditas, menemukan perubahan pekan-ke-pekan terbesar, merangkum lonjakan cabai merah, lalu menulis laporan lengkap ke laporan/laporan-akhir.txt.

python
"""analisis_harga.py: pipeline analisis harga komoditas Warung Nasi Bu Warni.

Pipeline ini menjalankan alur utuh satu proyek analisis data harga:
muat data mentah, periksa masalah, bersihkan, hitung statistik per
komoditas, temukan perubahan pekan-ke-pekan terbesar dan lonjakan
cabai merah, lalu tulis laporan lengkap ke laporan/laporan-akhir.txt.

Cara menjalankan (dari folder proyek analisis-harga-komoditas):

    python3 src/analisis_harga.py

Pipeline ini deterministik: tidak membaca jam sistem, tidak mengakses
jaringan, dan selalu menghasilkan keluaran yang sama dari data yang sama.
"""

from pathlib import Path

import pandas as pd

BERKAS_DATA = Path("data/harga_komoditas.csv")
BERKAS_LAPORAN = Path("laporan/laporan-akhir.txt")

NAMA_KOMODITAS = [
    "beras",
    "cabai merah",
    "bawang merah",
    "ayam broiler",
    "gula pasir",
]
PEKAN_M1 = "5 Januari 2026"
PEKAN_M8 = "23 Februari 2026"


def muat_data() -> pd.DataFrame:
    """Baca data mentah harga komoditas dari berkas CSV."""
    df = pd.read_csv(BERKAS_DATA)
    print(f"[1] Muat data mentah   : {df.shape[0]} baris, {df.shape[1]} kolom")
    return df


def periksa_masalah(df: pd.DataFrame) -> dict:
    """Kumpulkan temuan masalah pada data mentah sebelum dibersihkan."""
    nama = df["komoditas"].str.strip()
    tak_seragam = sorted(set(nama) - set(NAMA_KOMODITAS))
    masalah = {
        "duplikat": int(df.duplicated().sum()),
        "kosong": int((df["harga_rata_ribu"] == "-").sum()),
        "tak_seragam": tak_seragam,
    }

    ringkas = [f"{masalah['duplikat']} baris duplikat"]
    ringkas.append(f"{masalah['kosong']} sel harga kosong")
    if tak_seragam:
        ringkas.append("nama tak konsisten: " + ", ".join(tak_seragam))
    print("[2] Temuan validasi    : " + "; ".join(ringkas))
    return masalah


def bersihkan(df: pd.DataFrame) -> tuple[pd.DataFrame, list[str]]:
    """Buang duplikat, seragamkan nama, ubah '-' jadi NaN lalu interpolasi."""
    bersih = df.drop_duplicates(subset=["minggu", "komoditas"], keep="first").copy()
    bersih["komoditas"] = bersih["komoditas"].str.strip().str.lower()
    bersih["harga_rata_ribu"] = pd.to_numeric(bersih["harga_rata_ribu"], errors="coerce")
    bersih = bersih.sort_values(["komoditas", "minggu"]).reset_index(drop=True)

    # Catat sel kosong lebih dulu supaya nilai hasil interpolasi bisa dilaporkan.
    kosong = bersih[bersih["harga_rata_ribu"].isna()][["minggu", "komoditas"]]
    bersih["harga_rata_ribu"] = bersih.groupby("komoditas")["harga_rata_ribu"].transform(
        lambda s: s.interpolate()
    )

    catatan_isi = []
    for _, baris in kosong.iterrows():
        nilai = bersih.loc[
            (bersih["komoditas"] == baris["komoditas"]) & (bersih["minggu"] == baris["minggu"]),
            "harga_rata_ribu",
        ].iloc[0]
        catatan_isi.append(f"{baris['komoditas']} {baris['minggu']} = {nilai:.1f}")

    keterangan = f"{len(bersih)} baris bersih"
    if catatan_isi:
        keterangan += "; sel kosong diisi interpolasi (" + ", ".join(catatan_isi) + ")"
    print(f"[3] Pembersihan        : {keterangan}")
    return bersih, catatan_isi


def statistik_harga(bersih: pd.DataFrame) -> pd.DataFrame:
    """Hitung mean, std, min, max, dan koefisien variasi per komoditas."""
    stat = bersih.groupby("komoditas")["harga_rata_ribu"].agg(["mean", "std", "min", "max"])
    stat["cv"] = stat["std"] / stat["mean"] * 100
    print("[4] Statistik harga (ribu rupiah per kg):")
    for komoditas, baris in stat.iterrows():
        print(
            f"      {komoditas:<12} mean {baris['mean']:6.2f}  std {baris['std']:5.2f}"
            f"  min {baris['min']:5.2f}  max {baris['max']:5.2f}"
            f"  cv {baris['cv']:5.2f}%"
        )
    return stat


def perubahan_terbesar(bersih: pd.DataFrame, n: int = 5) -> pd.DataFrame:
    """Cari n perubahan harga pekan-ke-pekan terbesar (menurut besaran)."""
    urut = bersih.sort_values(["komoditas", "minggu"]).copy()
    urut["minggu_sebelum"] = urut.groupby("komoditas")["minggu"].shift(1)
    urut["harga_sebelum"] = urut.groupby("komoditas")["harga_rata_ribu"].shift(1)
    urut["pct"] = urut.groupby("komoditas")["harga_rata_ribu"].pct_change() * 100
    urut = urut.dropna(subset=["pct"])
    urut = urut.reindex(urut["pct"].abs().sort_values(ascending=False).index)

    teratas = urut.iloc[0]
    print(
        f"[5] Perubahan terbesar : {teratas['komoditas']} {teratas['minggu_sebelum']}"
        f" -> {teratas['minggu']} ({teratas['pct']:+.1f}%,"
        f" {teratas['harga_sebelum']:.1f} -> {teratas['harga_rata_ribu']:.1f})"
    )
    return urut.head(n)


def ringkasan_cabai(bersih: pd.DataFrame) -> dict:
    """Kumpulkan angka kunci lonjakan cabai merah."""
    cabai = bersih[bersih["komoditas"] == "cabai merah"].set_index("minggu")["harga_rata_ribu"]
    puncak_pekan = cabai.idxmax()
    puncak = float(cabai.max())
    awal = float(cabai["M1"])
    print(
        f"[6] Lonjakan cabai     : puncak {puncak_pekan} {puncak:.1f} ribu"
        f" ({puncak / awal:.1f}x harga awal M1 {awal:.1f}),"
        f" kembali {cabai['M8']:.1f} pada M8"
    )
    return {
        "m1": awal,
        "m3": float(cabai["M3"]),
        "m4": float(cabai["M4"]),
        "m5": float(cabai["M5"]),
        "m6": float(cabai["M6"]),
        "m7": float(cabai["M7"]),
        "m8": float(cabai["M8"]),
        "puncak_pekan": puncak_pekan,
        "puncak": puncak,
        "m3_ke_m5": (float(cabai["M5"]) / float(cabai["M3"]) - 1) * 100,
    }


def tren_akhir(bersih: pd.DataFrame) -> pd.DataFrame:
    """Bandingkan harga pekan awal (M1) dan pekan akhir (M8) per komoditas."""
    pivot = bersih.pivot(index="minggu", columns="komoditas", values="harga_rata_ribu")
    tren = pd.DataFrame({"awal_m1": pivot.iloc[0], "akhir_m8": pivot.iloc[-1]})
    tren["selisih"] = tren["akhir_m8"] - tren["awal_m1"]
    tren["pct"] = tren["selisih"] / tren["awal_m1"] * 100
    return tren


def susun_laporan(
    masalah: dict,
    bersih: pd.DataFrame,
    catatan_isi: list[str],
    stat: pd.DataFrame,
    terbesar: pd.DataFrame,
    cabai: dict,
    tren: pd.DataFrame,
) -> str:
    """Susun isi laporan akhir sebagai teks polos."""
    baris = []
    baris += [
        "=" * 68,
        "LAPORAN AKHIR - ANALISIS HARGA KOMODITAS",
        "Warung Nasi Bu Warni, Surabaya",
        f"Periode: 8 pekan, M1 (mulai {PEKAN_M1}) s.d. M8 (mulai {PEKAN_M8})",
        "=" * 68,
        "",
        "1. RINGKASAN DATA",
        "-" * 68,
        "Sumber        : catatan belanja mingguan Bu Warni dan harga",
        "                rata-rata satu pasar tradisional di Surabaya",
        "Satuan        : ribu rupiah per kilogram",
        "Data mentah   : 41 baris",
        f"Pembersihan   : {masalah['duplikat']} baris duplikat dibuang (M3 cabai merah);",
    ]
    if catatan_isi:
        baris.append("                1 sel kosong diisi interpolasi linear")
        baris.append(f"                ({catatan_isi[0]});")
    baris += [
        "                1 nama komoditas diseragamkan",
        "                (Cabai Merah -> cabai merah)",
        f"Data bersih   : {len(bersih)} baris = 5 komoditas x 8 pekan",
        "",
        "2. STATISTIK HARGA PER KOMODITAS (ribu rupiah per kg)",
        "-" * 68,
        f"{'komoditas':<13} {'mean':>6} {'std':>6} {'min':>7} {'max':>7} {'cv':>7}",
    ]
    for komoditas, b in stat.sort_values("cv", ascending=False).iterrows():
        baris.append(
            f"{komoditas:<13} {b['mean']:6.2f} {b['std']:6.2f} {b['min']:7.2f}"
            f" {b['max']:7.2f} {b['cv']:7.2f}%"
        )
    baris += [
        "cv = (std / mean) x 100%: ukuran gejolak relatif yang dapat",
        "dibandingkan antar komoditas walau tingkat harganya berbeda.",
        "",
        "3. TEMUAN UTAMA",
        "-" * 68,
        "T1  Cabai merah melonjak pada M4-M5 lalu turun.",
        f"    M3 {cabai['m3']:.1f} -> M4 {cabai['m4']:.1f} -> M5 {cabai['m5']:.1f}"
        f" (naik {cabai['m3_ke_m5']:.1f}% dari M3 ke M5), lalu turun",
        f"    bertahap: M6 {cabai['m6']:.1f}, M7 {cabai['m7']:.1f}, M8 {cabai['m8']:.1f}.",
        f"    Puncak {cabai['puncak_pekan']} ({cabai['puncak']:.1f}) mencapai"
        f" {cabai['puncak'] / cabai['m1']:.1f}x harga awal M1 ({cabai['m1']:.1f}).",
        "    Lonjakan bertepatan dengan puncak musim hujan",
        "    Januari-Februari yang mengganggu pasokan.",
        "T2  Beras dan gula pasir paling stabil.",
        f"    Kisaran beras {stat.loc['beras', 'min']:.1f}-{stat.loc['beras', 'max']:.1f}"
        f" (cv {stat.loc['beras', 'cv']:.2f}%) dan gula pasir"
        f" {stat.loc['gula pasir', 'min']:.1f}-{stat.loc['gula pasir', 'max']:.1f}"
        f" (cv {stat.loc['gula pasir', 'cv']:.2f}%).",
        "T3  Ayam broiler menanjak tipis tetapi konsisten.",
        f"    {tren.loc['ayam broiler', 'awal_m1']:.1f} (M1) ->"
        f" {tren.loc['ayam broiler', 'akhir_m8']:.1f} (M8),"
        f" +{tren.loc['ayam broiler', 'pct']:.1f}% dalam 8 pekan,",
        "    hanya sekali turun tipis pada M3 (33.5 -> 33.2).",
        "T4  Bawang merah bergejolak sedang.",
        f"    Harga naik-turun dalam kisaran {stat.loc['bawang merah', 'min']:.1f}-"
        f"{stat.loc['bawang merah', 'max']:.1f} (cv {stat.loc['bawang merah', 'cv']:.2f}%);",
        "    dua perubahan terbesarnya +16.1% (M3 -> M4) dan",
        "    +13.3% (M1 -> M2).",
        "",
        "4. PERUBAHAN PEKAN-KE-PEKAN TERBESAR",
        "-" * 68,
    ]
    for nomor, (_, b) in enumerate(terbesar.iterrows(), start=1):
        baris.append(
            f"{nomor}) {b['komoditas']:<12} {b['minggu_sebelum']} -> {b['minggu']}"
            f"  {b['pct']:+6.1f}%  ({b['harga_sebelum']:.1f} -> {b['harga_rata_ribu']:.1f})"
        )
    baris += [
        "",
        "5. REKOMENDASI UNTUK BU WARNI",
        "-" * 68,
        "R1  Jadikan cabai merah komoditas yang diawasi mingguan.",
        "    Bila harganya naik lebih dari 20% dalam satu pekan",
        "    (seperti M3 -> M4), tunda pembelian besar sampai mereda.",
        "R2  Saat cabai murah (kisaran 38-44 seperti M1-M3 dan M7-M8),",
        "    beli lebih banyak untuk stok sambal; saat di atas 60",
        "    (M4-M5), geser menu andalan ke olahan tanpa cabai segar.",
        "R3  Beras dan gula pasir cukup dibeli mingguan sesuai kebutuhan;",
        "    menimbun tidak memberi keuntungan berarti karena stabil.",
        "R4  Hitung ulang harga jual paket nasi ayam dengan asumsi ayam",
        "    naik sekitar 3% per 4 pekan agar margin tidak tergerus.",
        "",
        "6. KETERBATASAN ANALISIS",
        "-" * 68,
        "- Delapan pekan belum cukup memisahkan tren dari pola musiman",
        "  tahunan; dibutuhkan data minimal 12 bulan.",
        "- Harga adalah rata-rata satu pasar; harga belanja aktual",
        "  harian bisa berbeda tipis.",
        "- Satu nilai harga (bawang merah M6) adalah hasil interpolasi,",
        "  bukan harga nyata yang tercatat.",
        "",
        "Diproses oleh : src/analisis_harga.py (pipeline deterministik)",
        "Data          : data/harga_komoditas.csv",
    ]
    return "\n".join(baris) + "\n"


def main() -> None:
    """Jalankan seluruh alur pipeline dan tulis laporan."""
    mentah = muat_data()
    masalah = periksa_masalah(mentah)
    bersih, catatan_isi = bersihkan(mentah)
    stat = statistik_harga(bersih)
    terbesar = perubahan_terbesar(bersih)
    cabai = ringkasan_cabai(bersih)
    tren = tren_akhir(bersih)

    laporan = susun_laporan(masalah, bersih, catatan_isi, stat, terbesar, cabai, tren)
    BERKAS_LAPORAN.parent.mkdir(parents=True, exist_ok=True)
    BERKAS_LAPORAN.write_text(laporan, encoding="utf-8")
    print(f"[7] Laporan ditulis ke  : {BERKAS_LAPORAN}")


if __name__ == "__main__":
    main()

Output yang Dihasilkan:

text
[1] Muat data mentah   : 41 baris, 3 kolom
[2] Temuan validasi    : 1 baris duplikat; 1 sel harga kosong; nama tak konsisten: Cabai Merah
[3] Pembersihan        : 40 baris bersih; sel kosong diisi interpolasi (bawang merah M6 = 32.5)
[4] Statistik harga (ribu rupiah per kg):
      ayam broiler mean  34.00  std  0.78  min 33.00  max 35.20  cv  2.29%
      bawang merah mean  32.94  std  2.01  min 30.00  max 36.00  cv  6.10%
      beras        mean  13.25  std  0.16  min 13.00  max 13.50  cv  1.21%
      cabai merah  mean  50.25  std 14.53  min 38.00  max 78.00  cv 28.91%
      gula pasir   mean  17.65  std  0.12  min 17.50  max 17.80  cv  0.68%
[5] Perubahan terbesar : cabai merah M3 -> M4 (+54.8%, 42.0 -> 65.0)
[6] Lonjakan cabai     : puncak M5 78.0 ribu (2.1x harga awal M1 38.0), kembali 40.0 pada M8
[7] Laporan ditulis ke  : laporan/laporan-akhir.txt

Ringkasan tersebut adalah peta jalan seluruh proyek: langkah [1]–[3] kita kerjakan tuntas pada Bagian 2–4, statistik pada langkah [4] dibedah pada Bagian 6 setelah eksplorasi perubahan harga pada Bagian 5, lonjakan cabai pada langkah [6] dibahas sebagai bagian dari tren dan musiman pada Bagian 7, dan laporan pada langkah [7] menjadi bahan Bagian 8–10.

Laporan Akhir #

Pipeline menutup kerjanya dengan menulis laporan/laporan-akhir.txt — laporan teks polos berisi ringkasan data, tabel statistik, temuan utama, perubahan harga terbesar, rekomendasi untuk Bu Warni, dan keterbatasan analisis. Seluruh angka pada laporan diambil dari perhitungan pipeline, bukan diketik manual.

text
====================================================================
LAPORAN AKHIR - ANALISIS HARGA KOMODITAS
Warung Nasi Bu Warni, Surabaya
Periode: 8 pekan, M1 (mulai 5 Januari 2026) s.d. M8 (mulai 23 Februari 2026)
====================================================================

1. RINGKASAN DATA
--------------------------------------------------------------------
Sumber        : catatan belanja mingguan Bu Warni dan harga
                rata-rata satu pasar tradisional di Surabaya
Satuan        : ribu rupiah per kilogram
Data mentah   : 41 baris
Pembersihan   : 1 baris duplikat dibuang (M3 cabai merah);
                1 sel kosong diisi interpolasi linear
                (bawang merah M6 = 32.5);
                1 nama komoditas diseragamkan
                (Cabai Merah -> cabai merah)
Data bersih   : 40 baris = 5 komoditas x 8 pekan

2. STATISTIK HARGA PER KOMODITAS (ribu rupiah per kg)
--------------------------------------------------------------------
komoditas       mean    std     min     max      cv
cabai merah    50.25  14.53   38.00   78.00   28.91%
bawang merah   32.94   2.01   30.00   36.00    6.10%
ayam broiler   34.00   0.78   33.00   35.20    2.29%
beras          13.25   0.16   13.00   13.50    1.21%
gula pasir     17.65   0.12   17.50   17.80    0.68%
cv = (std / mean) x 100%: ukuran gejolak relatif yang dapat
dibandingkan antar komoditas walau tingkat harganya berbeda.

3. TEMUAN UTAMA
--------------------------------------------------------------------
T1  Cabai merah melonjak pada M4-M5 lalu turun.
    M3 42.0 -> M4 65.0 -> M5 78.0 (naik 85.7% dari M3 ke M5), lalu turun
    bertahap: M6 55.0, M7 44.0, M8 40.0.
    Puncak M5 (78.0) mencapai 2.1x harga awal M1 (38.0).
    Lonjakan bertepatan dengan puncak musim hujan
    Januari-Februari yang mengganggu pasokan.
T2  Beras dan gula pasir paling stabil.
    Kisaran beras 13.0-13.5 (cv 1.21%) dan gula pasir 17.5-17.8 (cv 0.68%).
T3  Ayam broiler menanjak tipis tetapi konsisten.
    33.0 (M1) -> 35.2 (M8), +6.7% dalam 8 pekan,
    hanya sekali turun tipis pada M3 (33.5 -> 33.2).
T4  Bawang merah bergejolak sedang.
    Harga naik-turun dalam kisaran 30.0-36.0 (cv 6.10%);
    dua perubahan terbesarnya +16.1% (M3 -> M4) dan
    +13.3% (M1 -> M2).

4. PERUBAHAN PEKAN-KE-PEKAN TERBESAR
--------------------------------------------------------------------
1) cabai merah  M3 -> M4   +54.8%  (42.0 -> 65.0)
2) cabai merah  M5 -> M6   -29.5%  (78.0 -> 55.0)
3) cabai merah  M4 -> M5   +20.0%  (65.0 -> 78.0)
4) cabai merah  M6 -> M7   -20.0%  (55.0 -> 44.0)
5) bawang merah M3 -> M4   +16.1%  (31.0 -> 36.0)

5. REKOMENDASI UNTUK BU WARNI
--------------------------------------------------------------------
R1  Jadikan cabai merah komoditas yang diawasi mingguan.
    Bila harganya naik lebih dari 20% dalam satu pekan
    (seperti M3 -> M4), tunda pembelian besar sampai mereda.
R2  Saat cabai murah (kisaran 38-44 seperti M1-M3 dan M7-M8),
    beli lebih banyak untuk stok sambal; saat di atas 60
    (M4-M5), geser menu andalan ke olahan tanpa cabai segar.
R3  Beras dan gula pasir cukup dibeli mingguan sesuai kebutuhan;
    menimbun tidak memberi keuntungan berarti karena stabil.
R4  Hitung ulang harga jual paket nasi ayam dengan asumsi ayam
    naik sekitar 3% per 4 pekan agar margin tidak tergerus.

6. KETERBATASAN ANALISIS
--------------------------------------------------------------------
- Delapan pekan belum cukup memisahkan tren dari pola musiman
  tahunan; dibutuhkan data minimal 12 bulan.
- Harga adalah rata-rata satu pasar; harga belanja aktual
  harian bisa berbeda tipis.
- Satu nilai harga (bawang merah M6) adalah hasil interpolasi,
  bukan harga nyata yang tercatat.

Diproses oleh : src/analisis_harga.py (pipeline deterministik)
Data          : data/harga_komoditas.csv

Sepuluh Bagian Pengerjaan #

Proyek dikerjakan berurutan; setiap bagian membangun di atas hasil bagian sebelumnya:

  1. Bagian 1: Memahami Masalah — keputusan apa yang ingin dibantu, dan pertanyaan analisis apa yang mengarahkan seluruh proyek.
  2. Bagian 2: Mengumpulkan Data Harga — dari mana data berasal, bagaimana strukturnya, dan mengapa asal-usul data perlu dicatat.
  3. Bagian 3: Memvalidasi Data — memeriksa bentuk, tipe, duplikat, sel kosong, dan konsistensi nama sebelum percaya pada data.
  4. Bagian 4: Membersihkan Data — membuang duplikat, mengisi sel kosong dengan interpolasi, dan menyeragamkan nama komoditas.
  5. Bagian 5: Eksplorasi Perubahan Harga — memutar data menjadi tabel harga per pekan dan menemukan perubahan terbesar.
  6. Bagian 6: Analisis Statistik Harga — mean, median, simpangan baku, dan koefisien variasi untuk mengukur gejolak tiap komoditas.
  7. Bagian 7: Analisis Tren dan Musiman — membandingkan awal versus akhir periode dan membaca pengaruh musim hujan.
  8. Bagian 8: Membandingkan Komoditas — memberi peringkat gejolak dan membagi komoditas menjadi kelompok stabil dan bergejolak.
  9. Bagian 9: Visualisasi Hasil — menggambar grafik garis dan grafik batang yang menceritakan temuan.
  10. Bagian 10: Menyusun Laporan — membaca laporan akhir, menimbang rekomendasinya, dan merefleksikan keterbatasan analisis.

Mulailah dari Bagian 1 dan kerjakan sesuai urutan. Seluruh berkas proyek juga dapat diunduh dari bagian Berkas Sumber di bawah halaman ini, serta dari halaman setiap bagian.

# Bagian 1: Memahami Masalah

Rumuskan keputusan yang ingin dibantu dan pertanyaan analisis yang mengarahkan seluruh proyek harga komoditas.

Buka →
# Bagian 2: Mengumpulkan Data Harga

Telusuri asal data harga, cara pencatatannya, dan struktur berkas CSV yang menjadi bahan analisis.

Buka →
# Bagian 3: Memvalidasi Data

Periksa dimensi, tipe kolom, duplikat, sel kosong, dan konsistensi nama komoditas pada data mentah.

Buka →
# Bagian 4: Membersihkan Data

Perbaiki tiga masalah temuan validasi: buang duplikat, isi sel kosong dengan interpolasi, dan seragamkan nama komoditas.

Buka →
# Bagian 5: Eksplorasi Perubahan Harga

Pivot data menjadi tabel harga per pekan, temukan perubahan pekan-ke-pekan terbesar, dan baca lonjakan cabai merah.

Buka →
# Bagian 6: Analisis Statistik Harga

Hitung mean, median, simpangan baku, dan koefisien variasi untuk mengukur dan membandingkan gejolak harga tiap komoditas.

Buka →
# Bagian 7: Analisis Tren dan Musiman

Bandingkan harga awal dan akhir periode, baca tren ayam broiler, dan letakkan lonjakan musim hujan pada konteksnya.

Buka →
# Bagian 8: Membandingkan Komoditas

Ranking gejolak lima komoditas lewat koefisien variasi, bagi menjadi kelompok stabil dan bergejolak, lalu tarik implikasinya bagi belanja dan menu warung.

Buka →
# Bagian 9: Visualisasi Hasil

Gambar grafik garis pergerakan harga lima komoditas dan grafik batang peringkat koefisien variasi yang siap dipakai dalam laporan.

Buka →
# Bagian 10: Menyusun Laporan

Baca laporan akhir yang ditulis pipeline, timbang temuan dan rekomendasinya, refleksikan keterbatasan analisis, lalu tutup proyek.

Buka →