Lewati ke konten utama
Data Science

SARIMAX: Deret Waktu Musiman Dengan Variabel Eksternal

Pelajari cara SARIMAX menggabungkan pemodelan deret waktu musiman dengan prediktor eksternal. Pahami parameternya, lihat perbedaannya dengan ARIMA dan SARIMA, dan bangun model peramalan di Python.
Dario Radečić's photo
Dario Radečić
Diperbarui · 15 mnt Baca

Jelajahi bersama AI

ChatGPTClaudePerplexity

Buat Akun Gratis Anda

Berlatih dan lacak kemajuan Anda.

Lanjutkan Dengan Google
Dengan melanjutkan, Anda menerima Ketentuan Penggunaan kami, Kebijakan Privasi kami dan bahwa data Anda disimpan di Amerika Serikat.

Misalkan targetnya adalah permintaan listrik bulanan. Model seperti ARIMA dan SARIMA hanya melihat nilai masa lalu dari deret dan kesalahan peramalan masa lalunya sendiri. Namun, permintaan juga bergantung pada faktor eksternal seperti suhu: musim panas yang panas meningkatkannya, begitu pula musim dingin yang dingin. Jika model tidak dapat melihat faktor-faktor ini, ia memperlakukan setiap bulan yang tidak biasa sebagai derau dan mengulangi kesalahan yang sama saat cuaca berubah lagi.

SARIMAX menyelesaikan masalah ini dengan menambahkan variabel eksternal, atau eksogen, di atas model ARIMA musiman. Model ini tetap mempelajari tren dan musiman dari riwayat deret, tetapi juga menggunakan informasi eksternal yang menjelaskan hal-hal yang tidak dapat dijelaskan oleh nilai masa lalu.

Jika Anda butuh pengantar untuk memanipulasi, menafsirkan, dan memvisualisasikan data deret waktu di Python, daftar ke jalur Time Series in Python kami untuk menguasai dasar-dasarnya dalam seminggu.

Apa Itu SARIMAX?

SARIMAX ialah model ARIMA musiman yang juga dapat menggunakan prediktor eksternal. Secara khusus, namanya merupakan singkatan dari Seasonal AutoRegressive Integrated Moving Average with eXogenous regressors.

SARIMAX bekerja dengan memprediksi deret target dari empat sumber informasi:

  • Nilai masa lalu: Permintaan pada bulan-bulan terakhir
  • Kesalahan peramalan masa lalu: Seberapa jauh meleset model pada bulan-bulan terakhir
  • Pola musiman: Permintaan pada bulan yang sama di tahun-tahun sebelumnya
  • Variabel eksogen: Data eksternal yang Anda tambahkan ke model, seperti suhu rata-rata bulanan

Misalkan tujuannya meramalkan permintaan listrik untuk Juli mendatang. SARIMAX melihat permintaan pada beberapa bulan terakhir, permintaan pada Juli sebelumnya, dan suhu yang diharapkan untuk Juli. Dua yang pertama berasal dari dalam deret dan suhu berasal dari luar.

Anda menuliskan model sebagai SARIMAX(p, d, q)(P, D, Q, S). Sekumpulan parameter pertama mencakup perilaku jangka pendek, dan kumpulan kedua mencakup komponen musiman, di mana S adalah jumlah langkah waktu dalam satu siklus. Untuk data bulanan dengan pola tahunan, S adalah 12.

Variabel eksogen tidak termasuk dalam notasi ini. Anda memberikannya ke model secara terpisah, sebagai masukan tersendiri.

Cara Kerja SARIMAX

SARIMAX memiliki dua kelompok suku, dan variabel eksogen ditambahkan di atasnya.

Suku nonmusiman (p, d, q) memodelkan perilaku jangka pendek:

  • Orde autoregresif p: Berapa banyak nilai masa lalu yang digunakan model. Dengan p = 2, permintaan bulan ini bergantung pada permintaan dalam dua bulan sebelumnya

  • Orde pembedaan d: Berapa kali model melakukan diferensiasi deret untuk menghapus tren. Dengan d = 1, model bekerja dengan perubahan bulan ke bulan alih-alih permintaan mentah

  • Orde moving average q: Berapa banyak kesalahan peramalan masa lalu yang digunakan model. Jika model meremehkan permintaan bulan lalu, kesalahan itu memengaruhi prediksi bulan ini

