Deret penjualan Toko Kopi Kita yang kita bangun pada chapter sebelumnya memuat dua pola yang sengaja kita tanam: penjualan yang merayap naik dari pekan ke pekan, dan lonjakan yang datang tiap akhir pekan. Dalam bahasa analisis deret waktu, keduanya bernama trend (tren) dan seasonality (musiman) — dan mengenali keduanya adalah langkah pertama sebelum peramalan, karena teknik yang tepat untuk keduanya berbeda. Pada chapter ini kita beri definisi yang tajam untuk tren, musiman, dan siklus, lalu kita tunjukkan dua cara mengukurnya dari data: rata-rata per hari lewat groupby, dan garis tren lewat rolling mean.

Tren, Musiman, dan Siklus #

Tren adalah pergerakan arah jangka panjang — naik, turun, atau datar — yang bersumber dari perubahan mendasar: jumlah pelanggan yang bertambah, harga bahan baku yang merambat, atau daya beli masyarakat. Musiman adalah pola yang berulang dengan periode tetap dan bisa kita beri nama kalendernya: setiap hari (jam sibuk siang), setiap pekan (akhir pekan ramai), atau setiap tahun. Siklus mirip musiman karena naik-turun berulang, tetapi panjang periodenya tidak tetap dan tidak terikat kalender — gelombang ekonomi naik-turun dalam rentang beberapa tahun adalah contohnya.

AspekTrenMusimanSiklus
ArahSatu arah panjang (naik/turun)Naik-turun berulangNaik-turun berulang
PeriodeTidak berulangTetap, terikat kalenderTidak tetap
Contoh IndonesiaPenjualan kopi tumbuh seiring pelanggan bertambahRamai tiap Sabtu-Minggu; makan di luar jelang Lebaran; sate ramai saat musim hujanPasar properti dan komoditas naik-turun mengikuti ekonomi

Contoh kalender Indonesia memperlihatkan betapa kuatnya musiman:transportasi dan oleh-oleh melonjak menjelang Lebaran, harga cabai naik pada musim hujan saat panen terganggu, dan es kelapa laku saat kemarau. Jumlah pengamatan yang kita butuhkan juga berbeda: musiman mingguan cukup terlihat setelah beberapa pekan data harian, sedangkan musiman tahunan (Lebaran, musim hujan) menuntut data minimal dua-tiga tahun agar tidak tertukar dengan kejadian sekali itu.

Membaca Musiman Mingguan dengan groupby #

Cara paling lugas mengukur musiman mingguan adalah mengelompokkan seluruh 42 hari menurut nama harinya, lalu menghitung rata-rata tiap kelompok. Karena tiap nama hari muncul tepat enam kali, perbandingannya adil — tidak ada hari yang lebih banyak mewakili daripada yang lain.

python
import numpy as np
import pandas as pd

rng = np.random.default_rng(42)
n = 42
tanggal = pd.date_range("2025-01-06", periods=n, freq="D")
bobot_hari = np.array([0, 1, 2, 3, 8, 14, 11], dtype=float)
gelas = 40 + 0.6 * np.arange(n) + bobot_hari[tanggal.dayofweek] + rng.normal(0, 4.0, n)
deret = pd.Series(gelas.round().astype(int), index=tanggal, name="gelas")

per_hari = deret.groupby(deret.index.day_name()).mean().round(1)
urutan = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
print(per_hari.reindex(urutan))

Output yang Dihasilkan:

text
Monday       51.3
Tuesday      51.8
Wednesday    54.7
Thursday     55.0
Friday       60.7
Saturday     67.0
Sunday       66.8
Name: gelas, dtype: float64

Mari kita telaah hasilnya:

  1. deret.groupby(deret.index.day_name()) mengelompokkan nilai deret menurut nama hari dari indeks waktunya — Senin dengan Senin, Sabtu dengan Sabtu.
  2. .mean() memberi rata-rata enam kemunculan tiap hari, dan reindex(urutan) menyusunnya Senin sampai Minggu agar mudah dibaca.
  3. Pola yang muncul sangat jelas: Senin-Kamis berkisar 51-55 gelas, Jumat naik ke 60,7, lalu Sabtu-Minggu menembus 66-67. Selisih Sabtu terhadap Senin mencapai 15,7 gelas — hampir 30% dari level harian. Bobot musiman yang kita tanam (0-14 gelas) terbaca utuh meski tertutup noise dan tren.

