Keluhan terbesar kita terhadap moving average — semua hari dalam jendela diberi bobot sama padahal informasi terbaru lebih berharga — diselesaikan oleh exponential smoothing: beri bobot terbesar pada pengamatan terbaru, lalu bobot menurun secara eksponensial untuk pengamatan yang makin lama. Dari gagasan sederhana itu lahir keluarga model peramal pertama kita yang sungguhan: Simple Exponential Smoothing (SES) untuk deret datar, dan Holt-Winters yang menambahkan tren serta musiman. Pada chapter ini kita menuliskan rumusnya, mempraktikkan keduanya dengan statsmodels pada data Toko Kopi Kita, dan merasakan bedanya ketika model akhirnya tahu bahwa Sabtu memang selalu ramai.
Bobot yang Menurun Eksponensial #
SES memelihara satu angka bernama level — taksiran rata-rata terkini deret — yang diperbarui setiap ada pengamatan baru:
s_t = alpha * y_t + (1 - alpha) * s_(t-1)
s_t = level (taksiran level) setelah melihat pengamatan ke-t
alpha = parameter pemulusan, 0 < alpha < 1
y_t = pengamatan terbaru
s_(t-1) = level periode sebelumnyaJika rumus itu kita urai berulang kali, level terbukti merupakan rata-rata tertimbang seluruh masa lalu dengan bobot alpha, alpha(1-alpha), alpha(1-alpha)^2, … yang menurun secara geometris — dari situlah nama exponential. Ramalan untuk semua periode mendatang cukup satu angka: level terakhir, s_T. Parameter alpha mengatur karakter model:
| alpha | Respons terhadap perubahan | Garis ramalan | Cocok untuk |
|---|---|---|---|
| 0.1 - 0.3 | Lambat, stabil | Sangat halus | Deret tenang, perubahan langka |
| 0.5 | Sedang | Halus | Keseimbangan umum |
| 0.7 - 0.9 | Cepat, responsif | Mengikuti data | Deret yang sering bergeser |
Simple Exponential Smoothing dengan statsmodels #
Kita latih SES pada 35 hari pertama, meramalkan 7 hari terakhir, dan membandingkan dua karakter: alpha=0.2 yang halus dan alpha=0.8 yang responsif. Argumen optimized=False membuat statsmodels memakai nilai alpha kita apa adanya, bukan menaksirnya dari data — sehingga karakter kedua model benar-benar kita yang pegang.
import numpy as np
import pandas as pd
from statsmodels.tsa.holtwinters import SimpleExpSmoothing
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")
latih = deret.iloc[:-7]
ujian = deret.iloc[-7:]
ses_halus = SimpleExpSmoothing(latih, initialization_method="estimated").fit(
smoothing_level=0.2, optimized=False
)
ses_cepat = SimpleExpSmoothing(latih, initialization_method="estimated").fit(
smoothing_level=0.8, optimized=False
)
ramal_halus = ses_halus.forecast(7)
ramal_cepat = ses_cepat.forecast(7)
banding = pd.DataFrame(
{
"aktual": ujian.values,
"alpha_0.2": ramal_halus.round(1).values,
"alpha_0.8": ramal_cepat.round(1).values,
},
index=ujian.index,
)
print(banding)
print()
mae_halus = np.abs(ramal_halus.values - ujian.values).mean()
mae_cepat = np.abs(ramal_cepat.values - ujian.values).mean()
print(f"MAE alpha 0.2: {mae_halus:.2f} gelas")
print(f"MAE alpha 0.8: {mae_cepat:.2f} gelas")Output yang Dihasilkan:
aktual alpha_0.2 alpha_0.8
2025-02-10 66 66.2 73.1
2025-02-11 62 66.2 73.1
2025-02-12 61 66.2 73.1
2025-02-13 63 66.2 73.1
2025-02-14 74 66.2 73.1
2025-02-15 81 66.2 73.1
2025-02-16 78 66.2 73.1
MAE alpha 0.2: 6.75 gelas
MAE alpha 0.8: 7.73 gelasMari kita telaah hasilnya:
SimpleExpSmoothing(latih).fit(...)memelihara level dari awal deret hingga akhir data latih;.forecast(7)mengembalikan level terakhir untuk tujuh hari ke depan — itulah mengapa kedua kolom ramalan berupa angka yang sama berulang: SES hanya punya satu informasi (level), tanpa tren dan tanpa musiman.alpha_0.2berhenti di 66,2 karena bobot kecil membuat level nyaris tak terguncang pekan akhir yang tinggi;alpha_0.8menanjak ke 73,1 karena levelnya cepat menyerap akhir pekan ramai (78-81 gelas) yang menutup data latih.- Keduanya kalah telak dari kenyataan mingguan: aktual berayun 61 → 81 mengikuti irama Senin-Sabtu, sementara ramalan SES datar sempurna. MAE 6,75 vs 7,73 memang memenangkan alpha kecil, tetapi kemenangan itu datang dari keberuntungan level, bukan dari menangkap pola.
Holt-Winters: Menambahkan Tren dan Musiman #
SES yang datar jelas tidak cukup untuk deret kita. Keluarga Holt-Winters (di statsmodels: ExponentialSmoothing) menambahkan dua persamaan pembaruan lagi: trend (kemiringan yang juga diperbarui dengan pemulusan) dan seasonal (indeks per posisi dalam periode, dalam kasus kita tujuh hari). Ketiganya digabung saat meramal: level terkini + proyeksi tren + penyesuaian musiman hari yang diramal.
import numpy as np
import pandas as pd
from statsmodels.tsa.holtwinters import ExponentialSmoothing
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")
latih = deret.iloc[:-7]
ujian = deret.iloc[-7:]
hw = ExponentialSmoothing(
latih,
trend="add",
seasonal="add",
seasonal_periods=7,
initialization_method="estimated",
).fit()
ramalan = hw.forecast(7)
banding = pd.DataFrame(
{"aktual": ujian.values, "holt_winters": ramalan.round(1).values},
index=ujian.index,
)
print(banding)
mae = np.abs(ramalan.values - ujian.values).mean()
print("MAE Holt-Winters:", round(mae, 2), "gelas")Output yang Dihasilkan:
aktual holt_winters
2025-02-10 66 62.2
2025-02-11 62 63.6
2025-02-12 61 67.2
2025-02-13 63 67.2
2025-02-14 74 71.8
2025-02-15 81 78.0
2025-02-16 78 78.4
MAE Holt-Winters: 3.06 gelasMari kita baca hasilnya:
trend="add"danseasonal="add"menyatakan tren dan musiman ditambahkan ke level — padanan model aditif pada dekomposisi;seasonal_periods=7memberi tahu model panjang satu periode musiman mingguan..fit()tanpa argumen membiarkan statsmodels menaksir ketiga parameter pemulusan (level, tren, musiman) dari data — berbeda dengan blok sebelumnya yang memaksa alpha tertentu.- Ramalan kini bernafas mingguan: Senin 62,2, menanjak ke Jumat 71,8, memuncak Sabtu 78,0, Minggu 78,4 — bentuk yang sama dengan pola aktual. MAE anjlok dari 6,75 (SES terbaik) ke 3,06 gelas, lebih dari setengahnya, semata-mata karena model akhirnya mengenal kalender.
Rangkuman #
- SES memelihara satu level dengan bobot eksponensial menurun; rumus
s_t = alpha*y_t + (1-alpha)*s_(t-1); ramalannya datar untuk semua horizon. - Alpha kecil menghasilkan ramalan halus dan stabil; alpha besar responsif tetapi mudah terperangkap fluktuasi ujung data — responsif tidak sama dengan akurat.
- Holt-Winters menambahkan persamaan tren dan musiman; dengan
seasonal_periods=7, ramalannya mengikuti irama mingguan dan MAE turun dari 6,75 ke 3,06 gelas. - Semua varian exponential smoothing tetap berbasis pemulusan: mereka mengekstrapolasi pola yang sedang berjalan, tanpa menanyakan mekanisme sebab-akibat.
Exponential smoothing meramal dengan memuluskan lalu meneruskan. Ada cara berpikir yang berbeda untuk pekerjaan yang sama: tuliskan nilai sekarang sebagai persamaan regresi atas nilai-nilai lampau — itulah model autoregressive, tokoh utama chapter berikutnya dan bata pertama ARIMA.