Suku musiman (P, D, Q, S) melakukan hal yang sama, tetapi pada lag musiman:

  • Orde autoregresif musiman P: Berapa banyak musim sebelumnya yang dilihat model. Dengan P = 1 dan data bulanan, permintaan Juli ini bergantung pada permintaan Juli lalu

  • Orde pembedaan musiman D: Berapa kali model membedakan deret pada lag musiman. Dengan D = 1, model membandingkan Juli ini dengan Juli lalu, yang menghapus pola tahunan berulang

  • Orde moving average musiman Q: Berapa banyak kesalahan peramalan di lag musiman yang digunakan model, seperti kesalahan dari Juli lalu

  • Periode musiman S: Berapa banyak langkah waktu dalam satu siklus. Nilainya 12 untuk data bulanan dengan pola tahunan dan 7 untuk data harian dengan pola mingguan

Variabel eksogen menambahkan informasi yang tidak dimiliki deret.

Dalam contoh permintaan listrik, variabel itu adalah suhu. Musim panas yang panas atau musim dingin yang dingin meningkatkan permintaan, dan nilai permintaan masa lalu tidak dapat memberi tahu model bagaimana cuaca bulan depan. Pola bulan dalam setahun sudah ditangkap oleh suku musiman, jadi suhu adalah satu-satunya variabel eksternal yang dibutuhkan contoh ini.

Di statsmodels, SARIMAX adalah regresi linear pada variabel eksogen, di mana error mengikuti proses ARIMA musiman. Dengan satu variabel eksogen, bentuknya seperti ini:

SARIMAX dengan satu variabel eksogen

SARIMAX dengan satu variabel eksogen

Di sini, y_t adalah permintaan listrik pada bulan t, x_t adalah suhu pada bulan tersebut, beta adalah koefisien suhu, dan u_t adalah bagian dari permintaan yang tidak dijelaskan oleh suhu. Suku nonmusiman dan musiman memodelkan u_t.

Secara sederhana, suhu menjelaskan sebagian permintaan, dan suku SARIMA memodelkan sisanya.

Berikut ringkasan yang lebih visual:

Komponen SARIMAX

Komponen SARIMAX

ARIMA vs. SARIMA vs. ARIMAX vs. SARIMAX

Keempat model ini berasal dari keluarga yang sama. Perbedaannya tipis, tetapi Anda akan memahaminya setelah sekali baca.

ARIMA memodelkan deret dari nilai masa lalunya sendiri dan kesalahan peramalan masa lalu. SARIMA menambahkan suku musiman di atasnya, sehingga dapat memodelkan pola yang berulang setiap S langkah waktu. ARIMAX menambahkan variabel eksogen ke ARIMA, tetapi secara bawaan tidak memiliki suku musiman. SARIMAX memiliki keduanya.

Itulah mengapa SARIMAX dapat merepresentasikan model lain sebagai kasus khusus. Jika Anda tidak memberikan variabel eksogen, Anda mendapatkan model SARIMA. Jika semua orde musiman diset ke nol, Anda mendapatkan model ARIMAX nonmusiman. Dan tanpa keduanya, jadinya model ARIMA.

Namun sayangnya, terminologi tidak konsisten di berbagai paket.

ARIMAX versi buku teks menempatkan variabel eksogen langsung ke dalam persamaan ARIMA, berdampingan dengan nilai masa lalu deret. SARIMAX milik statsmodels justru menyesuaikan regresi dengan error SARIMA, seperti ditunjukkan pada bagian sebelumnya. Kedua bentuk tersebut mengestimasi koefisien yang berbeda, sehingga variabel suhu yang sama bisa mendapat koefisien berbeda tergantung paketnya.

Nama kelas dan fungsi juga tidak seragam. Kelas ARIMA di statsmodels juga menerima suku musiman dan variabel eksogen. Di R, paket forecast menangani regressor eksternal melalui argumen xreg pada Arima() dan auto.arima(). Karena itu, ingat untuk memeriksa bagaimana setiap paket mendefinisikan model sebelum Anda membandingkan hasil antar alat.

Berikut ringkasan singkat:

  Musiman? Variabel eksternal?
ARIMA Tidak Tidak
SARIMA Ya Tidak
ARIMAX Tidak secara bawaan Ya
SARIMAX Ya Ya

Perbandingan keluarga model ARIMA

Kapan Menggunakan SARIMAX

SARIMAX masuk akal ketika target memiliki pola musiman yang berulang dan variabel eksternal dapat meningkatkan peramalan.

Sebagai contoh:

  • Permintaan listrik: Suhu dan efek kalender seperti hari libur nasional, di atas siklus tahunan
  • Penjualan ritel: Promosi, harga, dan periode liburan
  • Pemesanan hotel: Acara lokal dan harga kamar, di atas musim perjalanan tahunan
  • Penumpang transportasi umum: Cuaca dan liburan sekolah, di atas pola mingguan pada data harian