Angka per hari seperti ini berguna untuk keputusan operasional harian — jadwal barista ekstra di akhir pekan, misalnya. Chapter Mendeteksi Pola dan Anomali telah memakai pola mingguan sebagai baseline deteksi anomali; sekarang kita memakainya sebagai bahan bangunan peramalan.

Menonjolkan Tren dengan Rolling Mean #

Rata-rata per hari menonjolkan musiman tetapi menyembunyikan tren. Untuk kebalikannya, kita pakai rolling mean: rata-rata bergerak dari jendela 7 hari yang bergeser satu per satu. Jendela 7 hari sengaja dipilih karena satu pekan penuh memuat semua hari secara seimbang — lonjakan Sabtu diimbangi Senin yang sepi, sehingga musiman mingguan saling meniadakan dan yang tersisa adalah tren.

python
import numpy as np
import pandas as pd

rng = np.random.default_rng(42)
n = 42
tanggal = pd.date_range("2025-01-06", periods=n, freq="D")
bobot_hari = np.array([0, 1, 2, 3, 8, 14, 11], dtype=float)
gelas = 40 + 0.6 * np.arange(n) + bobot_hari[tanggal.dayofweek] + rng.normal(0, 4.0, n)
deret = pd.Series(gelas.round().astype(int), index=tanggal, name="gelas")

rata7 = deret.rolling(7).mean()
tabel = pd.DataFrame({"gelas": deret, "rata_7_hari": rata7.round(1)})
print(tabel.iloc[5:12])
print("...")
print(tabel.iloc[-3:])

Output yang Dihasilkan:

text
            gelas  rata_7_hari
2025-01-11     52          NaN
2025-01-12     55         46.1
2025-01-13     43         46.4
2025-01-14     46         47.7
2025-01-15     44         47.4
2025-01-16     53         48.0
2025-01-17     58         50.1
...
            gelas  rata_7_hari
2025-02-14     74         67.3
2025-02-15     81         68.7
2025-02-16     78         69.3

Cara membaca tabelnya:

  1. deret.rolling(7).mean() menghitung rata-rata nilai sekarang dan enam hari sebelumnya, lalu bergeser. Enam baris pertama tidak cukup data sehingga berisi NaN — baris 11 Januari masih NaN, dan nilai pertama muncul di 12 Januari.
  2. Naiknya rata-rata 7 hari dari 46,1 ke 69,3 memperlihatkan tren dengan sangat jelas: dari sekitar 46 gelas/pekan-per-hari di awal Januari ke 69 di pertengahan Februari, naik 23 gelas dalam 35 hari — konsisten dengan tren 0,6 gelas per hari yang kita tanam.
  3. Gelisahnya kolom gelas (43 ke 81) tidak diikuti kolom rata_7_hari yang bergerak mulus. Inilah fungsi kedua rolling mean: memidahkan noise dan musiman agar tren mudah dilihat.

Rangkuman #

  • Tren adalah arah jangka panjang; musiman adalah pola berulang berperiode tetap; siklus berulang tanpa periode tetap.
  • groupby pada deret.index.day_name() mengukur musiman mingguan secara adil karena tiap hari terwakili sama banyak.
  • rolling(7).mean() meratakan musiman mingguan dan noise sehingga tren terbaca; jendela sebesar satu periode musiman adalah pilihan alami.
  • Musiman tahunan butuh data beberapa tahun; jangan menilainya dari satu kejadian sekali jalan.

Tren dan musiman kini terbaca dari dua arah, tetapi ada satu pertanyaan yang belum terjawab dan justru menentukan pemilihan model: apakah sifat dasar deret ini — rata-rata dan sebarannya — tetap dari waktu ke waktu? Pertanyaan itulah pokok bahasan chapter berikutnya, Stasioneritas .

Referensi #

  1. pandas — API Reference: DataFrame.groupby
  2. pandas — User Guide: Time Series