Chapter sebelumnya kita memeriksa tren dan musiman lewat dua lensa terpisah: groupby untuk musiman, rolling mean untuk tren. Dekomposisi (decomposition) menggabungkan keduanya dalam satu gerakan: memecah deret menjadi tiga komponen — tren, musiman, dan sisa — sekaligus, dengan metode baku dari statsmodels. Hasilnya bukan sekadar gambar yang indah; tiap komponen bisa kita baca angkanya, dan komponen sisa yang bersih menjadi tanda bahwa tren dan musiman sudah tertangkap tuntas. Pada chapter ini kita jalankan seasonal_decompose, membaca ketiga komponennya, dan menafsirkan hasil dekomposisi penjualan Toko Kopi Kita.
Tiga Komponen dan Model Aditif #
Dekomposisi klasik memodelkan deret sebagai gabungan tiga bagian. Pada model additive (aditif), nilainya dijumlahkan:
y_t = T_t + S_t + R_t
y_t = nilai deret pada waktu t
T_t = komponen tren
S_t = komponen musiman
R_t = komponen sisa (residu)Model aditif cocok bila besaran lonjakan musiman relatif tetap — Sabtu selalu menambah sekitar belasan gelas, baik di awal maupun akhir periode. Sebaliknya, bila lonjakan musiman tumbuh proporsional mengikuti level (Sabtu menambah 20% berapa pun levelnya), bentuk multiplicative dengan perkalian y_t = T_t × S_t × R_t lebih tepat. Aturan praktisnya: amplitudo musiman yang melebar di grafik adalah sinyal untuk memakai model multiplicative; pola kita yang stabil memakai aditif.
| Komponen | Pertanyaan yang dijawab | Pada data kita |
|---|---|---|
Tren T_t | Ke mana arah level jangka panjang? | Naik dari ~46 ke ~69 gelas |
Musiman S_t | Berapa tambahan/kurangan tiap posisi kalender? | Senin -4,7; Sabtu +6,9 gelas |
Sisa R_t | Apa yang tidak dijelaskan tren dan musiman? | Noise bersimpangan ~3 gelas |
Menjalankan seasonal_decompose #
Fungsi seasonal_decompose dari statsmodels mengerjakan pemecahan ini dengan satu panggilan. Kita perlu memberi period=7 — panjang satu periode musiman, yaitu tujuh hari untuk pola mingguan — dan model="additive" sesuai analisis kita di atas.
import numpy as np
import pandas as pd
from statsmodels.tsa.seasonal import seasonal_decompose
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")
hasil = seasonal_decompose(deret, model="additive", period=7)
komponen = pd.DataFrame({
"asli": deret,
"tren": hasil.trend.round(1),
"musiman": hasil.seasonal.round(1),
"sisa": hasil.resid.round(1),
})
print(komponen.iloc[:10])
print()
print("Rentang komponen musiman :", round(hasil.seasonal.max() - hasil.seasonal.min(), 1), "gelas")
print("Simpangan baku sisa :", round(hasil.resid.std(), 1), "gelas")Output yang Dihasilkan:
asli tren musiman sisa
2025-01-06 41 NaN -4.7 NaN
2025-01-07 37 NaN -4.2 NaN
2025-01-08 46 NaN -3.4 NaN
2025-01-09 49 46.1 -3.0 5.9
2025-01-10 43 46.4 1.5 -4.9
2025-01-11 52 47.7 6.9 -2.7
2025-01-12 55 47.4 6.9 0.7
2025-01-13 43 48.0 -4.7 -0.3
2025-01-14 46 50.1 -4.2 0.0
2025-01-15 44 51.4 -3.4 -4.0
Rentang komponen musiman : 11.6 gelas
Simpangan baku sisa : 3.2 gelasMari kita telaah baris-baris kode di atas:
seasonal_decompose(deret, model="additive", period=7)menjalankan dekomposisi klasik: musiman ditaksir dari rata-rata tiap posisi dalam periode (hari ke-0 sampai ke-6 dari pekan), tren dari centered moving average jendela 7 hari, dan sisa adalah asli dikurangi keduanya.hasil.trend,hasil.seasonal,hasil.residmasing-masing berupa Series sepanjang deret asli, yang kita rangkai jadi satuDataFrameagar bisa dibandingkan baris demi baris.NaNpada tiga baris pertama dan terakhir kolom tren bukan galat: rata-rata bergerak terpusat 7 hari tidak punya cukup data di pinggir deret, sehingga tepi tren memang tidak terdefinisi — konsekuensi yang sama denganrollingpada chapter sebelumnya.- Dua baris ringkasan di bawah merangkum mutu dekomposisi: rentang musiman 11,6 gelas (dari Senin terendah sampai Sabtu tertinggi) dan simpangan sisa 3,2 gelas — hampir sama persis dengan noise 4,0 yang kita tanam.
Membaca Hasil Dekomposisi #
Tabel di atas padat dengan temuan. Kolom musiman berulang dengan periode tujuh: Senin selalu -4,7, Selasa -4,2, Sabtu +6,9, Minggu +6,9 — persis profil mingguan yang kita ukur lewat groupby pada chapter Tren dan Musiman, kini dikembalikan dalam satuan tambahan gelas. Kolom tren menanjak mulus dari 46,1 ke 51,4 dalam sepuluh hari pertama (~0,5-0,6/hari, cocok dengan tren yang kita tanam). Kolom sisa berayun di sekitar nol (-4,9 sampai +5,9) tanpa pola — itulah tanda dekomposisi yang sehat: sisa harusnya tidak berpola lagi, karena seluruh struktur sudah dipindahkan ke tren dan musiman.
Blok berikut memvisualisasikan keempat panel (deret asli, tren, musiman, sisa) sekaligus:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.tsa.seasonal import seasonal_decompose
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")
hasil = seasonal_decompose(deret, model="additive", period=7)
hasil.plot()
plt.show()Grafik yang muncul tersusun empat baris: panel teratas menampilkan deret asli yang bertren naik dengan gigi gergaji akhir pekan; panel kedua menampilkan garis tren yang mulus menanjak dengan ujung terpotong (efek NaN di tepi); panel ketiga menampilkan garis musiman yang berulang identik tiap tujuh hari; dan panel keempat menampilkan sisa yang menyebar acak di sekitar nol tanpa arah. Satu gambar, tiga cerita yang terpisah rapi.
Rangkuman #
- Dekomposisi memecah deret menjadi tren + musiman + sisa; model aditif memakai penjumlahan, multiplicative memakai perkalian.
seasonal_decompose(deret, model="additive", period=7)menuntaskan pemecahan untuk pola mingguan;periodharus sesuai panjang periode musiman sebenarnya.- Komponen musiman terbaca sebagai tambahan/kurangan per hari (Senin -4,7, Sabtu +6,9); tren terbaca sebagai level jangka panjang; sisa harusnya tak berpola.
- Tepi kolom tren berisi
NaNkarena centered moving average kehilangan data di pinggir — wajar, bukan galat.
Kini kita punya cara berpikir yang utuh tentang struktur deret. Bab berikutnya memperlakukan salah satunya sebagai alat kerja yang berdiri sendiri: moving average — teknik pemulusan di balik kolom tren tadi — beserta kekuatan dan kelemahannya bila dipakai untuk meramal.