Namun SARIMAX tidak selalu pilihan yang tepat. Model yang lebih sederhana bisa melakukan hal yang sama dalam dua kasus ini:

  • Tak ada musiman yang berarti: Jika deret tidak mengulang pola, suku musiman hanya menambah parameter untuk diestimasi. ARIMA atau ARIMAX sudah cukup
  • Prediktor tidak meningkatkan akurasi: Jika variabel eksogen tidak mengurangi error pada periode uji yang ditahan, hapus dan gunakan SARIMA. Kesesuaian yang lebih baik pada data latih tidak dihitung

Hal yang perlu diingat di sini adalah SARIMAX membutuhkan nilai untuk setiap variabel eksogen dalam periode peramalan.

Beberapa nilai sudah diketahui sebelumnya, misalnya hari libur nasional atau promosi yang direncanakan. Yang lain, seperti suhu, harus diramalkan secara terpisah sebelum dapat digunakan SARIMAX. Jika Anda tidak bisa mendapatkan nilai masa depan untuk suatu prediktor, Anda tidak bisa menggunakannya dalam peramalan.

Cara Membangun Model SARIMAX di Python

Pada bagian ini, saya akan membangun model SARIMAX dengan statsmodels, dari data mentah hingga peramalan 12 bulan.

Contoh ini menggunakan permintaan listrik bulanan sintetis dengan suhu sebagai variabel eksternal. Datasetnya kecil dan dapat direproduksi, serta mengikuti alur cerita yang sama seperti artikel ini.

Siapkan data

Dataset mencakup sepuluh tahun data bulanan, dari Januari 2015 hingga Desember 2024.

Permintaan memiliki tren naik, pola kalender tahunan yang berubah perlahan seiring waktu, efek cuaca, dan derau. Dua pembacaan suhu sengaja dihilangkan, agar Anda dapat melihat cara menangani celah data:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import warnings

warnings.filterwarnings("ignore")

rng = np.random.default_rng(10)

# Monthly timestamps from January 2015 to December 2024
dates = pd.date_range(start="2015-01-01", periods=120, freq="MS")
month = dates.month.to_numpy()

# Average monthly temperature in degrees Celsius
temperature = 12 + 11 * np.sin(2 * np.pi * (month - 4) / 12) + rng.normal(0, 2, 120)

# Calendar pattern that repeats every year and changes slowly over time
calendar_effect = 15 * np.cos(2 * np.pi * (month - 1) / 12)
for t in range(12, 120):
    calendar_effect[t] = calendar_effect[t - 12] + rng.normal(0, 2.5)

# Short-term noise where each month carries over part of the previous one
noise = np.zeros(120)
for t in range(1, 120):
    noise[t] = 0.5 * noise[t - 1] + rng.normal(0, 6)

# Demand in GWh: upward trend, calendar pattern, weather effect, and noise
trend = np.linspace(500, 560, 120)
heating_demand = 6 * np.clip(18 - temperature, 0, None)
cooling_demand = 9 * np.clip(temperature - 18, 0, None)
demand = trend + calendar_effect + heating_demand + cooling_demand + noise

df = pd.DataFrame(
    {"demand_gwh": demand.round(1), "temperature": temperature.round(1)},
    index=dates,
)

# Two missing temperature readings
df.loc[["2018-07-01", "2021-02-01"], "temperature"] = np.nan

print(df.head())

Lima baris pertama dataset

Lima baris pertama dataset

Atau, jika Anda lebih suka gambaran visual:

Dataset suhu

Dataset suhu

Jika Anda bekerja dengan data sendiri, muat dengan pd.read_csv() dan setel kolom tanggal sebagai indeks. Alur kerja selebihnya tetap sama.

SARIMAX membutuhkan indeks waktu dengan frekuensi konsisten. Metode .asfreq() menyetelnya ke bulanan dan menyisipkan baris kosong untuk bulan yang hilang. Lalu Anda dapat menghitung celahnya dan mengisinya:

df = df.asfreq("MS")
print(df.isna().sum())

df["temperature"] = df["temperature"].interpolate()

Interpolasi celah suhu

Interpolasi celah suhu

Interpolasi linear cocok di sini karena suhu berubah mulus dari bulan ke bulan. Jangan lakukan hal yang sama untuk target jika bagian besarnya hilang. Anda akan mengajari model dengan nilai buatan.

Selanjutnya, variabel eksogen. Permintaan naik saat dingin dan saat panas, tetapi regresi garis lurus pada suhu mentah tidak bisa memodelkan bentuk U. Jadi saya akan memecah suhu menjadi dua fitur:

  • Heating degrees: Berapa derajat suhu rata-rata berada di bawah 18 derajat Celsius, dan nol jika tidak
  • Cooling degrees: Berapa derajat suhu rata-rata berada di atas 18 derajat Celsius, dan nol jika tidak
