Seluruh delapan bagian sebelumnya bermuara pada satu dokumen: laporan/laporan-akhir.txt. Laporan ini ditujukan kepada Bu Rina — bukan kepada sesama analis — sehingga bentuknya teks polos tanpa kode yang bisa dibuka di ponsel, dicetak, atau ditempel di dinding belakang kasir. Yang membuatnya istimewa: seluruh angkanya ditulis ulang oleh skrip src/segmentasi.py setiap kali pipeline dijalankan, bukan diketik manual, sehingga laporan tidak mungkin telat satu langkah dari data. Pada bagian ini kita membedah strukturnya, menguji ulang klaim angkanya terhadap data mentah, lalu menutup proyek dengan refleksi.
Struktur Enam Seksi Laporan #
Laporan tersusun atas enam seksi berurutan, masing-masing dengan tugas yang jelas:
| Seksi | Isi | Bahan dari |
|---|---|---|
| 1. Ringkasan Data | Asal data, pembersihan, fitur yang dipakai | Bagian 2 dan 3 |
| 2. Metode | Algoritma, penyekalaan, alasan k=3 | Bagian 5, 6, dan 7 |
| 3. Profil Segmen | Kartu profil tiap segmen beserta anggota dan menu | Bagian 8 |
| 4. Temuan Utama | Empat temuan T1-T4 dengan angkanya | Bagian 4 dan 8 |
| 5. Rekomendasi Program | Tiga rekomendasi R1-R3 dengan dasar angka | Bagian 8 |
| 6. Keterbatasan | Jujur mencatat batas-batas analisis | Bagian 3 dan 8 |
Urutan ini mengikuti kaidah yang sama dengan laporan proyek sebelumnya: pembaca sibuk cukup membaca tiga seksi pertama untuk memahami hasilnya, dan semakin jauh dibaca semakin dalam detailnya. Karena laporan ditulis oleh skrip, strukturnya bisa diperiksa langsung dari berkasnya:
with open("../laporan/laporan-akhir.txt", encoding="utf-8") as berkas:
baris_laporan = berkas.read().splitlines()
print(f"Jumlah baris laporan : {len(baris_laporan)}")
print("\nStruktur laporan:")
for baris in baris_laporan:
if baris[:1].isdigit() and ". " in baris[:4]:
print(" ", baris)Output yang Dihasilkan:
Jumlah baris laporan : 100
Struktur laporan:
1. RINGKASAN DATA
2. METODE
3. PROFIL SEGMEN
4. TEMUAN UTAMA
5. REKOMENDASI PROGRAM
6. KETERBATASANMari kita bedah kode kecil di atas:
read().splitlines(): seluruh isi laporan dibaca sekali lalu dipecah menjadi daftar baris — struktur bisa diperiksa tanpa mencetak 100 baris penuh.- Syarat
baris[:1].isdigit() and ". " in baris[:4]: hanya baris yang diawali angka lalu titik (seperti4. TEMUAN UTAMA) yang dicetak. Enam baris hasilnya persis daftar isi laporan. - 100 baris: cukup ringkas untuk dua lembar cetak — panjang yang tepat untuk dokumen yang benar-benar dibaca orang sibuk.
Kartu Segmen sebagai Format Baku #
Seksi profil adalah jantung laporan, dan tiap segmen ditulis dalam format kartu yang seragam. Berikut kartu Pembeli Stok apa adanya:
Segmen 2: Pembeli Stok - 8 pelanggan (26.7%, cluster 1)
Kunjungan 30 hari : rata-rata 4.5 (3-6 kali)
Belanja/kunjungan : rata-rata Rp 115.000 (Rp 80.000 s.d. Rp 150.000)
Total 30 hari : rata-rata Rp 502.500
Menu favorit : americano (3), kopi susu (2), teh tawar (2), matcha latte (1)
Contoh anggota : Bambang Sutrisno, Ratna Dewi, Tono HartonoPerhatikan tiga sifat kartu tersebut. Pertama, setiap baris memuat angka dengan rentangnya — rata-rata 4,5 kunjungan disertai rentang 3-6 — sehingga pembaca tahu sebaran di balik rata-rata, bukan hanya titik pusatnya. Kedua, satuan ditulis penuh (Rp 115.000, bukan bpk_rata) dan mengikuti format Indonesia, karena pembacanya Bu Rina, bukan mesin. Ketiga, kartu ditutup dengan menu favorit dan nama anggota — elemen yang membuat segmen terasa hidup ketika dibahas dalam rapat.
Mengunduh dan Menjalankan Ulang Proyek #
Seluruh berkas proyek — data mentah data/pelanggan.csv, pipeline src/segmentasi.py, dan laporan laporan/laporan-akhir.txt — dapat diunduh dari bagian Berkas Sumber di bawah halaman ini maupun dari halaman overview proyek
. Susun ketiganya dengan struktur folder yang sama, lalu jalankan python3 src/segmentasi.py dari folder proyek: pipeline akan mencetak sembilan langkahnya dan menulis ulang laporan yang identik — bukan salinan lama, melainkan hasil perhitungan ulang dari data yang sama. Inilah makna klaim deterministik yang kita jaga sejak Bagian 3: tanpa angka karangan, tanpa jam sistem, tanpa akses jaringan.
Menguji Ulang Angka Laporan #
Klaim “setiap angka bisa direproduksi” tidak boleh berhenti sebagai kalimat manis — ia harus bisa diuji. Kita hitung ulang tiga angka kunci dari data mentah dengan jalur yang sama seperti pipeline, lalu periksa apakah sebutannya memang tersurat di berkas laporan:
import pandas as pd
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
from sklearn.preprocessing import StandardScaler
def muat_bersih(path):
"""Muat data mentah pelanggan dan terapkan seluruh langkah pembersihan."""
df = pd.read_csv(path)
df = df.drop_duplicates().reset_index(drop=True)
df["kunjungan_30hari"] = pd.to_numeric(df["kunjungan_30hari"], errors="coerce")
df = df.dropna(subset=["kunjungan_30hari"]).reset_index(drop=True)
df["kota"] = df["kota"].str.strip().str.title()
df["kunjungan_30hari"] = df["kunjungan_30hari"].astype(int)
return df
bersih = muat_bersih("../data/pelanggan.csv")
bersih["belanja_per_kunjungan"] = (
bersih["belanja_ribu"] / bersih["kunjungan_30hari"]
)
fitur = bersih[["kunjungan_30hari", "belanja_per_kunjungan"]]
skala = StandardScaler().fit_transform(fitur)
model = KMeans(n_clusters=3, random_state=42, n_init="auto").fit(skala)
bersih["cluster"] = model.labels_
with open("../laporan/laporan-akhir.txt", encoding="utf-8") as berkas:
isi_laporan = berkas.read()
total_rata = bersih.groupby("cluster")["belanja_ribu"].mean()
sebutan_total = "Rp " + f"{total_rata.loc[1] * 1000:,.0f}".replace(",", ".")
print(f"Hitungan ulang total rata-rata cluster 1 : {sebutan_total}")
print(f"Tersurat di laporan : {sebutan_total in isi_laporan}")
porsi = bersih["cluster"].value_counts(normalize=True).loc[2]
sebutan_porsi = f"{100 * porsi:.1f}%"
print(f"Hitungan ulang porsi cluster 2 : {sebutan_porsi}")
print(f"Tersurat di laporan : {sebutan_porsi in isi_laporan}")
skor = silhouette_score(skala, model.labels_)
sebutan_skor = f"{skor:.3f}"
print(f"Hitungan ulang silhouette k=3 : {sebutan_skor}")
print(f"Tersurat di laporan : {sebutan_skor in isi_laporan}")Output yang Dihasilkan:
Hitungan ulang total rata-rata cluster 1 : Rp 502.500
Tersurat di laporan : True
Hitungan ulang porsi cluster 2 : 40.0%
Tersurat di laporan : True
Hitungan ulang silhouette k=3 : 0.687
Tersurat di laporan : TrueCara kerja ujiannya sederhana namun kuat:
- Tiga angka dari tiga dunia berbeda: total belanja segmen (bisnis), porsi segmen terbesar (struktur), dan skor silhouette (metode). Ketiganya mewakili bahwa laporan konsisten di seluruh lapisannya.
sebutan in isi_laporan: operatorinmemeriksa apakah string — dibentuk dari hitungan ulang dengan format yang sama seperti laporan — benar-benar muncul di dalam teks. Tiga hasilTrueberarti laporan dan data sejajar; satu sajaFalseberarti keduanya sudah tidak sejajar dan laporan wajib disusun ulang.- Bukan salinan: angka-angka ini dihitung dari
data/pelanggan.csvpada langkah ini juga, bukan dibaca dari laporan itu sendiri. Uji seperti inilah yang mengubah janji keterulangan menjadi fakta yang terverifikasi.
Refleksi Proyek #
Proyek ketiga selesai, dan nilainya justru bertambah bila kita jujur menilai apa yang bisa lebih baik. Lima hal berikut akan kami lakukan berbeda pada putaran berikutnya:
- Memakai jendela data lebih panjang. 30 hari cukup untuk memotret perilaku, tetapi pola musiman — misalnya pelanggan yang hanya muncul saat musim hujan — belum terlihat. Tiga bulan data akan membuat segmen jauh lebih kokoh.
- Memperbaiki data di hulu. Duplikat Budi Santoso dan tanda
"-"milik Rani Oktaviani seharusnya dicegah di aplikasi kasir sejak awal. Data yang bersih dari sumbernya membuat proyek bergerak lebih cepat — meski kemampuan membersihkan tetap wajib dikuasai. - Mencatat hari dan jam kunjungan. Rekomendasi R3 (penawaran akhir pekan) berdiri di atas dugaan bahwa Pengunjung Sesekali bisa didorong datang Sabtu-Minggu — tetapi data kita tidak mencatat hari kunjungan, jadi efektivitasnya memang harus diuji coba di toko. Satu kolom tanggal transaksi akan mengubah dugaan itu menjadi analisis.
- Mencatat produk non-minuman. Dugaan “Pembeli Stok membeli biji kopi” lahir dari besaran belanja, bukan dari catatan produk. Satu kolom rincian belanja akan memastikannya — dan mungkin menemukan segmen baru yang lebih tajam.
- Mempertahankan kebiasaan yang terbukti baik. Resep
muat_bersihyang disalin konsisten di seluruh bagian,random_state=42yang membekukan unsur acak, dan penulisan laporan oleh skrip — tiga kebiasaan ini yang membuat setiap angka proyek bisa diuji seperti di atas, dan akan kami bawa ke proyek berikutnya.
Dari tiga ide program yang masih samar sampai laporan 100 baris yang setiap angkanya lolos uji ulang, kita menuntaskan satu putaran penuh proyek unsupervised learning: memahami masalah, menyiapkan dan membersihkan data, mengeksplorasi, membuat fitur, menerapkan clustering, mengevaluasi, menginterpretasikan, lalu melaporkan. Perjalanan berikutnya berpindah wilayah: dari mengelompokkan yang sudah terjadi ke memprediksi yang akan terjadi — Proyek: Prediksi Harga Komoditas menunggu kita dengan disiplin yang sama dan teknik yang baru.