Pada section Anomaly Detection sebelumnya, anomali kita perlakukan sebagai titik yang berdiri sendiri: Isolation Forest dan Local Outlier Factor menilai setiap pengamatan lewat posisinya di antara tetangga, tanpa peduli kapan pengamatan itu terjadi. Deret waktu (time series) membalik logika tersebut — urutan pengamatan justru menjadi sumber informasi utama, dan pertanyaan yang kita jawab bergeser dari menandai kejadian menjadi meramalkan kejadian berikutnya. Untuk itu, hampir semua kebiasaan yang kita bangun pada data tabular — pengacakan baris, validasi silang acak, fitur yang berdiri sendiri — perlu ditinjau ulang. Sepanjang section ini kita memakai satu contoh yang sama: penjualan harian toko daring fiktif Toko Ceria, sehingga setiap konsep dapat dibandingkan pada data yang dikenal baik.
Apa yang Membedakan Data Deret Waktu #
Data tabular pada chapter-chapter sebelumnya kita perlakukan sebagai sampel iid — independent and identically distributed — artinya setiap baris ditarik dari distribusi yang sama dan tidak saling memengaruhi. Pada deret waktu, asumsi tersebut tidak berlaku lagi pada dua sisi sekaligus. Pertama, ketergantungan temporal: nilai penjualan hari ini berkorelasi dengan nilai kemarin dan minggu lalu, sehingga urutan baris membawa informasi, bukan sekadar wadah. Kedua, distribusi yang bergeser: tren dan musiman membuat rata-rata serta sebaran data berubah sepanjang waktu, sehingga masa depan memang berbeda dari masa lalu.
| Aspek | Data tabular (iid) | Data deret waktu |
|---|---|---|
| Hubungan antar-baris | Tidak saling memengaruhi | Nilai sekarang bergantung nilai lampau |
| Pembagian latih-uji | Boleh diacak (shuffle) | Wajib kronologis, masa lalu untuk latih |
| Validasi silang | KFold acak aman dipakai | Kebocoran informasi masa depan (bab Validasi Walk-Forward) |
| Sumber fitur prediktif | Kolom yang tersedia | Nilai lampau deret itu sendiri (fitur lag) |
| Pertanyaan khas | Klasifikasi/regresi per baris | Meramalkan nilai pada waktu berikutnya |
Karena urutan membawa informasi, mengacak baris deret waktu sama dengan membuang sinyalnya. Kita akan membuktikan hal ini secara kuantitatif lewat autokorelasi pada bagian akhir chapter, bukan sekadar menerimanya sebagai dalil.
Menyusun Deret Penjualan Sintetis #
Kita butuh data yang komponennya diketahui pasti agar setiap teknik pada section ini dapat diadili dengan ground truth. Contoh berikut membangun 168 hari penjualan (tepat 24 minggu penuh, mulai Senin 5 Januari 2026) dari lima komponen: tren naik lambat, pola mingguan (Jumat–Minggu lebih ramai), kampanye promo dua minggu penuh, diskon kilat satu hari, dan derau acak. Seluruh keacakan berasal dari generator berseed, dan tanggal acuan ditulis tetap — bukan datetime.now() — supaya hasil setiap eksekusi identik.
# Deret penjualan harian toko daring fiktif "Toko Ceria".
# Seluruh komponen dibangun deterministik: tren, pola mingguan,
# kampanye promo dua minggu, diskon kilat satu hari, dan derau
# dari generator angka acak berseed.
import numpy as np
import pandas as pd
def buat_deret_penjualan(n_hari=168):
rng = np.random.default_rng(42)
idx = pd.date_range(start="2026-01-05", periods=n_hari, freq="D")
t = np.arange(n_hari)
tren = 120.0 + 0.45 * t # pertumbuhan lambat
hari = np.asarray(idx.dayofweek) # 0 = Senin
efek_hari = np.select(
[hari == 4, hari == 5, hari == 6],
[10.0, 32.0, 40.0], # Jumat, Sabtu, Minggu
default=0.0,
)
promo = ((t >= 70) & (t < 84)).astype(float) * 45.0 # kampanye 16-29 Mar
kilat = (t == 105).astype(float) * 85.0 # diskon kilat 20 Apr
derau = rng.normal(0.0, 12.0, n_hari)
y = tren + efek_hari + promo + kilat + derau
return pd.Series(np.round(y, 1), index=idx, name="penjualan")
penjualan = buat_deret_penjualan()
print("Lima hari pertama (2026-01-05 adalah hari Senin):")
print(penjualan.head(5).to_string())
mingguan = penjualan.resample("W").mean()
print(f"\nJumlah minggu penuh: {len(mingguan)}")
print("Rata-rata empat minggu pertama:")
print(mingguan.head(4).round(1).to_string())
sebelum = penjualan.loc["2026-03-02":"2026-03-15"].mean()
saat = penjualan.loc["2026-03-16":"2026-03-29"].mean()
print(f"\nRata-rata dua minggu sebelum kampanye: {sebelum:.1f}")
print(f"Rata-rata dua minggu selama kampanye: {saat:.1f}")
print(f"Kenaikan rata-rata selama kampanye: {saat - sebelum:.1f} unit per hari")Output yang Dihasilkan:
Lima hari pertama (2026-01-05 adalah hari Senin):
2026-01-05 123.7
2026-01-06 108.0
2026-01-07 129.9
2026-01-08 132.6
2026-01-09 108.4
Freq: D
Jumlah minggu penuh: 24
Rata-rata empat minggu pertama:
2026-01-11 129.3
2026-01-18 139.1
2026-01-25 138.8
2026-02-01 143.4
Freq: W-SUN
Rata-rata dua minggu sebelum kampanye: 161.1
Rata-rata dua minggu selama kampanye: 208.7
Kenaikan rata-rata selama kampanye: 47.6 unit per hariMari kita telaah baris-baris kode yang berperan penting:
- Baris 10–25 (
def buat_deret_penjualan): fungsi generator membangun seluruh komponen secara eksplisit. Baris 11 membuatrngberseed 42 — satu-satunya sumber keacakan — sedangkan baris 12 memakaipd.date_rangedengan tanggal awal tetap sehingga indeks waktu selalu sama pada setiap eksekusi. - Baris 13–23 (komponen-komponen):
trentumbuh 0,45 unit per hari,efek_harimenambah 10/32/40 unit pada Jumat/Sabtu/Minggu,promomenaikkan 45 unit selama hari ke-70 sampai ke-83 (16–29 Maret),kilatmenyuntik lonjakan 85 unit pada satu hari (20 April), danderaumenambahkan fluktuasi acak bersimpangan baku 12 unit. - Baris 33–36 (
resample("W")): operasiresamplemengubah frekuensi dari harian menjadi mingguan ("W"berakhir hari Minggu), lalu.mean()meringkas tiap minggu menjadi satu nilai. Dari 168 hari diperoleh tepat 24 minggu — bukti frekuensi reguler terjaga. - Baris 38–42 (
penjualan.loc[...]):DatetimeIndexmemungkinkan pemotongan dengan teks tanggal, misalnya["2026-03-16":"2026-03-29"]. Selisih rata-rata dua minggu sebelum dan selama kampanye mencapai 47,6 unit per hari — efek yang kita suntik sendiri dan akan kita kejar lagi dengan berbagai model pada chapter-chapter berikutnya.
Perhatikan pula output head(5): baris terakhirnya bertuliskan Freq: D. pandas menyimpan frekuensi pada indeks dan memanfaatkannya untuk operasi turunan — misalnya melanjutkan indeks saat meramalkan tanggal-tanggal masa depan pada chapter ARIMA untuk Forecasting.
Autokorelasi: Informasi yang Tersimpan di dalam Urutan #
Autokorelasi adalah korelasi antara deret dan salinan dirinya yang digeser beberapa langkah (lag). Autokorelasi lag 1 menjawab “seberapa mirip hari ini dengan kemarin”; lag 7 menjawab “seberapa mirip hari ini dengan hari yang sama minggu lalu”. Metode Series.autocorr(lag=...) pada pandas menghitung korelasi Pearson antara pasangan nilai yang bersesuaian setelah pergeseran. Contoh berikut menghitung autokorelasi deret Toko Ceria, membandingkannya dengan deret yang sama nilainya tetapi urutannya diacak, lalu membagi data secara kronologis.
# Autokorelasi mengukur kuatnya hubungan nilai hari ini dengan nilai
# hari-hari sebelumnya. Pemisahan data latih-uji dilakukan secara
# kronologis, tanpa pengacakan urutan.
import numpy as np
import pandas as pd
def buat_deret_penjualan(n_hari=168):
rng = np.random.default_rng(42)
idx = pd.date_range(start="2026-01-05", periods=n_hari, freq="D")
t = np.arange(n_hari)
tren = 120.0 + 0.45 * t
hari = np.asarray(idx.dayofweek)
efek_hari = np.select(
[hari == 4, hari == 5, hari == 6],
[10.0, 32.0, 40.0],
default=0.0,
)
promo = ((t >= 70) & (t < 84)).astype(float) * 45.0
kilat = (t == 105).astype(float) * 85.0
derau = rng.normal(0.0, 12.0, n_hari)
y = tren + efek_hari + promo + kilat + derau
return pd.Series(np.round(y, 1), index=idx, name="penjualan")
penjualan = buat_deret_penjualan()
print("Autokorelasi deret dengan urutan asli:")
for lag in (1, 2, 3, 7, 14):
print(f" lag {lag:2d}: {penjualan.autocorr(lag):+.3f}")
# Nilai yang sama, urutan diacak: ketergantungan waktu hilang.
rng = np.random.default_rng(42)
teracak = pd.Series(
rng.permutation(penjualan.to_numpy()),
index=penjualan.index,
name="penjualan_teracak",
)
print("\nAutokorelasi deret yang sama setelah urutannya diacak:")
for lag in (1, 2, 3, 7, 14):
print(f" lag {lag:2d}: {teracak.autocorr(lag):+.3f}")
# Pemisahan kronologis 80/20: tanpa pengacakan.
n_latih = int(len(penjualan) * 0.8)
latih = penjualan.iloc[:n_latih]
uji = penjualan.iloc[n_latih:]
print("\nPemisahan kronologis 80/20 (tanpa shuffle):")
print(f" data latih : {latih.index[0].date()} s.d. {latih.index[-1].date()} ({len(latih)} hari)")
print(f" data uji : {uji.index[0].date()} s.d. {uji.index[-1].date()} ({len(uji)} hari)")
print(f" seluruh data uji berada setelah data latih: {uji.index[0] > latih.index[-1]}")Output yang Dihasilkan:
Autokorelasi deret dengan urutan asli:
lag 1: +0.681
lag 2: +0.493
lag 3: +0.381
lag 7: +0.775
lag 14: +0.654
Autokorelasi deret yang sama setelah urutannya diacak:
lag 1: -0.056
lag 2: -0.058
lag 3: +0.066
lag 7: +0.107
lag 14: -0.102
Pemisahan kronologis 80/20 (tanpa shuffle):
data latih : 2026-01-05 s.d. 2026-05-18 (134 hari)
data uji : 2026-05-19 s.d. 2026-06-21 (34 hari)
seluruh data uji berada setelah data latih: TrueBedah kode di atas menyoroti tiga kelompok baris:
- Baris 27–31 (autokorelasi deret asli): lag 1 bernilai +0,681 dan lag 7 mencapai +0,775 — korelasi mingguan lebih kuat daripada korelasi harian karena pola “akhir pekan ramai, hari kerja sepi” berulang tiap tujuh hari. Nilai lag 14 (+0,654) juga tinggi: hari Senin ini memang mirip hari Senin dua minggu lalu. Inilah sinyal yang nanti dipetakan menjadi fitur lag dan komponen musiman.
- Baris 33–42 (pengacakan urutan):
rng.permutationmengacak urutan nilai yang sama persis. Autokorelasi deret hasil acak jatuh ke kisaran −0,10 sampai +0,11 — praktis nol. Nilai-nilainya tidak berubah, tetapi informasi prediktifnya hilang bersama urutannya. Kesimpulannya tegas: pada deret waktu, urutan adalah data. - Baris 44–51 (pemisahan kronologis):
iloc[:n_latih]mengambil 134 hari pertama sebagai data latih (5 Januari–18 Mei) dan 34 hari terakhir sebagai data uji (19 Mei–21 Juni). Baris terakhir memverifikasi secara eksplisit bahwa tanggal uji pertama memang berada setelah tanggal latih terakhir.
Pemisahan Kronologis: Aturan Emas Tanpa Pengacakan #
Pada data tabular, train_test_split secara bawaan mengacak baris agar kedua bagian memiliki distribusi serupa. Pada deret waktu, pengacakan tersebut justru membuat kebocoran: sebagian hari uji berada di masa lalu, sehingga model dilatih pada “masa depan” dari hari yang dinilai — skenario yang mustahil terjadi ketika model benar-benar dipakai untuk meramalkan. Pemisahan yang benar selalu memotong pada satu titik waktu: masa lalu untuk belajar, masa depan untuk dinilai.
Fungsi train_test_split tetap dapat dipakai dengan parameter shuffle=False, tetapi pemotongan langsung lewat iloc seperti pada contoh di atas lebih lugas dan bebas salah paham. Kita juga sebaiknya menahan diri dari KFold acak untuk menilai model deret waktu — bab terakhir section ini, Validasi Walk-Forward, membangun skema evaluasi penggantinya.
Istilah Kunci Chapter Ini #
- Frekuensi (frequency): jarak tetap antar-pengamatan, misalnya
"D"untuk harian padadate_range. - Lag: pergeseran deret sebesar sejumlah langkah waktu; lag 7 berarti nilai tujuh hari sebelumnya.
- Autokorelasi (autocorrelation): korelasi deret dengan salinan dirinya yang digeser; mengukur seberapa banyak informasi yang tersimpan di urutan.
- Pemisahan kronologis (chronological split): pembagian latih-uji dengan satu titik potong waktu, tanpa pengacakan.
- Resample: operasi pandas untuk mengubah frekuensi deret, misalnya harian menjadi mingguan.
Kita kini memiliki data contoh, indeks waktu yang rapi, dan pemahaman bahwa urutan menyimpan informasi. Langkah analisis pertama yang lazim adalah membedah deret menjadi komponen-komponen pembentuknya — tren, musiman, dan residu — agar pola yang tadi hanya terbaca lewat angka autokorelasi dapat dipisahkan satu per satu. Pembedahan tersebut adalah materi Chapter Dekomposisi Deret Waktu.
Referensi Resmi #
- pandas — Time series / date functionality
— panduan resmi
date_range,DatetimeIndex, dan frekuensi. - pandas —
pandas.Series.autocorr— API resmi autokorelasi yang dipakai pada contoh kedua. - scikit-learn — Cross-validation: Time-series split — pembahasan resmi mengapa validasi silang acak tidak sesuai untuk data deret waktu.