df["heating_degrees"] = (18 - df["temperature"]).clip(lower=0)
df["cooling_degrees"] = (df["temperature"] - 18).clip(lower=0)

Sekarang pisahkan data menjadi target y dan variabel eksogen X. Pemisahan harus kronologis: model dilatih pada masa lalu dan diuji pada masa depan. Pemisahan acak akan membocorkan informasi masa depan ke pelatihan:

y = df["demand_gwh"]
X = df[["heating_degrees", "cooling_degrees"]]

y_train, y_test = y[:"2022-12"], y["2023-01":]
X_train, X_test = X[:"2022-12"], X["2023-01":]

print(f"Train: {len(y_train)} months, Test: {len(y_test)} months")

Pemisahan latih/uji

Pemisahan latih/uji

Hal yang perlu diingat di sini adalah X_test memiliki suhu teramati sebenarnya. Dalam peramalan nyata, Anda tidak akan mengetahuinya terlebih dahulu - paling bagus Anda punya prakiraan cuaca. Ini berarti skor uji yang akan Anda lihat nanti bersifat optimistis. Gunakan nilai prediktor teramati untuk evaluasi hanya jika nilai yang sama akan tersedia saat peramalan, seperti hari libur nasional atau harga yang direncanakan.

Jelajahi musiman dan stasioneritas

Mulailah dengan plot. Anda mencari tren, siklus musiman, dan perubahan mendadak:

from statsmodels.tsa.seasonal import seasonal_decompose

fig, ax = plt.subplots(figsize=(10, 4))
y_train.plot(ax=ax, title="Monthly electricity demand (GWh)")
plt.show()

Permintaan listrik bulanan pada periode pelatihan

Permintaan listrik bulanan pada periode pelatihan

Permintaan meningkat seiring waktu, dan memuncak setiap musim dingin dengan puncak yang lebih kecil setiap musim panas. Polanya berulang setiap 12 bulan.

Dekomposisi musiman akan membagi deret menjadi komponen tren, musiman, dan residual, sehingga Anda dapat mengonfirmasi periode musiman S:

decomposition = seasonal_decompose(y_train, model="additive", period=12)
decomposition.plot()
plt.show()

Dekomposisi musiman permintaan listrik

Dekomposisi musiman permintaan listrik

Komponen musiman berulang setiap tahun, jadi S = 12.

Model keluarga ARIMA memerlukan deret yang stasioner - yang rerata dan variansnya tidak berubah seiring waktu. Permintaan tidak stasioner karena memiliki tren dan siklus musiman. 

Pembedaan adalah cara untuk mengatasi itu:

  • Pembedaan reguler (d): Mengurangkan nilai bulan lalu dari nilai bulan ini. Ini menghapus tren

  • Pembedaan musiman (D): Mengurangkan nilai dari bulan yang sama tahun lalu. Ini menghapus pola musiman berulang, dan juga menghapus tren linear

Uji Augmented Dickey-Fuller (ADF) memeriksa stasioneritas. Hipotesis nolnya adalah deret tidak stasioner, jadi p-value kecil (di bawah 0,05) menjadi bukti bahwa deret stasioner:

from statsmodels.tsa.stattools import adfuller

series_versions = {
    "Original": y_train,
    "Seasonally differenced (D=1)": y_train.diff(12).dropna(),
    "Both differences (d=1, D=1)": y_train.diff().diff(12).dropna(),
}

for name, series in series_versions.items():
    adf_stat, p_value = adfuller(series)[:2]
    print(f"{name}: ADF statistic = {adf_stat:.2f}, p-value = {p_value:.4f}")

Hasil uji ADF

Hasil uji ADF

Deret asli tidak stasioner. Pembedaan musiman saja sudah memperbaikinya, jadi pembedaan reguler di atasnya tidak menambah apa-apa. Gunakan jumlah pembedaan paling kecil yang berhasil - pembedaan berlebih menambah derau pada deret dan menyulitkan penyesuaian model.

Jadi pilihannya adalah d = 0 dan D = 1.

Namun perlakukan uji ADF hanya sebagai bukti pendukung. Uji ini tidak memberi tahu apa pun tentang p, q, P, atau Q, dan pada deret pendek dapat memberi jawaban berbeda tergantung pengaturannya.

Pilih parameter kandidat

Plot ACF dan PACF membantu Anda memilih nilai kandidat untuk orde yang tersisa:

  • ACF (autocorrelation function): Menunjukkan korelasi antara deret dan nilai tertundanya sendiri. Paku pada ACF mengarah ke suku moving average, q pada lag pendek dan Q pada lag musiman

  • PACF (partial autocorrelation function): Menunjukkan korelasi yang sama, tetapi menghapus pengaruh lag di antaranya. Paku pada PACF mengarah ke suku autoregresif, p pada lag pendek dan P pada lag musiman

