Sebelas bagian telah menghasilkan tumpukan temuan: deret yang bersih, model yang menang tipis, residu yang terpola, interval yang melebar. Bagian penutup ini merangkai semuanya menjadi satu dokumen yang sampai ke tangan Bu Warni — laporan/laporan-akhir.txt, teks polos yang ditulis otomatis oleh pipeline pada langkah terakhirnya. Kita akan membedah strukturnya, memeriksa satu klaim angkanya terhadap data, menimbang rekomendasi belanja yang diusulkannya, lalu menutup proyek dengan refleksi jujur tentang apa yang sudah dan belum kita capai.
Membaca Laporan dari Baris Pertama #
Pipeline tidak mengetik laporan; pipeline menyusunnya dari nilai yang sudah dihitung — koefisien dari fungsi pelatihan, MAE dari fungsi evaluasi, prakiraan dari fungsi interval. Tidak ada satu angka pun yang disalin tangan, sehingga tidak ada ruang salah tik. Ganti berkas data dengan catatan musim depan, jalankan ulang python3 src/prediksi_harga.py, dan laporan baru dengan bentuk yang sama akan tertulis. Isinya dirangkum sebagai berikut:
====================================================================
LAPORAN AKHIR - PREDIKSI HARGA CABAI MERAH (ringkas)
====================================================================
1. RINGKASAN DATA 38 baris mentah -> 36 bersih; tren +0.089
ribu/minggu; lonjakan W19-W21 (puncak W20 53.1)
2. METODE PREDIKSI fitur lag_1, lag_2, minggu_ke; pembagian
kronologis 30/6; baseline naive; koefisien model
3. HASIL EVALUASI MAE model 1.080 vs baseline 1.167 (unggul 7.4%);
RMSE 1.151 vs 1.288
4. ANALISIS KESALAHAN bias -0.99; hanya W33 diremehkan (+0.27);
galat latih terburuk W19 (+9.64)
5. PRAKIRAAN 4 MINGGU W37-W40: 41.5, 42.9, 44.3, 44.9 ribu, disertai
interval 95% yang melebar
6. REKOMENDASI BELANJA R1-R4: patokan W37, baca interval, waspadai
musim, jalankan ulang pipeline
7. KETERBATASAN 36 minggu; interval dari 6 residu; tanpa fitur
cuaca; satu nilai hasil interpolasi (W27)Struktur itu bisa dipetakan secara mekanis, bukan hanya dikenali penulisnya. Blok berikut membuka berkas laporan dari folder proyek lalu mencetak setiap judul bagiannya:
import re
from pathlib import Path
laporan = Path("../laporan/laporan-akhir.txt").read_text(encoding="utf-8")
baris_laporan = laporan.splitlines()
print(f"Berkas : laporan/laporan-akhir.txt")
print(f"Panjang : {len(baris_laporan)} baris")
print()
print("Tujuh bagian laporan:")
for baris in baris_laporan:
if re.match(r"^[0-9]+\. [A-Z]", baris):
print(" " + baris)Output yang Dihasilkan:
Berkas : laporan/laporan-akhir.txt
Panjang : 87 baris
Tujuh bagian laporan:
1. RINGKASAN DATA
2. METODE PREDIKSI
3. HASIL EVALUASI PADA 6 MINGGU UJI (W31-W36)
4. ANALISIS KESALAHAN
5. PRAKIRAAN 4 MINGGU KE DEPAN
6. REKOMENDASI BELANJA UNTUK BU WARNI
7. KETERBATASANPola ^[0-9]+\. [A-Z] menangkap baris yang diawali nomor dan huruf kapital — tujuh judul bagian ditemukan, sama persis dengan kerangka di atas. Laporan 87 baris ini sengaja pendek: cukup panjang untuk memuat seluruh temuan beserta angkanya, cukup ringkas untuk dibaca sambil menunggu nasi matang. Dua baris penutupnya mencantumkan Diproses oleh : src/prediksi_harga.py dan Data : data/harga_mingguan.csv — pernyataan keterulangan yang mengikat seluruh angka pada berkas yang bisa diperiksa siapa pun.
Tujuh Bagian dan Asal-Usulnya #
Setiap bagian laporan adalah hasil dari bagian-bagian proyek; peta berikut menunjukkan dari mana setiap angka berasal:
| Seksi laporan | Isi utama | Dibangun pada |
|---|---|---|
| 1. Ringkasan data | 38 baris mentah menjadi 36 bersih, tren +0,089, lonjakan W19–W21 | Bagian 2–5 |
| 2. Metode prediksi | Fitur lag, pembagian 30/6, baseline naive, koefisien +1,151 / −0,647 / +0,072 | Bagian 6–8 |
| 3. Hasil evaluasi | MAE 1,080 vs 1,167; RMSE 1,151 vs 1,288; unggul 7,4% | Bagian 7 dan 9 |
| 4. Analisis kesalahan | Bias −0,99; W33 diremehkan +0,27; W19 terburuk +9,64 | Bagian 10 |
| 5. Prakiraan 4 minggu | W37 41,5 [40,3, 42,8] hingga W40 44,9 [42,4, 47,4] | Bagian 11 |
| 6. Rekomendasi belanja | R1–R4 untuk keputusan warung | Bagian 1 dan 9–11 |
| 7. Keterbatasan | 36 minggu, 6 residu, tanpa fitur cuaca, W27 interpolasi | Seluruh proyek |
Urutan tujuh seksi ini mengikuti alur cerita yang bisa diikuti pembaca non-teknis: apa datanya, bagaimana metodenya, apa hasilnya, di mana galatnya, apa prakiraannya, apa yang sebaiknya dilakukan, dan di mana batas kepercayaannya. Seksi keterbatasan yang diletakkan terakhir bukan catatan kaki basa-basi — seksi itu membatasi tafsir seluruh angka di atasnya, kebiasaan yang dilatih pada chapter Keterbatasan Prediksi Deret Waktu .
Memverifikasi Klaim Kemenangan 7,4 Persen #
Angka seberisi apa pun pada laporan selayaknya dihitung ulang sebelum dipercai. Klaim yang paling sering akan dikutip dari laporan ini adalah “model lebih baik 7.4% pada MAE (menang tipis)” — klaim yang menentukan apakah model layak dipakai. Kita periksa dari data, dengan resep dan model yang sama:
import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression
# Resep pembersihan hasil Bagian 4: duplikat dibuang, '-' diinterpolasi.
df = pd.read_csv("../data/harga_mingguan.csv")
bersih = df.drop_duplicates(subset=["minggu"], keep="first").copy()
bersih["harga_ribu"] = pd.to_numeric(bersih["harga_ribu"], errors="coerce")
bersih = bersih.sort_values("tanggal_mulai").reset_index(drop=True)
bersih["harga_ribu"] = bersih["harga_ribu"].interpolate().round(1)
# Tabel fitur lag hasil Bagian 6, lalu pembagian kronologis 28/6.
fitur = pd.DataFrame(
{
"lag_1": bersih["harga_ribu"].shift(1),
"lag_2": bersih["harga_ribu"].shift(2),
"minggu_ke": bersih["harga_ribu"].index + 1,
"target": bersih["harga_ribu"],
"minggu": bersih["minggu"],
}
).dropna().reset_index(drop=True)
fitur["minggu_ke"] = fitur["minggu_ke"].astype(int)
latih = fitur.iloc[:-6].copy()
uji = fitur.iloc[-6:].copy()
# Model Bagian 8: LinearRegression pada fitur lag (deterministik).
FITUR_KOLOM = ["lag_1", "lag_2", "minggu_ke"]
model = LinearRegression()
model.fit(latih[FITUR_KOLOM], latih["target"])
mae_model = float(np.mean(np.abs(uji["target"].to_numpy() - model.predict(uji[FITUR_KOLOM]))))
mae_naive = float(np.mean(np.abs(uji["target"].to_numpy() - uji["lag_1"].to_numpy())))
perbaikan = (mae_naive - mae_model) / mae_naive * 100
print(f"Hitung ulang : ({mae_naive:.3f} - {mae_model:.3f}) / {mae_naive:.3f} x 100 = {perbaikan:.2f}%")
print("Klaim laporan: model lebih baik 7.4% pada MAE (menang tipis)")
print(f"Cocok : {round(perbaikan, 1) == 7.4}")Output yang Dihasilkan:
Hitung ulang : (1.167 - 1.080) / 1.167 x 100 = 7.40%
Klaim laporan: model lebih baik 7.4% pada MAE (menang tipis)
Cocok : TruePerhitungan ulang dari data menghasilkan 7,40%, dan laporan menuliskannya sebagai 7,4% — pembulatan yang tepat, klaim didukung. Inilah cara membaca laporan yang sehat: percaya, lalu verifikasi angka yang paling menentukan keputusan. Perhatikan pula frasa “menang tipis” yang menyertai klaim tersebut; pipeline sengaja menuliskannya karena seperti dibedah pada Bagian 9, seluruh keunggulan model lahir dari satu minggu berbalik cepat.
Dari Rekomendasi ke Keputusan Belanja #
Seksi 6 laporan menerjemahkan temuan menjadi empat rekomendasi. Tabel berikut memetakan masing-masing ke keputusan warung yang sudah didefinisikan pada Bagian 1:
| Rekomendasi | Inti pesan | Keputusan yang didukung | Dasar dalam data |
|---|---|---|---|
| R1 | Anggarkan cabai pekan depan pada kisaran 40,3–42,8 ribu per kg | Beli berapa kilo | Prakiraan W37 41,5 dengan interval satu minggu (Bagian 11) |
| R2 | Horizon 2–4 minggu: baca intervalnya, bukan angka titiknya — batas bawah skenario hemat, batas atas skenario waspada | Menunda atau mengejar; menggeser menu | Interval melebar dari ±1,78 hingga ±2,51 ribu (Bagian 11) |
| R3 | Waspadai peralihan musim; bila ada kabar gangguan pasokan, beli lebih awal dari prakiraan | Menunda atau mengejar | Galat W19 +9,64 saat lonjakan yang tak terlihat fitur lag (Bagian 10) |
| R4 | Catat harga mingguan baru dan jalankan ulang pipeline | Semua keputusan | Pipeline deterministik dari data yang sama (Bagian 2 dan 8) |
Empat rekomendasi ini sengaja berpijak pada interval, bukan pada angka titik — konsisten dengan bahasa jujur yang dilatih pada Bagian 11. Tidak satu pun menuntut Bu Warni berkomitmen pada satu angka masa depan; semuanya memberi kisaran beserta rencana untuk skenario batas bawah dan batas atasnya.
Refleksi Dua Belas Bagian #
Dua belas bagian membentuk satu lingkaran penuh. Pertanyaan Bu Warni — “berapa perkiraan harga cabai minggu depan” — dirumuskan menjadi spesifikasi pada Bagian 1; data historis dikumpulkan dan dicatat asal-usulnya pada Bagian 2; validasi dan pembersihan menyiapkan 36 baris bersih pada Bagian 3–4; eksplorasi membaca tren, irama, dan lonjakan pada Bagian 5; fitur lag dan pembagian kronologis dibangun pada Bagian 6; baseline naive menetapkan garis start pada Bagian 7; model dilatih dan dibaca koefisiennya pada Bagian 8; evaluasi, analisis kesalahan, dan interval menuntaskan pertanyaan itu pada Bagian 9–11; laporan menutup lingkaran menjadi keputusan belanja.
Dari perjalanan itu, empat pelajaran paling melekat. Pertama, baseline dulu, model kemudian: model hanya unggul 7,4% dari prakiraan paling malas sekalipun, dan kerumitan apa pun wajib membayar dirinya melewati garis start itu. Kedua, kejujuran evaluasi ditentukan sebelum model dijalankan — pembagian acak pada Bagian 6 terbukti membocorkan masa depan, dan skor indah dari pembagian yang salah tidak bernilai apa-apa. Ketiga, galat berkumpul di titik balik: lonjakan W19 (+9,64) terjadi justru setelah dua minggu yang datar, pengingat bahwa model hanya mengenal pola yang pernah ada di datanya. Keempat, masa depan layak diucap dengan kisaran: prakiraan tanpa interval menjual kepastian yang tidak kita miliki.
Keterbatasan tetap kita pegang terbuka, sebagaimana ditulis seksi 7 laporan: 36 minggu belum memisahkan musiman tahunan dari tren; interval dihitung dari enam residu jendela uji yang tenang; model tidak memiliki fitur cuaca dan fase musiman; dan satu nilai (W27 41,4) adalah hasil interpolasi. Langkah lanjut yang wajar: mencatat data hingga lewat 12 bulan, menambahkan fitur fase musiman dan cuaca, serta menjadikan R4 sebagai rutinitas — pipeline tinggal dijalankan ulang setiap pekan dengan data terbaru. Bila kelak kode dan narasi perlu hidup dalam satu berkas yang bisa dijalankan selangkah demi selangkah, bentuk notebook adalah kelanjutan yang umum; dokumentasi Jupyter memandu mulainya.
Ringkasan Bagian 12 #
- Laporan akhir ditulis pipeline dari nilai yang sudah dihitung: 87 baris, tujuh seksi, tanpa satu angka pun yang diketik manual — dan strukturnya terverifikasi secara mekanis.
- Klaim kunci “model lebih baik 7,4% pada MAE” lolos pemeriksaan ulang dari data: (1,167 − 1,080) / 1,167 × 100 = 7,40%.
- Empat rekomendasi R1–R4 menerjemahkan interval dan analisis kesalahan menjadi keputusan belanja: patokan W37, baca kisaran bukan titik, waspadai peralihan musim, jalankan ulang pipeline.
- Keterbatasan dilaporkan terbuka sebagai batas tafsir: 36 minggu, enam residu, tanpa fitur cuaca, satu nilai interpolasi.
Pertanyaan pembuka proyek kini terjawab dengan cara yang bisa dipertanggungjawabkan: harga cabai W37 diperkirakan 41,5 ribu per kilogram, kemungkinan besar di kisaran 40,3–42,8, dan setiap angka tersebut dapat dihitung ulang siapa pun dari dua berkas proyek. Bu Warni tidak mendapat bola kristal — ia mendapatkan hal yang lebih berguna: perkiraan berinterval beserta kebiasaan membacanya secara jujur.
Ini proyek keempat kita: dari analisis deskriptif ke prediktif, dari menjelaskan masa lalu ke memperkirakan masa depan dengan disiplin. Proyek kelima mengembalikan kebebasan penuh ke tangan Anda: menganalisis dataset terbuka pilihan sendiri dari awal hingga laporan, dengan seluruh bekal empat proyek sebelumnya. Kita mulai pada proyek Analisis Dataset Terbuka .