Deret waktu adalah kumpulan nilai yang terekam berurutan per periode — penjualan harian, suhu per jam, harga komoditas per pekan. NumPy menyediakan dua perkakas yang dibutuhkan: tipe datetime64 untuk indeks tanggal (dibahas pada Chapter datetime64 dan timedelta64) dan operasi array seperti convolve, diff, serta reshape untuk statistik yang bergeser mengikuti waktu.
Kita mengolah data pendapatan harian warung selama 28 hari (empat minggu) yang sengaja dibuat mengandung pola mingguan plus noise acak ber-seed. Empat pengerjaan yang umum ditanyakan pada deret seperti ini:
- Membentuk deret dari indeks tanggal.
- Menghaluskan fluktuasi dengan rata-rata bergerak 7 hari.
- Mengukur perubahan antar hari dengan
np.diff. - Mengagregasi per minggu dan membandingkan dua prakiraan naif.
Membangun Deret Pendapatan Harian #
Indeks tanggal dibentuk dari np.arange bertipe datetime64[D], dan nilainya disusun dari komponen dasar, pola mingguan sinus, lalu noise:
import numpy as np
rng = np.random.default_rng(11)
tanggal = np.arange("2025-03-01", "2025-03-29", dtype="datetime64[D]")
n = tanggal.size
musiman = 120.0 * np.sin(np.arange(n) * 2 * np.pi / 7)
pendapatan = np.round(850.0 + musiman + rng.normal(0.0, 60.0, n), 0)
print("jumlah hari:", n)
print(tanggal[:4])
print(pendapatan[:7])Output yang Dihasilkan:
jumlah hari: 28
['2025-03-01' '2025-03-02' '2025-03-03' '2025-03-04']
[ 852. 1025. 1040. 871. 780. 701. 790.]Mari kita bedah:
- Baris 4 (
np.arange("2025-03-01", "2025-03-29", dtype="datetime64[D]")): rentang tanggal dibangun sepertiarangebiasa — batas atas bersifat eksklusif, sehingga hasilnya tepat 28 hari dengan satuan hari[D]. - Baris 6 (rumus
musiman): sinus dengan periode 7 menghadirkan gelombang mingguan beramplitudo 120; inilah sumber pola yang nanti ditemukan kembali oleh rata-rata bergerak. - Baris 7 (
rng.normal(0.0, 60.0, n)): noise normal ber-seed meniru ketidakpastian penjualan harian, dannp.roundmembuat nilainya berupa angka bulat. - Baris 9-10: empat tanggal pertama tampil dalam format
YYYY-MM-DD; penjualan hari pertama 852 lalu naik ke 1025 dan 1040 mengikuti gelombang mingguannya.
Rata-rata Bergerak Tujuh Hari #
Fluktuasi harian menutupi pola di baliknya. Rata-rata bergerak menghaluskannya: setiap titik digantikan rata-rata jendela tujuh hari. Dengan NumPy, jendela itu adalah kernel yang dikonvolusikan ke deret:
import numpy as np
rng = np.random.default_rng(11)
tanggal = np.arange("2025-03-01", "2025-03-29", dtype="datetime64[D]")
n = tanggal.size
musiman = 120.0 * np.sin(np.arange(n) * 2 * np.pi / 7)
pendapatan = np.round(850.0 + musiman + rng.normal(0.0, 60.0, n), 0)
kernel = np.ones(7) / 7
rata7 = np.convolve(pendapatan, kernel, mode="valid")
print("jumlah titik:", rata7.size)
print(np.round(rata7[:8], 1))Output yang Dihasilkan:
jumlah titik: 22
[865.6 864.9 859.7 833.4 851.3 853. 863.4 857.4]Penjelasan tiap baris kunci:
- Baris 8 (
np.ones(7) / 7): kernel berisi tujuh nilai1/7; konvolusi mengalikan setiap jendela tujuh hari dengan kernel ini, yang setara dengan mengambil rata-rata jendela. - Baris 9 (
mode="valid"): hanya jendela yang lengkap tujuh hari yang dihitung, sehingga deret hasil menyusut dari 28 menjadi 22 titik — enam hari pertama kehilangan rata-ratanya. - Baris 11: hasil yang berayun antara 833 dan 866 jauh lebih tenang daripada deret aslinya (701-1040); pola gelombang mingguan kini menonjol tanpa tertutup noise harian.
Alternatif tanpa konvolusi: cukup cumsum dari Chapter Cumulative Sum dan Product — selisih cs[7:] - cs[:-7] memberi jumlah setiap jendela, tinggal dibagi tujuh. Hasilnya identik dan hemat untuk jendela besar.
Perubahan Harian dengan np.diff #
Pertanyaan lain yang sering muncul: naik atau turun berapa dari kemarin? np.diff menjawabnya dengan selisih elemen berurutan, dan pembagian mengubahnya menjadi persentase:
import numpy as np
rng = np.random.default_rng(11)
tanggal = np.arange("2025-03-01", "2025-03-29", dtype="datetime64[D]")
n = tanggal.size
musiman = 120.0 * np.sin(np.arange(n) * 2 * np.pi / 7)
pendapatan = np.round(850.0 + musiman + rng.normal(0.0, 60.0, n), 0)
perubahan = np.diff(pendapatan)
persen = perubahan / pendapatan[:-1] * 100
print("selisih harian :", perubahan[:6])
print("perubahan % :", np.round(persen[:6], 1))Output yang Dihasilkan:
selisih harian : [ 173. 15. -169. -91. -79. 89.]
perubahan % : [ 20.3 1.5 -16.2 -10.4 -10.1 12.7]- Baris 8 (
np.diff(pendapatan)): menghasilkan 27 selisih dari 28 titik — panjang deret selalu menyusut satu, karena hari pertama tidak punya pembanding. - Baris 9 (
perubahan / pendapatan[:-1]): penyebutnya deret tanpa elemen terakhir, agar tiap selisih dibagi nilai awalnya sendiri; hasilnya persen perubahan antar hari. - Baris 10-11: lonjakan terbesar terjadi di awal pekan (+173, atau +20,3%), lalu tiga hari penurunan beruntun — informasi yang jauh lebih mudah dibaca daripada deret mentahnya.
Agregasi Mingguan dan Prakiraan Naif #
Karena data kita tepat 28 hari, reshape(-1, 7) menatanya menjadi empat baris mingguan; rata-rata per baris memberi ringkasan per minggu. Setelah itu kita membandingkan dua prakiraan paling sederhana: mengulang nilai tujuh hari lalu, atau mengulang rata-rata keseluruhan:
import numpy as np
rng = np.random.default_rng(11)
tanggal = np.arange("2025-03-01", "2025-03-29", dtype="datetime64[D]")
n = tanggal.size
musiman = 120.0 * np.sin(np.arange(n) * 2 * np.pi / 7)
pendapatan = np.round(850.0 + musiman + rng.normal(0.0, 60.0, n), 0)
mingguan = pendapatan.reshape(-1, 7).mean(axis=1)
print("rata-rata per minggu:", np.round(mingguan, 1))
aktual = pendapatan[7:]
pred_naif = pendapatan[:-7]
mae_naif = np.mean(np.abs(aktual - pred_naif))
pred_rata = np.full(aktual.size, pendapatan.mean())
mae_rata = np.mean(np.abs(aktual - pred_rata))
print(f"MAE naif-7 hari : {mae_naif:.1f}")
print(f"MAE rata-rata : {mae_rata:.1f}")Output yang Dihasilkan:
rata-rata per minggu: [865.6 857.4 853.1 797.1]
MAE naif-7 hari : 58.0
MAE rata-rata : 90.4Bedah baris demi baris:
- Baris 8 (
reshape(-1, 7)): argumen-1membiarkan NumPy menghitung jumlah baris — 28 data menjadi(4, 7);.mean(axis=1)lalu merangkum tiap baris menjadi satu angka mingguan. - Baris 10-11 (prakiraan naif-7):
pendapatan[:-7]dipakai sebagai prediksi untukpendapatan[7:]— prakiraan yang mengasumsikan pekan ini sama seperti pekan lalu. - Baris 12 (
np.mean(np.abs(...))): MAE (Mean Absolute Error) menakar rata-rata meleset prakiraan; inilah ukuran pembanding yang adil untuk kedua model. - Baris 13-15: prakiraan rata-rata statis memakai
np.full; MAE-nya 90,4 berbanding 58,0 milik naif-7. Pola mingguan membuat “sama seperti minggu lalu” jauh lebih akurat daripada “sama seperti rata-rata”.
Sebelum menutup, empat pengerjaan bab ini patut dirangkum beserta efeknya pada panjang deret:
| Pekerjaan | Fungsi NumPy | Panjang hasil |
|---|---|---|
| Indeks tanggal | np.arange(..., dtype="datetime64[D]") | n |
| Rata-rata bergerak 7 hari | np.convolve(x, np.ones(7)/7, mode="valid") | n - 6 |
| Selisih harian | np.diff(x) | n - 1 |
| Agregasi mingguan | x.reshape(-1, 7).mean(axis=1) | n / 7 |
| Prakiraan naif-7 | x[:-7] vs x[7:] | n - 7 |
Empat pengerjaan di atas — indeks tanggal, rata-rata bergerak, selisih, agregasi periode — adalah inti analisis deret waktu pada skala apa pun. Ketika data semakin besar dan berlabel, pandas menyediakan padanannya lewat rolling dan resample; di bawahnya, mekanisme yang bekerja tetap operasi array seperti yang kita praktikkan di bab ini.