Anda sebaiknya memplot keduanya untuk deret yang telah dibedakan secara musiman, karena itulah deret yang digunakan model:

from statsmodels.graphics.tsaplots import plot_acf, plot_pacf

y_seasonal_diff = y_train.diff(12).dropna()

fig, axes = plt.subplots(1, 2, figsize=(12, 4))
plot_acf(y_seasonal_diff, lags=24, ax=axes[0])
plot_pacf(y_seasonal_diff, lags=24, ax=axes[1])
plt.show()

Plot ACF dan PACF dari permintaan listrik yang dibedakan secara musiman

Plot ACF dan PACF dari permintaan listrik yang dibedakan secara musiman

ACF memiliki paku negatif yang jelas pada lag 12 dan tidak ada pada lag 24. Itu adalah tanda khas suku moving average musiman, jadi Q = 1 adalah kandidat bagus. Kedua plot juga menunjukkan beberapa paku pada lag pendek, jadi p dan q layak diuji.

Langkah berikutnya adalah menyesuaikan sejumlah kecil model kandidat dan membandingkannya dengan AIC atau BIC. Keduanya menilai seberapa baik model menyesuaikan data latih dan menghukum parameter tambahan. Lebih rendah lebih baik, dan BIC menghukum kompleksitas lebih keras daripada AIC:

import itertools
from statsmodels.tsa.statespace.sarimax import SARIMAX

candidates = []
for p, q, P, Q in itertools.product([0, 1], [0, 1], [0, 1], [0, 1]):
    candidate = SARIMAX(
        y_train,
        exog=X_train,
        order=(p, 0, q),
        seasonal_order=(P, 1, Q, 12),
        trend="c",
    ).fit(disp=False)
    candidates.append({
        "order": (p, 0, q),
        "seasonal_order": (P, 1, Q, 12),
        "AIC": round(candidate.aic, 1),
        "BIC": round(candidate.bic, 1),
    })

print(pd.DataFrame(candidates).sort_values("AIC").head(5).to_string(index=False))

Hasil AIC dan BIC

Hasil AIC dan BIC

SARIMAX(1, 0, 0)(0, 1, 1, 12) menang pada AIC dan BIC. Ini juga salah satu model tersederhana dalam daftar.

Argumen trend="c" menambahkan konstanta. Dengan pembedaan musiman, konstanta memodelkan peningkatan permintaan dari tahun ke tahun.

Anda akan menemukan alat seperti auto_arima() dari pustaka pmdarima yang menjalankan pencarian ini untuk Anda. Alat tersebut berguna untuk langkah pertama, tetapi AIC dan BIC hanya mengukur kesesuaian pada data latih. Sebelum mempercayai model, uji pada data yang belum pernah dilihat.

Sesuaikan model

Berikan target sebagai argumen pertama dan variabel eksogen melalui exog. Argumen order menerima (p, d, q), dan seasonal_order menerima (P, D, Q, S):

model = SARIMAX(
    y_train,
    exog=X_train,
    order=(1, 0, 0),
    seasonal_order=(0, 1, 1, 12),
    trend="c",
)
results = model.fit(disp=False)
print(results.summary())

Ringkasan model SARIMAX

Ringkasan model SARIMAX

Berikut cara membaca tabel koefisien:

  • heating_degrees: Setiap heating degree tambahan berkaitan dengan sekitar 6,6 GWh permintaan ekstra, dengan hal lain dalam model tetap

  • cooling_degrees: Setiap cooling degree tambahan berkaitan dengan sekitar 7,4 GWh permintaan ekstra

  • ar.L1: Sekitar 46% dari selisih tak terjelaskan bulan lalu terbawa ke bulan ini

  • ma.S.L12: Suku moving average musiman, yang mengoreksi peramalan berdasarkan kesalahan dari bulan yang sama tahun lalu

  • sigma2: Varians derau yang tersisa

Semua koefisien memiliki p-value mendekati nol, jadi setiap suku menambahkan sesuatu ke model.

Namun koefisien-koefisien ini menggambarkan hubungan di dalam model terpasang, bukan sebab-akibat. Di sini, saya membangkitkan data dengan suhu sebagai penyebab permintaan, jadi penafsirannya aman. Pada data nyata, sebuah prediktor bisa tampak penting karena bergerak bersama dengan sesuatu yang tidak terlihat oleh model.

Diagnosis dan evaluasi model

Model yang baik menyisakan residual yang terlihat seperti derau acak. Jika residual masih memiliki pola, berarti ada sesuatu yang terlewat oleh model.

Metode .plot_diagnostics() memberi Anda empat plot dalam satu pemanggilan:

from statsmodels.stats.diagnostic import acorr_ljungbox

results.plot_diagnostics(figsize=(12, 8))
plt.show()

Plot diagnostik residual

Plot diagnostik residual

Berikut yang perlu dicari:

  • Residual terstandarisasi: Tidak ada tren, tidak ada pola berulang, dan tidak ada rentang di mana sebaran menjadi jauh lebih lebar
  • Histogram dan plot Q-Q: Titik-titik mendekati distribusi normal
  • Korelogram: Tidak ada paku di luar pita kepercayaan, terutama pada lag 12 - paku di sana berarti model belum sepenuhnya menangani musiman

Uji Ljung-Box memberi pemeriksaan yang sama dalam bentuk angka. Hipotesis nolnya adalah residual tidak memiliki autokorelasi hingga lag tertentu, jadi Anda menginginkan p-value besar:

# Lewati 13 residual pertama, yang berasal dari periode awal pembedaan
print(acorr_ljungbox(results.resid[13:], lags=[12, 24]))

Hasil uji Ljung-Box

Hasil uji Ljung-Box

Kedua p-value jauh di atas 0,05, sehingga residual tampak seperti derau.

Sekarang bagian yang paling penting - akurasi pada data yang belum dilihat model. Metode .get_forecast() memprediksi 24 bulan uji, dan membutuhkan nilai eksogen untuk bulan-bulan tersebut.

Angka peramalan sendirian kurang bermakna, jadi saya akan membandingkan SARIMAX dengan dua baseline:

  • Peramalan naif musiman: Mengulang nilai dari 12 bulan terakhir data latih
  • SARIMA: Model yang sama, tetapi tanpa variabel eksogen
from sklearn.metrics import mean_absolute_error, root_mean_squared_error

sarimax_pred = results.get_forecast(steps=len(y_test), exog=X_test).predicted_mean

# Baseline 1: repeat the last 12 observed months
naive_pred = pd.Series(np.tile(y_train[-12:].to_numpy(), 2), index=y_test.index)

# Baseline 2: the same model without exogenous variables
sarima_results = SARIMAX(
    y_train, order=(1, 0, 0), seasonal_order=(0, 1, 1, 12), trend="c"
).fit(disp=False)
sarima_pred = sarima_results.get_forecast(steps=len(y_test)).predicted_mean

for name, pred in [("SARIMAX", sarimax_pred), ("SARIMA", sarima_pred), ("Seasonal naive", naive_pred)]:
    mae = mean_absolute_error(y_test, pred)
    rmse = root_mean_squared_error(y_test, pred)
    print(f"{name:<15} MAE = {mae:.2f} GWh, RMSE = {rmse:.2f} GWh")

fig, ax = plt.subplots(figsize=(10, 4))
y_train["2020":].plot(ax=ax, label="Train")
y_test.plot(ax=ax, label="Test")
sarimax_pred.plot(ax=ax, label="SARIMAX", linestyle="--")
naive_pred.plot(ax=ax, label="Seasonal naive", linestyle=":")
ax.legend()
plt.show()

Peramalan SARIMAX dan naif musiman versus permintaan aktual di set uji

Peramalan SARIMAX dan naif musiman versus permintaan aktual di set uji

MAE (mean absolute error) adalah ukuran rata-rata besarnya error dalam GWh. RMSE (root mean squared error) menghukum error besar lebih keras.

SARIMAX memiliki sekitar setengah error SARIMA pada kedua metrik. Suku musiman saja tidak dapat memprediksi Januari yang sangat dingin atau Juli yang panas, sedangkan fitur suhu dapat.

Ingat, hasil ini menggunakan suhu periode uji yang teramati. Dengan prakiraan cuaca sebagai gantinya, selisihnya akan lebih kecil.

Meramalkan nilai masa depan

Setelah Anda puas dengan modelnya, pasang ulang pada semua data, sehingga peramalan dimulai dari bulan terbaru.

Lalu lakukan peramalan dengan .get_forecast(). Anda memerlukan nilai untuk setiap variabel eksogen di setiap bulan masa depan. Jika ada yang hilang, statsmodels akan menimbulkan error.

Sumber nilai-nilai tersebut bergantung pada variabelnya. Misalnya:

  • Fitur kalender yang diketahui: Hari libur dan jumlah hari kerja diketahui bertahun-tahun sebelumnya
  • Keputusan bisnis yang direncanakan: Harga dan promosi diketahui jika tim Anda sudah menjadwalkannya
  • Cuaca: Suhu membutuhkan peramalan terpisah, dari layanan cuaca atau dari model lain
  • Rata-rata historis: Jika tidak ada yang lebih baik, gunakan nilai rata-rata untuk setiap bulan kalender dari data masa lalu

