Bagian 5 sampai 7 membedah komoditas satu per satu: pergerakannya, statistiknya, arah trennya. Namun keputusan Bu Warni tidak pernah menyangkut satu bahan saja — setiap rupiah untuk cabai berkompetisi dengan rupiah untuk beras dan ayam, jadi kelima komoditas perlu berdiri dalam satu arena perbandingan. Bagian ini menjawab pertanyaan Q4 dari Bagian 1: apa implikasi pola harga tiap komoditas bagi belanja mingguan dan menu warung. Kita mulai dari papan peringkat gejolak, lanjut ke pembagian kelompok stabil dan bergejolak, lalu menutup dengan tabel perbandingan lengkap yang menjadi dasar rekomendasi laporan akhir.
Papan Peringkat Gejolak #
Peringkat membutuhkan satu penggaris yang sama untuk semua peserta. Simpangan baku tidak memenuhi syarat itu — cabai merah berdagang di kisaran 50 ribu sehingga std 14.53 terasa wajar, sementara beras di 13 ribu membuat std 0.16 tampak sepele; keduanya tidak bisa diadu langsung. Koefisien variasi dari Bagian 6 menyelesaikan persoalan ini karena cv membandingkan sebaran terhadap rata-rata masing-masing komoditas. Materi lengkapnya ada pada chapter Ukuran Penyebaran ; di sini kita langsung memakainya untuk mengurutkan lima komoditas:
import pandas as pd
# Resep pembersihan Bagian 4: 41 baris mentah menjadi 40 baris bersih.
df = pd.read_csv("../data/harga_komoditas.csv")
df = df.drop_duplicates(subset=["minggu", "komoditas"], keep="first").copy()
df["komoditas"] = df["komoditas"].str.strip().str.lower()
df["harga_rata_ribu"] = pd.to_numeric(df["harga_rata_ribu"], errors="coerce")
df = df.sort_values(["komoditas", "minggu"])
df["harga_rata_ribu"] = df.groupby("komoditas")["harga_rata_ribu"].transform(
lambda s: s.interpolate()
)
stat = df.groupby("komoditas")["harga_rata_ribu"].agg(["mean", "std"])
stat["cv"] = stat["std"] / stat["mean"] * 100
print("Papan peringkat gejolak harga 8 pekan:")
for nomor, (komoditas, baris) in enumerate(
stat.sort_values("cv", ascending=False).iterrows(), start=1
):
print(
f"{nomor}. {komoditas:<12} cv {baris['cv']:5.2f}%"
f" mean {baris['mean']:5.2f} std {baris['std']:5.2f}"
)Output yang Dihasilkan:
Papan peringkat gejolak harga 8 pekan:
1. cabai merah cv 28.91% mean 50.25 std 14.53
2. bawang merah cv 6.10% mean 32.94 std 2.01
3. ayam broiler cv 2.29% mean 34.00 std 0.78
4. beras cv 1.21% mean 13.25 std 0.16
5. gula pasir cv 0.68% mean 17.65 std 0.12Tiga hal perlu dibaca dari papan peringkat tersebut:
- Jurang antara peringkat pertama dan kedua sangat lebar: cv cabai merah 28.91% hampir lima kali cv bawang merah 6.10%. Cabai merah berdiri sendirian di kelas atas; tidak ada komoditas lain yang mendekat.
- Empat komoditas sisanya berhimpit di bawah 7% — dari bawang merah 6.10% sampai gula pasir 0.68%. Untuk keempatnya, harga bergerak dalam koridor yang relatif sempit.
- Peringkat menegaskan temuan Bagian 5: empat dari lima perubahan pekan-ke-pekan terbesar memang milik cabai merah. Ukuran gejolak dan daftar lonjakan saling menguatkan.
Blok di atas memakai groupby() berpasangan agg() untuk menghitung mean dan std sekaligus per komoditas; rincian pemakaiannya ada di dokumentasi pandas untuk groupby
.
Membagi Kelompok Stabil dan Bergejolak #
Peringkat menjawab pertanyaan “yang paling”, tetapi keputusan warung bekerja dengan kelompok: bahan mana yang cukup direncanakan sekali seminggu, dan bahan mana yang harus diawasi. Kita pakai ambang sederhana — cv 5% ke atas masuk kelompok bergejolak, di bawahnya stabil. Pada data ini ambang mana pun di antara cv ayam broiler (2.29%) dan cv bawang merah (6.10%) menghasilkan pembagian yang sama, karena tidak ada komoditas yang berada di antara keduanya:
import pandas as pd
# Resep pembersihan Bagian 4: 41 baris mentah menjadi 40 baris bersih.
df = pd.read_csv("../data/harga_komoditas.csv")
df = df.drop_duplicates(subset=["minggu", "komoditas"], keep="first").copy()
df["komoditas"] = df["komoditas"].str.strip().str.lower()
df["harga_rata_ribu"] = pd.to_numeric(df["harga_rata_ribu"], errors="coerce")
df = df.sort_values(["komoditas", "minggu"])
df["harga_rata_ribu"] = df.groupby("komoditas")["harga_rata_ribu"].transform(
lambda s: s.interpolate()
)
stat = df.groupby("komoditas")["harga_rata_ribu"].agg(["mean", "std"])
stat["cv"] = stat["std"] / stat["mean"] * 100
kelompok = {"stabil": [], "bergejolak": []}
for komoditas, baris in stat.iterrows():
if baris["cv"] >= 5:
kelompok["bergejolak"].append(komoditas)
else:
kelompok["stabil"].append(komoditas)
for nama, anggota in kelompok.items():
rincian = ", ".join(f"{k} (cv {stat.loc[k, 'cv']:.2f}%)" for k in anggota)
print(f"Kelompok {nama:10}: {rincian}")Output yang Dihasilkan:
Kelompok stabil : ayam broiler (cv 2.29%), beras (cv 1.21%), gula pasir (cv 0.68%)
Kelompok bergejolak: bawang merah (cv 6.10%), cabai merah (cv 28.91%)Kelompok stabil beranggotakan ayam broiler, beras, dan gula pasir — ketiganya berayun di bawah 2.5% dari rata-ratanya sendiri. Kelompok bergejolak beranggotakan bawang merah dan cabai merah, tetapi keduanya tidak sederajat: bawang merah tergolong bergejolak sedang (6.10%, persis sebutan temuan T4 pada laporan akhir), sedangkan cabai merah bergejolak berat (28.91%). Pembagian ini nanti terbaca langsung pada grafik batang Bagian 9 dan menjadi kerangka tabel rekomendasi Bagian 10.
Melengkapi Peringkat dengan Arah Tren #
Gejolak hanyalah separuh cerita. cv mengukur besarnya ayunan tetapi buta terhadap arah, dan perbandingan yang lengkap menyandingkan keduanya: tren ujung-ke-ujung M1 menuju M8 dari Bagian 7, ditambah hitungan berapa pekan harga benar-benar naik. Kolom pekan_naik pada blok berikut dihitung dengan pivot.diff(): selisih tiap pekan terhadap pekan sebelumnya per komoditas, lalu dihitung jumlah selisih yang positif dari tujuh perubahan yang ada:
import pandas as pd
# Resep pembersihan Bagian 4: 41 baris mentah menjadi 40 baris bersih.
df = pd.read_csv("../data/harga_komoditas.csv")
df = df.drop_duplicates(subset=["minggu", "komoditas"], keep="first").copy()
df["komoditas"] = df["komoditas"].str.strip().str.lower()
df["harga_rata_ribu"] = pd.to_numeric(df["harga_rata_ribu"], errors="coerce")
df = df.sort_values(["komoditas", "minggu"])
df["harga_rata_ribu"] = df.groupby("komoditas")["harga_rata_ribu"].transform(
lambda s: s.interpolate()
)
pivot = df.pivot(index="minggu", columns="komoditas", values="harga_rata_ribu")
stat = df.groupby("komoditas")["harga_rata_ribu"].agg(["mean", "std"])
stat["cv"] = stat["std"] / stat["mean"] * 100
tren = pd.DataFrame({"awal_m1": pivot.iloc[0], "akhir_m8": pivot.iloc[-1]})
tren["pct"] = (tren["akhir_m8"] - tren["awal_m1"]) / tren["awal_m1"] * 100
pekan_naik = pivot.diff().dropna().gt(0).sum()
banding = stat.join(tren)[["mean", "cv", "awal_m1", "akhir_m8", "pct"]]
banding["pekan_naik"] = pekan_naik
print(banding.sort_values("cv", ascending=False).round(2).to_string())Output yang Dihasilkan:
mean cv awal_m1 akhir_m8 pct pekan_naik
komoditas
cabai merah 50.25 28.91 38.0 40.0 5.26 4
bawang merah 32.94 6.10 30.0 35.0 16.67 3
ayam broiler 34.00 2.29 33.0 35.2 6.67 6
beras 13.25 1.21 13.0 13.5 3.85 4
gula pasir 17.65 0.68 17.5 17.8 1.71 4Tabel ini memperlihatkan bahwa dua peringkat — gejolak dan tren — tidak searah:
- Bawang merah juara tren ujung-ke-ujung (+16.67%) padahal gejolaknya hanya sedang. Dua titik ujung M1 dan M8 memang menipu, sebagaimana sudah kita bahas pada Bagian 7; enam pekan di antaranya naik-turun tanpa arah.
- Cabai merah justru tampak jinak (+5.26%) karena harga M8 sudah pulih ke 40.0. Ujung yang rata menyembunyikan puncak 78.0 di tengah periode.
- Hanya ayam broiler yang memadukan gejolak rendah dengan arah konsisten: cv 2.29% sekaligus 6 dari 7 pekan naik. Inilah jawaban Q3 — komoditas yang menanjak perlahan tetapi konsisten.
Implikasi untuk Warung Bu Warni #
Tabel perbandingan berikut merangkum seluruh ukuran sekaligus menerjemahkannya menjadi perlakuan belanja dan menu:
| Komoditas | cv | Tren M1-M8 | Ciri pergerakan | Perlakuan untuk warung |
|---|---|---|---|---|
| cabai merah | 28.91% | +5.26%, puncak 78.0 pada M5 | Naik tajam dua pekan, pulih bertahap | Awasi tiap pekan; siapkan menu cadangan tanpa cabai segar |
| bawang merah | 6.10% | +16.67% | Bergelombang tanpa arah | Beli rutin sesuai kebutuhan pekan |
| ayam broiler | 2.29% | +6.67%, 6 dari 7 pekan naik | Menanjak landai tanpa jeda | Tinjau harga jual paket ayam secara berkala |
| beras | 1.21% | +3.85% | Nyaris datar | Aman dirinci dalam anggaran mingguan |
| gula pasir | 0.68% | +1.71% | Paling tenang | Aman dirinci dalam anggaran mingguan |
Menu berbasis cabai adalah sumber risiko terbesar warung. Saat harga menembus 78.0 pada M5, biaya cabai untuk sambal membengkak hampir dua kali lipat dalam dua pekan (42.0 pada M3 menjadi 78.0), sementara harga jual paket nasi tidak mungkin diubah secepat itu. Karena itu laporan akhir menyiapkan dua pintu: saat cabai murah (kisaran 38-44) menambah stok sambal, dan saat cabai mahal (di atas 60) menggeser menu andalan ke olahan tanpa cabai segar.
Beras dan gula pasir adalah kebalikannya: gejolak di bawah 1.5% membuat keduanya aman diandalkan untuk perencanaan, sehingga cukup dirinci dalam anggaran mingguan tanpa perlu menimbun — menimbun justru mengikat uang warung tanpa keuntungan berarti. Ayam broiler menghadirkan jenis risiko ketiga: ayunan mingguannya kecil, tetapi arahnya menaik terus — pergeseran 33.0 menuju 35.2 selama delapan pekan tidak pernah berbalik, sehingga margin paket nasi ayam tergerus perlahan bila harga jual tidak pernah ditinjau.
Ringkasan Bagian 8 #
- Koefisien variasi memberi peringkat gejolak yang adil lintas tingkat harga: cabai merah 28.91% jauh di atas bawang merah 6.10%, ayam broiler 2.29%, beras 1.21%, dan gula pasir 0.68%.
- Ambang cv 5% membagi lima komoditas menjadi kelompok stabil (ayam broiler, beras, gula pasir) dan bergejolak (bawang merah sedang, cabai merah berat).
- Peringkat gejolak dan peringkat tren tidak searah: bawang merah paling cepat naik ujung-ke-ujung (+16.67%), cabai merah tampak jinak (+5.26%) karena puncaknya disembunyikan dua titik ujung, dan hanya ayam broiler yang stabil sekaligus konsisten menanjak.
- Implikasinya bagi warung: menu berbasis cabai paling berisiko terhadap margin, beras dan gula pasir aman diandalkan dalam anggaran mingguan, dan harga jual paket ayam perlu ditinjau berkala.
Angka-angka kini berbaris rapi, tetapi Bu Warni — seperti kebanyakan pembaca laporan — akan lebih cepat menangkap pola dari gambar daripada dari tabel angka. Pada Bagian 9: Visualisasi Hasil kita menggambar grafik garis pergerakan harga dan grafik batang peringkat gejolak yang akan menjadi wajah laporan akhir.