Hubungan antar variabel pada bab sebelumnya kita baca dari data yang diam: semua baris diperlakukan setara tanpa peduli kapan kejadiannya. Padahal urutan dan jarak waktu menyimpan cerita tersendiri — penjualan naik menjelang akhir pekan, turun saat hujan, dan melonjak di hari tertentu. Untuk membaca cerita itu, pandas perlu tahu bahwa sebuah kolom adalah tanggal, bukan teks biasa. Pada chapter ini kita mengubah teks menjadi tipe waktu, mengurai tahun-bulan-hari darinya, lalu merangkum data menjadi rekap mingguan dan bulanan yang bisa dibandingkan secara adil.

Mengubah Teks Menjadi Waktu dengan pd.to_datetime #

Tanggal yang dibaca dari CSV atau diketik manual selalu berupa teks pada awalnya. Selama masih teks, “2025-01-28” tidak bisa diurutkan menurut waktu secara andal, tidak bisa diambil bulannya, dan tidak bisa dihitung jaraknya ke tanggal lain. Fungsi pd.to_datetime() mengubah teks itu menjadi tipe datetime64 — dan sejak itu seluruh peralatan waktu pandas terbuka:

python
import pandas as pd

pesanan = pd.DataFrame({
    "tanggal": ["2025-02-03", "2025-01-28", "2025-02-11", "2025-01-30",
                "2025-02-01", "2025-01-29", "2025-02-07", "2025-02-14"],
    "menu": ["kopi susu", "teh tawar", "matcha latte", "kopi susu",
             "teh tawar", "matcha latte", "kopi susu", "teh tawar"],
    "nilai_ribu": [48, 20, 28, 24, 40, 56, 72, 20],
})

pesanan["tanggal"] = pd.to_datetime(pesanan["tanggal"])
pesanan = pesanan.sort_values("tanggal")

print(pesanan)
print()
print("Tahun    :", pesanan["tanggal"].dt.year.unique().tolist())
print("Bulan    :", sorted(pesanan["tanggal"].dt.month.unique().tolist()))
print("Tanggal  :", pesanan["tanggal"].dt.day.tolist())
print("Nama hari:", pesanan["tanggal"].dt.day_name().tolist())

Output yang Dihasilkan:

text
     tanggal          menu  nilai_ribu
1 2025-01-28     teh tawar          20
5 2025-01-29  matcha latte          56
3 2025-01-30     kopi susu          24
4 2025-02-01     teh tawar          40
0 2025-02-03     kopi susu          48
6 2025-02-07     kopi susu          72
2 2025-02-11  matcha latte          28
7 2025-02-14     teh tawar          20

Tahun    : [2025]
Bulan    : [1, 2]
Tanggal  : [28, 29, 30, 1, 3, 7, 11, 14]
Nama hari: ['Tuesday', 'Wednesday', 'Thursday', 'Saturday', 'Monday', 'Friday', 'Tuesday', 'Friday']

Mari kita telaah baris-baris kode di atas:

  1. pd.to_datetime(pesanan["tanggal"]) mengenali format 2025-01-28 (ISO 8601) tanpa perlu petunjuk tambahan, lalu mengembalikan kolom bertipe datetime64.
  2. sort_values("tanggal") mengurutkan baris menurut waktu. Delapan baris yang tadi datang acak kini berbaris dari akhir Januari ke pertengahan Februari — pengurutan seperti ini wajib sebelum analisis deret waktu, karena hitungan per periode mengasumsikan urutan kronologis.
  3. Akses .dt membuka properti tanggal satu per satu: .dt.year, .dt.month, .dt.day memberi angka; .dt.day_name() memberi nama hari dalam bahasa Inggris (Senin sampai Minggu menjadi Monday sampai Sunday) — kita tinggal memetakan atau menerjemahkannya bila perlu.

Resample: Merangkum per Minggu dan per Bulan #

Data harian terlalu rapat untuk dibaca tren: 42 angka berbaris membuat mata hanya menangkap derau. Metode resample() memadatkannya menjadi bin periode — “W” untuk mingguan, “ME” untuk bulanan (akhir bulan) — lalu masing-masing bin kita jumlahkan. Kita pakai penjualan_harian.csv, rekap pendapatan Toko Kopi Kita selama 42 hari penuh dari 1 Februari sampai 14 Maret 2025:

csv
tanggal,gelas,pendapatan_ribu
2025-02-01,84,1980
2025-02-02,87,2040
2025-02-03,55,1310
2025-02-04,56,1340
2025-02-05,54,1290
2025-02-06,57,1360
2025-02-07,59,1420
2025-02-08,84,2010
2025-02-09,87,2080
2025-02-10,55,1330
2025-02-11,56,1350
2025-02-12,47,1130
2025-02-13,58,1380
2025-02-14,137,3280
2025-02-15,86,2060
2025-02-16,88,2110
2025-02-17,26,620
2025-02-18,41,980
2025-02-19,48,1150
2025-02-20,58,1390
2025-02-21,60,1450
2025-02-22,86,2070
2025-02-23,89,2130
2025-02-24,57,1360
2025-02-25,58,1380
2025-02-26,51,1200
2025-02-27,59,1410
2025-02-28,61,1470
2025-03-01,87,2090
2025-03-02,90,2150
2025-03-03,58,1380
2025-03-04,58,1400
2025-03-05,57,1360
2025-03-06,60,1430
2025-03-07,62,1490
2025-03-08,88,2110
2025-03-09,90,2170
2025-03-10,58,1400
2025-03-11,59,1420
2025-03-12,63,1510
2025-03-13,60,1450
2025-03-14,63,1510
python
import pandas as pd