Saya akan menggunakan opsi terakhir di sini sebagai pengganti prakiraan cuaca:

final_results = SARIMAX(
    y, exog=X, order=(1, 0, 0), seasonal_order=(0, 1, 1, 12), trend="c"
).fit(disp=False)

future_dates = pd.date_range(start="2025-01-01", periods=12, freq="MS")

# Stand-in for a weather forecast: the average temperature of each calendar month
monthly_normals = df.groupby(df.index.month)["temperature"].mean()
future_temperature = monthly_normals.loc[future_dates.month].to_numpy()

X_future = pd.DataFrame({
    "heating_degrees": np.clip(18 - future_temperature, 0, None),
    "cooling_degrees": np.clip(future_temperature - 18, 0, None),
}, index=future_dates)

forecast = final_results.get_forecast(steps=12, exog=X_future)
forecast_df = pd.concat([forecast.predicted_mean.rename("forecast"), forecast.conf_int(alpha=0.05)], axis=1)
print(forecast_df.round(1))

fig, ax = plt.subplots(figsize=(10, 4))
y["2021":].plot(ax=ax, label="Observed")
forecast.predicted_mean.plot(ax=ax, label="Forecast")
ci = forecast.conf_int(alpha=0.05)
ax.fill_between(ci.index, ci.iloc[:, 0], ci.iloc[:, 1], alpha=0.3, label="95% interval")
ax.legend()
plt.show()

Peramalan permintaan listrik 12 bulan dengan interval prediksi 95%

Peramalan permintaan listrik 12 bulan dengan interval prediksi 95%

Peramalan mengikuti bentuk yang familier, dengan permintaan tertinggi di musim dingin, lonjakan lebih kecil di musim panas, dan permintaan terendah di musim semi dan gugur.

Namun interval 95% hanya mencakup ketidakpastian model terpasang, mengingat nilai suhu yang Anda berikan. Ini tidak mencakup ketidakpastian pada suhu tersebut. Jika Januari ternyata jauh lebih dingin dari rata-rata, permintaan aktual bisa berada di luar interval meski modelnya benar.

Jika Anda ingin melihat seberapa sensitif peramalan, jalankan lagi dengan skenario suhu yang lebih dingin dan lebih hangat dan bandingkan hasilnya.

Keterbatasan SARIMAX

SARIMAX adalah model yang baik untuk banyak masalah peramalan musiman, tetapi memiliki beberapa batasan. Berikut yang perlu Anda ketahui:

  • Prediktor masa depan wajib ada: Model tidak bisa meramal tanpa nilai untuk setiap variabel eksogen di setiap bulan masa depan. Jika suatu prediktor tidak diketahui sebelumnya dan Anda tidak dapat meramalkannya, prediktor itu tidak layak dimasukkan ke model, seberapa pun ia meningkatkan kesesuaian pada data masa lalu

  • Ketidakpastian prediktor tersembunyi: Ketika prediktor masa depan merupakan peramalan juga, kesalahannya terbawa ke peramalan permintaan. Interval prediksi standar tidak mencakupnya, sehingga tampak lebih sempit daripada seharusnya

  • Menangani satu periode musiman: Bentuk standar mendukung satu S. Permintaan listrik per jam memiliki siklus harian dan mingguan, dan SARIMAX tidak dapat memodelkan keduanya sekaligus. Model ini juga menjadi lambat dengan periode musiman yang panjang, seperti S = 168 untuk siklus mingguan pada data per jam

  • Hubungan dapat berubah: Model mengasumsikan pola dalam data latih akan tetap sama di masa depan. Jika lebih banyak rumah beralih ke heat pump, dampak cuaca dingin pada permintaan akan berubah, dan koefisien lama tidak lagi menggambarkannya. Anda harus memasang ulang model pada data terbaru secara berkala dan melacak akurasinya dari waktu ke waktu

  • Pemilihan parameter perlu kehati-hatian: Model dengan AIC rendah masih bisa menghasilkan peramalan buruk. AIC dan BIC hanya melihat data latih, jadi uji kandidat akhir pada periode yang ditahan, atau lebih baik, dengan validasi silang deret waktu pada beberapa jendela waktu

  • Bukan model kausal: Koefisien yang signifikan memberi tahu bahwa prediktor membantu peramalan, bukan bahwa ia menyebabkan perubahan pada target. Jika Anda ingin tahu apa yang terjadi pada permintaan ketika Anda mengubah harga, Anda memerlukan metode inferensi kausal

Kesimpulan

