Tabel per produk, kategori, dan kota pada Bagian 3 menjawab pertanyaan kinerja, tetapi manajemen Toko Sembako Berkah biasanya lebih dulu bertanya tentang waktu: bagaimana perkembangan penjualan bulan demi bulan. Pada bagian terakhir proyek ini kita merangkum 234 transaksi menjadi tiga angka bulanan dengan resample(), menyusun matriks kategori per bulan dengan pivot_table(), mengekspor kedua ringkasan ke berkas CSV, lalu mengubah seluruh angka proyek menjadi narasi singkat yang siap dibacakan. Setelah itu proyek Analisis Penjualan tuntas dan kita siap melangkah ke proyek berikutnya.
Ringkasan Bulanan dengan resample #
Agregasi per bulan membutuhkan kolom tanggal bertipe datetime — hasil kerja Bagian 2 yang kini terbayar. Kolom tanggal dijadikan index dengan set_index(), lalu resample("ME") membagi data per akhir bulan sebelum fungsi agg() menghitung omzet dan jumlah transaksi tiap kelompok. Pola ini persis materi Resampling Data pada section Data Waktu dan Deret Waktu.
"""Membuat ringkasan bulanan, pivot_table, dan berkas ekspor penjualan."""
from pathlib import Path
import tempfile
import pandas as pd
from buat_dataset import bersihkan, buat_dataset
if __name__ == "__main__":
with tempfile.TemporaryDirectory() as folder_hasil:
folder = Path(folder_hasil)
berkas = folder / "penjualan.csv"
buat_dataset().to_csv(berkas, index=False)
df = bersihkan(pd.read_csv(berkas))
df["omzet"] = df["jumlah"] * df["harga"]
df["bulan"] = df["tanggal"].dt.strftime("%Y-%m")
bulanan = (
df.set_index("tanggal")
.resample("ME")
.agg(omzet=("omzet", "sum"), transaksi=("id_transaksi", "count"))
)
bulanan.index = bulanan.index.strftime("%Y-%m")
print("== Ringkasan bulanan (resample) ==")
print(bulanan.to_string())
pivot = pd.pivot_table(
df, index="kategori", columns="bulan", values="omzet",
aggfunc="sum", margins=True, margins_name="Total",
)
print("\n== Omzet kategori per bulan (pivot_table + margins) ==")
print(pivot.to_string())
berkas_bulanan = folder / "ringkasan_bulanan.csv"
berkas_kategori = folder / "ringkasan_kategori.csv"
bulanan.to_csv(berkas_bulanan, index_label="bulan")
pivot.to_csv(berkas_kategori)
baca_bulanan = pd.read_csv(berkas_bulanan)
baca_kategori = pd.read_csv(berkas_kategori, index_col=0)
print("\n== Ekspor ringkasan ke CSV ==")
print(f"ringkasan_bulanan.csv : {len(baca_bulanan)} baris, kolom {list(baca_bulanan.columns)}")
print(
f"ringkasan_kategori.csv : {baca_kategori.shape[0]} baris x "
f"{baca_kategori.shape[1]} kolom"
)
kategori_terbesar = pivot.drop(index="Total")["Total"].idxmax()
per_kota = df.groupby("kota", as_index=False)["omzet"].sum()
kota_terbesar = per_kota.loc[per_kota["omzet"].idxmax(), "kota"]
perubahan = (
(bulanan["omzet"].iloc[-1] - bulanan["omzet"].iloc[0])
/ bulanan["omzet"].iloc[0] * 100
).round(1)
print("\n== Temuan utama ==")
print(f"total omzet 3 bulan : {int(bulanan['omzet'].sum())}")
print(
f"bulan terbaik : {bulanan['omzet'].idxmax()} "
f"(omzet {int(bulanan['omzet'].max())})"
)
print(
f"kategori terbesar : {kategori_terbesar} "
f"(omzet {int(pivot.loc[kategori_terbesar, 'Total'])})"
)
print(
f"kota terbesar : {kota_terbesar} "
f"(omzet {int(per_kota['omzet'].max())})"
)
print(f"tren Januari-Maret : {perubahan}%")Output yang Dihasilkan:
== Ringkasan bulanan (resample) ==
omzet transaksi
tanggal
2025-01 9878500 92
2025-02 7363500 63
2025-03 6425500 79
== Omzet kategori per bulan (pivot_table + margins) ==
bulan 2025-01 2025-02 2025-03 Total
kategori
Bahan Pokok 5190500 4509000 3512000 13211500
Kebersihan 629000 536500 351500 1517000
Minuman 3604500 1986500 2104500 7695500
Perawatan 454500 331500 457500 1243500
Total 9878500 7363500 6425500 23667500
== Ekspor ringkasan ke CSV ==
ringkasan_bulanan.csv : 3 baris, kolom ['bulan', 'omzet', 'transaksi']
ringkasan_kategori.csv : 5 baris x 4 kolom
== Temuan utama ==
total omzet 3 bulan : 23667500
bulan terbaik : 2025-01 (omzet 9878500)
kategori terbesar : Bahan Pokok (omzet 13211500)
kota terbesar : Surabaya (omzet 6649500)
tren Januari-Maret : -35.0%Tiga hal di blok kode perlu penjelasan:
resample("ME"): aliasMEberarti month end. Ini penanda wajib pada pandas 3.0 — alias lama"M"sudah dihapus dan menimbulkanValueError— sehingga tabel bulanan berakhir pada 31 Januari, 28 Februari, dan 31 Maret..agg(omzet=..., transaksi=...): named aggregation yang sama seperti pada Bagian 3, kini diterapkan pada objek resampler; hasilnya DataFrame dengan index bertipe datetime.bulanan.index.strftime("%Y-%m"): index datetime diganti label2025-01dan seterusnya agar ringkasan terbaca seperti laporan, bukan tanggal teknis akhir bulan.
Tabel bulanannya ringkas: Januari 9878500 dengan 92 transaksi, Februari 7363500 dengan 63 transaksi, Maret 6425500 dengan 79 transaksi.
Matriks Kategori per Bulan dengan pivot_table #
Satu angka per bulan belum cukup bila kita ingin tahu kategori mana yang menggerakkan naik-turunnya. pivot_table() menjawabnya: index="kategori" sebagai baris, columns="bulan" (kolom bantu %Y-%m yang dibuat di awal skrip), values="omzet", dan aggfunc="sum". Argumen margins=True dengan margins_name="Total" menambahkan baris dan kolom total, sehingga pembaca langsung melihat bahwa Bahan Pokok menyumbang 13211500 dari total 23667500 tanpa menghitung manual.
Matriks ini juga menunjukkan arah per kategori: omzet Bahan Pokok turun dari 5190500 pada Januari ke 3512000 pada Maret, sementara Perawatan justru berakhir lebih tinggi (457500) dari awalnya (454500).
Mengekspor dan Memeriksa Ringkasan #
Ringkasan baru berguna bila bisa keluar dari Python. bulanan.to_csv() menulis ringkasan_bulanan.csv dengan index_label="bulan" agar kolom index punya nama, dan pivot.to_csv() menulis ringkasan_kategori.csv. Kedua berkas langsung dibaca ulang dengan read_csv() untuk memastikan isinya utuh: tabel bulanan kembali dengan 3 baris dan kolom bulan, omzet, transaksi, sedangkan matriks kategori kembali berbentuk 5 baris x 4 kolom. Semua berkas ditulis di dalam TemporaryDirectory, pola yang sudah Anda pakai sejak Bagian 1; pada pekerjaan nyata, ganti path dengan folder laporan Anda.
Menyusun Narasi Temuan #
Bagian akhir skrip mencetak temuan utama yang disarikan dari seluruh proyek: total omzet tiga bulan 23667500, bulan terbaik Januari 2025 dengan omzet 9878500, kategori terbesar Bahan Pokok, kota terbesar Surabaya dengan 6649500, dan tren Januari-Maret yang turun 35.0 persen. Angka-angka ini dirangkai menjadi kalimat siap lapor: omzet dipimpin Bahan Pokok dengan margin terendah (23,2 persen) sesuai temuan Bagian 3, kategori bernilai kecil seperti Perawatan membawa margin tertinggi (29,2 persen), dan penurunan 35 persen dari Januari ke Maret adalah sinyal yang layak ditindaklanjuti dengan promosi kategori bermargin tinggi.
Proyek Analisis Penjualan di sini tuntas: satu berkas CSV mentah dengan lima masalah data berubah menjadi dataset bersih 234 baris, tabel kinerja produk dan kota, serta ringkasan bulanan yang terekspor. Skill yang Anda pakai — memuat CSV, pembersihan bertahap, groupby(), merge(), resample(), pivot_table() — adalah bekal yang sama untuk proyek berikutnya, Proyek: Analisis Harga Komoditas. Di sana kita mulai dari awal lagi dengan dataset harga komoditas harian: Bagian 1 mengimpor data harga, membersihkannya di Bagian 2, menghitung perubahan harga di Bagian 3, lalu membandingkan antar komoditas di Bagian 4.
Sumber bacaan resmi: pandas.DataFrame.resample , pandas.pivot_table , dan pandas.DataFrame.to_csv .