Saat memprediksi hari ini, informasi paling berharga biasanya bukan hari ini itu sendiri, melainkan kemarin. Penjualan kemarin, penjualan hari yang sama minggu lalu, dan rata-rata beberapa hari terakhir membentuk gambaran momentum yang tak bisa ditangkap feature kalender mana pun. Pembuatan fitur deret waktu menyusun gambaran itu secara sistematis lewat tiga alat: lag (menggeser nilai ke masa lalu), rolling window (meringkas jendela beberapa hari), dan diff (selisih antar waktu). Satu aturan menjaganya: jendela hanya boleh mengintip masa lalu — melanggarnya berarti membocorkan jawaban kepada model.

Fitur Lag: Membawa Kemarin ke Hari Ini #

Data kita adalah penjualan empat belas hari berturut-turut. Fitur lag dibuat dengan shift(n): nilai pada baris ke-i digeser ke bawah n langkah, sehingga baris hari ini menerima nilai hari ke-i-n:

python
import pandas as pd

deret = pd.DataFrame({
    "gelas_terjual": [120, 135, 110, 128, 142, 168, 175, 130,
                      125, 118, 138, 150, 172, 180],
})

fitur = deret.copy()
fitur["lag_1"] = fitur["gelas_terjual"].shift(1)
fitur["lag_7"] = fitur["gelas_terjual"].shift(7)
fitur["naik_dari_kemarin"] = fitur["gelas_terjual"].diff()
print(fitur.round(1))

Output yang Dihasilkan:

text
    gelas_terjual  lag_1  lag_7  naik_dari_kemarin
0             120    NaN    NaN                NaN
1             135  120.0    NaN               15.0
2             110  135.0    NaN              -25.0
3             128  110.0    NaN               18.0
4             142  128.0    NaN               14.0
5             168  142.0    NaN               26.0
6             175  168.0    NaN                7.0
7             130  175.0  120.0              -45.0
8             125  130.0  135.0               -5.0
9             118  125.0  110.0               -7.0
10            138  118.0  128.0               20.0
11            150  138.0  142.0               12.0
12            172  150.0  168.0               22.0
13            180  172.0  175.0                8.0

Mari kita amati cara kerjanya:

  1. Baris 9 (shift(1)): kolom digeser satu baris ke bawah. Baris ke-2 kini berpasangan dengan nilai baris ke-1 — kemarin menyapa hari ini. Baris pertama kehilangan pasangannya dan menjadi NaN.
  2. Baris 10 (shift(7)): pergeseran tujuh baris menangkap “hari yang sama minggu lalu” untuk data harian. Perhatikan bahwa tujuh baris pertama kosong — fitur lag n menuntut setidaknya n baris riwayat sebelum baris tersebut.
  3. Baris 11 (diff()): selisih hari_ini - kemarin, pembungkus ringkas dari shift(1) lalu dikurangkan. Nilai +26 pada baris ke-5 berarti hari itu naik 26 gelas dari sehari sebelumnya — arah pergerakan yang tidak terlihat pada angka mentah.
  4. Kolom lag_7: mulai baris ke-7, nilainya (120, 135, 110, …) persis menyalin tujuh baris pertama — persis perilaku yang kita harapkan.

Pemilihan lag yang tepat mengikuti ritme datanya: data harian bernada mingguan cocok dengan lag_7, data penjualan bulanan sering memakai lag_12 (tahun lalu), dan data per jam bisa memakai lag_24.

Rolling Window: Merangkum Ritme Beberapa Hari #

Satu angka kemarin bisa saja hari yang sial. Rata-rata tiga hari terakhir lebih tenang — dan itulah pekerjaan rolling window. Kombinasi shift(1).rolling(3).mean() berarti: geser dulu satu langkah, lalu rata-ratakan tiga hari yang tersisa. Kita bandingkan berdampingan dengan versi tanpa shift yang keliru:

python
import pandas as pd

deret = pd.DataFrame({
    "gelas_terjual": [120, 135, 110, 128, 142, 168, 175, 130,
                      125, 118, 138, 150, 172, 180],
})

fitur = deret.copy()
fitur["rata_3_hari_sebelumnya"] = (
    fitur["gelas_terjual"].shift(1).rolling(3, min_periods=1).mean()
)
fitur["rata_3_termasuk_hari_ini"] = (
    fitur["gelas_terjual"].rolling(3, min_periods=1).mean()
)
print(fitur.round(2))

Output yang Dihasilkan:

text
    gelas_terjual  rata_3_hari_sebelumnya  rata_3_termasuk_hari_ini
0             120                     NaN                    120.00
1             135                  120.00                    127.50
2             110                  127.50                    121.67
3             128                  121.67                    124.33
4             142                  124.33                    126.67
5             168                  126.67                    146.00
6             175                  146.00                    161.67
7             130                  161.67                    157.67
8             125                  157.67                    143.33
9             118                  143.33                    124.33
10            138                  124.33                    127.00
11            150                  127.00                    135.33
12            172                  135.33                    153.33
13            180                  153.33                    167.33

Dua kolom di kanan tampak serupa padahal berbeda nasib:

  1. Baris 9-11 (shift(1).rolling(3, min_periods=1).mean()): urutannya penting — geser dulu, baru rata-rata. Baris hari ini kini merangkum tiga hari sebelum hari itu: baris ke-7 mencatat 161,67 yaitu rata-rata hari ke-4 sampai ke-6 (142, 168, 175). Argumen min_periods=1 mengizinkan jendela terisi sebagian: baris kedua cukup dengan satu nilai kemarin (120,00).
  2. Baris 12-14 (rolling(3).mean() tanpa shift): kolom pembanding ini memuat nilai hari ini di dalam jendelanya sendiri. Baris ke-7 mencatat 161,67 juga — kebetulan sama — tetapi baris ke-6 (146,00) sudah memakai angka 168 milik hari itu sendiri.
  3. Mengapa kedua kolom bisa berangka sama di beberapa baris? Karena rata-rata bergeser satu langkah: jendela termasuk hari ini pada baris ke-i berisi hari ke-i-2 sampai ke-i, sedangkan jendela masa lalu pada baris ke-i+1 berisi hari ke-i-2 sampai ke-i juga — isi sama, pemilik baris berbeda.

Rangkuman #

  • shift(n) membuat fitur lag: kemarin (lag_1), minggu lalu (lag_7), atau periode mana pun yang mengikuti ritme data.
  • diff() menghasilkan perubahan antar periode — arah dan laju pergerakan yang tidak terlihat pada nilai mentah.
  • shift(1).rolling(k, min_periods=1).mean() merangkum k hari terakhir tanpa menyentuh hari ini; min_periods menjaga baris awal tetap terisi.
  • Aturan emas jendela: hanya masa lalu. Rolling yang memuat nilai hari ini membocorkan jawaban dan menggelembungkan skor evaluasi secara palsu.

Nilai kemarin dan rata-rata seminggu membuat tiap baris hari kini kaya konteks. Berikutnya kita berpindah sudut pandang: dari tiap baris ke tiap pelanggan — meringkas puluhan transaksi menjadi beberapa fitur identitas lewat agregasi.

Referensi #

  1. pandas — Time Series Data
  2. pandas — User Guide