df = pd.read_csv("penjualan_harian.csv", parse_dates=["tanggal"])

mingguan = df.resample("W", on="tanggal")["pendapatan_ribu"].sum()
bulanan = df.resample("ME", on="tanggal")["pendapatan_ribu"].sum()

print("Total per minggu:")
print(mingguan)
print()
print("Total per bulan:")
print(bulanan)

Output yang Dihasilkan:

text
Total per minggu:
tanggal
2025-02-02     4020
2025-02-09    10810
2025-02-16    12640
2025-02-23     9790
2025-03-02    11060
2025-03-09    11340
2025-03-16     7290
Freq: W-SUN, Name: pendapatan_ribu, dtype: int64

Total per bulan:
tanggal
2025-02-28    44080
2025-03-31    22870
Freq: ME, Name: pendapatan_ribu, dtype: int64

Bedah kode dan hasilnya:

  1. parse_dates=["tanggal"] pada read_csv mengubah kolom tanggal langsung saat pembacaan — cara singkat yang setara dengan pd.to_datetime pada blok sebelumnya.
  2. resample("W", on="tanggal") memotong data menjadi bin mingguan (Senin-Minggu, ditandai tanggal Minggunya) dan ["pendapatan_ribu"].sum() menjumlahkan nilai di dalam tiap bin.
  3. Pekan berlabel 2025-02-16 menonjol (12.640) dibanding pekan tetangganya — di dalamnya terdapat 14 Februari dengan pendapatan 3.280, hampir dua kali lipat hari Jumat biasa. Sebaliknya pekan 2025-02-23 anjlok ke 9.790 karena tiga hari hujan beruntun (17-19 Februari) menekan penjualan. Resample tidak hanya memadatkan; ia juga menyorot periode yang menyimpang.
  4. resample("ME") memotong per bulan dan menandainya dengan tanggal akhir bulan. Perhatikan bahwa Maret hanya terisi 14 hari karena data kita berhenti di tengah bulan.

Membandingkan Bulan secara Adil #

Kesadaran itu membawa kita ke aturan penting analisis waktu: bandingkan periode dengan ukuran yang setara. Alih-alih resample, kita kelompokkan dengan groupby pada bulan hasil .dt.to_period("M"), lalu hitung sekaligus jumlah hari, total, dan rata-rata harian:

python
import pandas as pd

df = pd.read_csv("penjualan_harian.csv", parse_dates=["tanggal"])

per_bulan = df.assign(bulan=df["tanggal"].dt.to_period("M")).groupby("bulan").agg(
    hari=("tanggal", "count"),
    total=("pendapatan_ribu", "sum"),
    rata_harian=("pendapatan_ribu", "mean"),
)
print(per_bulan.round(2))

Output yang Dihasilkan:

text
         hari  total  rata_harian
bulan                            
2025-02    28  44080      1574.29
2025-03    14  22870      1633.57

Cara membaca tabelnya:

  1. .dt.to_period("M") mengubah tiap tanggal menjadi label bulan 2025-02 atau 2025-03; groupby pada kolom itu mengumpulkan seluruh hari sebulan penuh dalam satu kelompok.
  2. total tidak bisa dibandingkan langsung — 44.080 dari 28 hari berhadapan dengan 20.780 dari 14 hari. Kolom rata_harian menyamakan ladangnya: 1.574,29 vs 1.484,29 per hari.
  3. Hasil yang jujur kadang berlawanan dengan intuisi: Maret justru sedikit lebih rendah harinya meski tren mingguan cenderung naik. Penjelasannya ada pada kolom kalender — Februari memuat 14 Februari yang luar biasa; satu hari istimewa itu mengangkat rata-rata sebulan penuh. Inilah mengapa perbandingan periode selalu perlu disertai pemeriksaan hari-hari ekstrem di dalamnya, materi yang kita tuntaskan pada chapter Mendeteksi Pola dan Anomali.

Tiga alat pada bab ini — konversi to_datetime, pemadatan resample, dan pengelompokan to_period — adalah pola dasar untuk membaca hampir semua data berwaktu: penjualan, cuaca, hingga kunjungan situs. Yang membedakan analisis pemula dan yang terlatih biasanya bukan alatnya, melainkan disiplin membandingkan periode yang setara.

Rangkuman #

  • pd.to_datetime() (atau parse_dates pada read_csv) mengubah kolom teks menjadi datetime64; sejak itu .dt.year, .dt.month, .dt.day, dan .dt.day_name() siap dipakai.
  • sort_values("tanggal") sebelum analisis deret waktu; resample("W") dan resample("ME") memadatkan data harian menjadi total mingguan dan bulanan.
  • Bin di pinggir jendela waktu tidak penuh — jangan bandingkan totalnya secara langsung.
  • groupby pada .dt.to_period("M") dengan count + mean memberikan perbandingan antar bulan yang adil lewat rata-rata harian.
  • Satu hari istimewa di dalam periode bisa membalik kesimpulan perbandingan; selalu periksa isi periode, bukan hanya ringkasannya.

Rata-rata harian Februari yang terangkat oleh satu hari istimewa menimbulkan pertanyaan berikutnya: hari apa sajakah yang menyimpang dari pola, dan bagaimana cara menandainya secara sistematis? Chapter berikutnya menyelami persis itu — Mendeteksi Pola dan Anomali .

Referensi #

  1. pandas — User Guide: Time Series
  2. pandas — API Reference: to_datetime
  3. pandas — API Reference: Offset Aliases