Jika data Anda mengulang pola musiman dan bergantung pada faktor eksternal, SARIMAX layak dicoba. Model ini menggabungkan riwayat deret dan faktor eksternal yang memengaruhinya. Ketika data Anda memiliki keduanya, model ini biasanya lebih baik daripada model yang hanya melihat salah satunya.

Hal yang perlu diingat adalah model hanya sebaik input yang Anda berikan. Pilih periode musiman berdasarkan data, selaraskan prediktor dengan cermat, uji pada data masa depan alih-alih mempercayai AIC, dan pastikan Anda akan memiliki nilai masa depan untuk setiap prediktor sebelum membangun apa pun. Jika Anda tidak bisa melakukan yang terakhir, SARIMAX bukan pilihan yang tepat untuk dataset Anda.

Jika Anda ingin terus belajar, daftar ke kursus Time Series Analysis in Python kami dan pahami dasarnya dalam satu sore.


Dario Radečić's photo
Author
Dario Radečić
LinkedIn
Senior Data Scientist yang berbasis di Kroasia. Penulis Tekno Teratas dengan lebih dari 700 artikel yang telah diterbitkan, menghasilkan lebih dari 10 juta tayangan. Penulis buku Machine Learning Automation with TPOT.

FAQ

Untuk apa SARIMAX digunakan?

SARIMAX meramalkan deret waktu yang memiliki pola musiman berulang dan bergantung pada faktor eksternal. Permintaan listrik dengan suhu atau pemesanan hotel dengan acara lokal adalah contoh umum. Jika deret Anda hanya memiliki salah satu dari dua karakteristik ini, model yang lebih sederhana seperti SARIMA atau ARIMAX biasanya sudah memadai.

Apa perbedaan antara SARIMA dan SARIMAX?

SARIMA memodelkan deret dari nilai masa lalunya sendiri, kesalahan peramalan masa lalu, dan pola musiman. SARIMAX menambahkan variabel eksogen di atas itu, sehingga juga dapat menggunakan informasi eksternal seperti suhu atau harga. Jika Anda menyesuaikan SARIMAX tanpa variabel eksogen, Anda mendapatkan model SARIMA.

Apakah SARIMAX merupakan model machine learning?

SARIMAX adalah model statistik, bukan model machine learning dalam pengertian biasa. Model ini memiliki struktur tetap, sejumlah kecil parameter, serta koefisien yang dapat Anda baca dan tafsirkan. Itu membuatnya menjadi pilihan yang baik untuk dataset kecil, di mana model machine learning tidak memiliki cukup data untuk dipelajari.

Mengapa get_forecast() menghasilkan error saat saya meramalkan dengan SARIMAX?

Jika Anda memasang model dengan argumen exog, statsmodels memerlukan nilai eksogen untuk setiap langkah waktu masa depan. Tanpanya, get_forecast() akan menghasilkan ValueError. Berikan sebuah DataFrame dengan kolom yang sama seperti prediktor pelatihan Anda dan satu baris per langkah peramalan.

Bisakah SARIMAX menangani lebih dari satu periode musiman?

Tidak dalam bentuk standarnya, karena seasonal_order menerima satu periode S. Untuk data dengan lebih dari satu siklus, seperti permintaan per jam dengan pola harian dan mingguan, Anda dapat menyetel S ke siklus yang lebih pendek dan memberikan suku Fourier untuk siklus yang lebih panjang melalui exog. Model seperti TBATS dan Prophet mendukung beberapa periode musiman secara langsung.

Topik
Data Science
Terkait

blogs

Tutorial Korelasi di R

Dapatkan pengenalan dasar-dasar korelasi di R: pelajari lebih lanjut tentang koefisien korelasi, matriks korelasi, plotting korelasi, dan sebagainya.
David Woods's photo

David Woods

13 mnt

blogs

Spaghetti Plot dan Jalur Badai

Temukan alasan mengapa Anda sebaiknya (tidak) menggunakan spaghetti plot untuk menyampaikan ketidakpastian jalur prediksi badai serta dampaknya terhadap interpretasi.
Hugo Bowne-Anderson's photo

Hugo Bowne-Anderson

13 mnt

blogs

40 Pertanyaan Wawancara DBMS Teratas di 2026

Kuasai pertanyaan wawancara basis data, dari konsep SQL dasar hingga skenario desain sistem tingkat lanjut. Panduan mendalam ini mencakup semua yang Anda perlukan untuk sukses di wawancara DBMS dan meraih peran berikutnya.
Dario Radečić's photo

Dario Radečić

15 mnt

blogs

12 Alternatif ChatGPT Terbaik yang Bisa Anda Coba pada 2026

Artikel ini menyajikan daftar alternatif ChatGPT yang akan meningkatkan produktivitas Anda.
Javier Canales Luna's photo

Javier Canales Luna

14 mnt

Lihat Selengkapnya