Transportasi udara merupakan salah satu moda transportasi yang memiliki peran strategis dalam mendukung konektivitas antardaerah di Indonesia sebagai negara kepulauan. Jumlah penumpang pesawat domestik menjadi salah satu indikator penting dalam mengukur tingkat mobilitas masyarakat serta kinerja sektor penerbangan nasional.
Berdasarkan data Badan Pusat Statistik (BPS), rata-rata jumlah penumpang pesawat domestik pada periode sebelum pandemi (2017–2019) mencapai sekitar 7,2 juta penumpang per bulan, dengan puncak tertinggi pada Juli 2018 yang mencapai 8,95 juta penumpang. Namun, pandemi COVID-19 yang melanda Indonesia sejak awal 2020 menyebabkan penurunan drastis hingga titik terendah pada Mei 2020 dengan hanya 87.008 penumpang — turun lebih dari 98% dibandingkan kondisi normal. Seiring pelonggaran pembatasan sosial, jumlah penumpang berangsur pulih, meskipun rata-rata periode 2022–2025 masih berada di sekitar 4,97 juta penumpang per bulan.
Fluktuasi yang signifikan ini menunjukkan bahwa data penumpang pesawat domestik memiliki pola musiman yang kuat, terutama dipengaruhi oleh musim liburan, hari raya, dan faktor-faktor eksternal seperti pandemi. Oleh karena itu, diperlukan suatu metode peramalan deret waktu yang mampu menangkap pola musiman sekaligus tren jangka panjang secara akurat.
Laporan ini bertujuan untuk:
Data yang digunakan dalam analisis ini adalah data jumlah penumpang pesawat domestik bulanan yang bersumber dari Badan Pusat Statistik (BPS) Republik Indonesia, mencakup 5 bandar udara utama di Indonesia pada periode Januari 2017 – Desember 2025 (108 observasi). Data ini mencerminkan volume penumpang pada rute domestik dan mencakup periode pandemi COVID-19 (2020–2021) yang menjadi gangguan struktural (structural break) pada deret waktu.
Deret waktu adalah sekumpulan data yang dikumpulkan atau dicatat berdasarkan urutan waktu dengan interval yang sama (misalnya harian, bulanan, atau tahunan). Tujuan analisis deret waktu adalah memahami pola yang terkandung dalam data historis dan menggunakannya untuk membuat peramalan (forecasting) di masa mendatang.
Secara umum, deret waktu dapat mengandung empat komponen utama:
ARIMA (Autoregressive Integrated Moving Average) adalah model deret waktu yang menggabungkan tiga komponen:
Model ARIMA dinotasikan sebagai ARIMA(p, d, q) dan hanya cocok untuk data yang tidak memiliki pola musiman. Ketika data memiliki komponen musiman yang signifikan — seperti data penumpang pesawat bulanan — diperlukan perluasan model menjadi SARIMA.
SARIMA (Seasonal Autoregressive Integrated Moving Average) merupakan perluasan dari model ARIMA yang mampu menangkap pola musiman dalam data deret waktu. Model SARIMA dinotasikan sebagai:
\[\text{SARIMA}(p, d, q)(P, D, Q)[s]\]
| Parameter | Jenis | Keterangan |
|---|---|---|
| \(p\) | Non-musiman | Orde AR non-musiman: pengaruh \(p\) nilai masa lalu terdekat |
| \(d\) | Non-musiman | Jumlah differencing non-musiman untuk mencapai stasioneritas |
| \(q\) | Non-musiman | Orde MA non-musiman: pengaruh \(q\) error masa lalu terdekat |
| \(P\) | Musiman | Orde AR musiman: pengaruh nilai pada lag musiman ke-\(1\) s.d. \(P\) |
| \(D\) | Musiman | Jumlah differencing musiman |
| \(Q\) | Musiman | Orde MA musiman: pengaruh error pada lag musiman ke-\(1\) s.d. \(Q\) |
| \(s\) | Periode | Panjang satu siklus musiman (\(s = 12\) untuk data bulanan) |
Pada analisis ini digunakan \(s = 12\) karena data bersifat bulanan sehingga satu siklus musiman terdiri dari 12 bulan.
Identifikasi orde model SARIMA dilakukan dengan mengamati pola pada plot ACF (Autocorrelation Function) dan PACF (Partial Autocorrelation Function) setelah proses differencing. Terdapat dua pola utama yang diperhatikan:
| Kondisi ACF | Kondisi PACF | Model yang Diindikasikan |
|---|---|---|
| Cut off setelah lag \(q\) | Dies down | MA(\(q\)) |
| Dies down | Cut off setelah lag \(p\) | AR(\(p\)) |
| Dies down | Dies down | ARMA(\(p\), \(q\)) |
Berdasarkan materi perkuliahan (Darmawan, 2024), pola pada lag musiman (lag \(s\), \(2s\), \(3s\), …) diidentifikasi sebagai berikut:
| Model Musiman | ACF pada Lag Musiman | PACF pada Lag Musiman |
|---|---|---|
| SAR(\(P\)) | Dies down | Cut off setelah lag \(Ps\) |
| SMA(\(Q\)) | Cut off setelah lag \(Qs\) | Dies down |
| SARMA(\(P\), \(Q\)) | Dies down | Dies down |
Setelah differencing gabungan (\(d = 1\), \(D = 1\)), pengamatan dilakukan pada:
Apabila pada lag-lag kecil, ACF cut off setelah lag 1 → mengindikasikan MA(1) (\(q = 1\)). Apabila PACF cut off setelah lag 1 → mengindikasikan AR(1) (\(p = 1\)). Pada lag musiman (kelipatan 12), apabila ACF cut off setelah lag 12 dan PACF dies down → mengindikasikan SMA(1) (\(Q = 1\)). Sebaliknya jika PACF cut off setelah lag 12 → SAR(1) (\(P = 1\)).
Berdasarkan pola-pola tersebut, beberapa model kandidat SARIMA diajukan dan dibandingkan menggunakan kriteria AIC (Akaike Information Criterion) dan BIC (Bayesian Information Criterion).
Setelah model terbaik dipilih, dilakukan evaluasi melalui dua tahap:
1. Uji Diagnostik Residual
Model yang baik menghasilkan residual yang bersifat white noise — tidak mengandung autokorelasi tersisa. Pengujian dilakukan menggunakan uji Ljung-Box dengan hipotesis:
Jika \(p\text{-value} > 0{,}05\), maka gagal tolak \(H_0\) → residual bersifat white noise → model layak digunakan.
2. Evaluasi Akurasi Peramalan
Akurasi peramalan diukur menggunakan:
MAPE (Mean Absolute Percentage Error): rata-rata persentase kesalahan absolut. \[\text{MAPE} = \frac{1}{n}\sum_{t=1}^{n}\left|\frac{Y_t - \hat{Y}_t}{Y_t}\right| \times 100\%\]
Kriteria MAPE: < 10% = sangat akurat, 10–20% = baik, 20–50% = layak, > 50% = tidak akurat.
MSE (Mean Squared Error): rata-rata kuadrat kesalahan, sensitif terhadap kesalahan besar. \[\text{MSE} = \frac{1}{n}\sum_{t=1}^{n}(Y_t - \hat{Y}_t)^2\]
data_raw <- read.csv("C:/Users/Fathia S/Downloads/data video adw1.xlsx - data.csv", header = TRUE, sep = ",")
colnames(data_raw) <- trimws(colnames(data_raw))
datatable(data_raw, options = list(pageLength = 6, scrollX = TRUE),
caption = "Tabel 1. Data Jumlah Penumpang Pesawat Domestik per Bulan")datats <- ts(data_raw$Total, start = c(2017, 1), frequency = 12)
data <- datats
n_obs <- length(data)
cat("Jumlah observasi :", n_obs, "\n")## Jumlah observasi : 108
## Periode data : Januari 2017 - December 2025
Interpretasi: Data terdiri dari 108 observasi bulanan dengan frekuensi musiman 12 (data bulanan). Variabel yang dianalisis adalah Total, yaitu jumlah penumpang pesawat domestik per bulan.
autoplot(data) +
labs(title = "Data Aktual Jumlah Penumpang Pesawat Domestik (2017–2025)",
x = "Tahun", y = "Jumlah Penumpang") +
scale_y_continuous(labels = comma) +
theme_minimal(base_size = 12) +
geom_line(color = "steelblue", linewidth = 0.9)Interpretasi: Plot menunjukkan adanya tren dan pola musiman yang relatif stabil pada periode sebelum 2020. Pada awal 2020 terjadi penurunan drastis akibat pandemi COVID-19, diikuti oleh proses pemulihan (recovery) secara bertahap hingga mendekati atau melampaui level sebelum pandemi pada tahun-tahun terakhir. Pola ini menunjukkan deret waktu belum stasioner baik dalam rata-rata maupun terdapat unsur musiman.
ggseasonplot(data, year.labels = TRUE, continuous = TRUE) +
labs(title = "Seasonal Plot - Jumlah Penumpang Domestik per Bulan",
y = "Jumlah Penumpang") +
scale_y_continuous(labels = comma) +
theme_minimal(base_size = 11)Interpretasi: Seasonal plot memperlihatkan pola musiman yang berulang setiap tahun, dengan kenaikan pada bulan-bulan tertentu (misalnya menjelang liburan/lebaran/akhir tahun) dan penurunan pada bulan lain. Garis tahun 2020–2021 tampak jauh di bawah garis tahun lainnya, menegaskan dampak pandemi.
ggsubseriesplot(data) +
labs(title = "Subseries Plot - Rata-rata Penumpang per Bulan",
y = "Jumlah Penumpang") +
scale_y_continuous(labels = comma) +
theme_minimal(base_size = 10)Interpretasi: Garis horizontal biru pada setiap panel menunjukkan rata-rata jumlah penumpang untuk bulan tersebut sepanjang periode pengamatan. Terlihat variasi rata-rata antarbulan yang mengindikasikan adanya komponen musiman dalam data.
par(mfrow = c(1, 2))
Acf(data, lag.max = 48, main = "ACF Data Asli")
Pacf(data, lag.max = 48, main = "PACF Data Asli")Interpretasi: Plot ACF menunjukkan penurunan (decay) yang lambat, mengindikasikan data tidak stasioner dalam rata-rata. Pola gelombang berulang pada lag kelipatan 12 mengindikasikan adanya komponen musiman. Hal ini menjadi dasar perlunya proses differencing.
##
## Augmented Dickey-Fuller Test
##
## data: data
## Dickey-Fuller = -1.7501, Lag order = 4, p-value = 0.6803
## alternative hypothesis: stationary
Interpretasi: Nilai p-value uji ADF sebesar 0.6803 (> 0,05), sehingga gagal tolak H0, artinya data belum stasioner. Karena belum stasioner, dilakukan proses differencing.
dif_original <- diff(data)
autoplot(dif_original) +
labs(title = "Differencing Non-Musiman (d=1, D=0)", x = "Tahun", y = "Selisih") +
theme_minimal(base_size = 12) +
geom_line(color = "darkorange")##
## Augmented Dickey-Fuller Test
##
## data: dif_original
## Dickey-Fuller = -5.6469, Lag order = 4, p-value = 0.01
## alternative hypothesis: stationary
Interpretasi: Setelah differencing satu kali (d=1), p-value ADF menjadi 0.01. Nilai ini ≤ 0,05 sehingga data sudah stasioner dalam rata-rata setelah differencing non-musiman, namun pola musiman pada plot masih dapat terlihat.
dif_season <- diff(data, lag = 12)
autoplot(dif_season) +
labs(title = "Differencing Musiman (d=0, D=1)", x = "Tahun", y = "Selisih Musiman") +
theme_minimal(base_size = 12) +
geom_line(color = "seagreen")##
## Augmented Dickey-Fuller Test
##
## data: dif_season
## Dickey-Fuller = -2.1305, Lag order = 4, p-value = 0.5225
## alternative hypothesis: stationary
Interpretasi: Differencing musiman (lag 12) menghasilkan p-value ADF sebesar 0.5225. Hasil ini menunjukkan differencing musiman saja belum cukup untuk mencapai stasioneritas.
dif_oriseason <- diff(dif_original, lag = 12)
autoplot(dif_oriseason) +
labs(title = "Differencing Gabungan Non-Musiman & Musiman (d=1, D=1)",
x = "Tahun", y = "Selisih") +
theme_minimal(base_size = 12) +
geom_line(color = "firebrick")##
## Augmented Dickey-Fuller Test
##
## data: dif_oriseason
## Dickey-Fuller = -5.0312, Lag order = 4, p-value = 0.01
## alternative hypothesis: stationary
Interpretasi: Setelah differencing gabungan (d=1, D=1), p-value ADF menjadi 0.01 (≤ 0,05), sehingga H0 ditolak dan data dinyatakan stasioner. Berdasarkan hasil ini, ordo differencing d=1 dan D=1 dipilih sebagai dasar identifikasi model SARIMA.
conf_bound <- qnorm(0.975) / sqrt(length(dif_oriseason))
par(mfrow = c(2, 1))
acf_res <- acf(dif_oriseason, lag.max = 48, plot = FALSE)
plot(acf_res$acf, type = "h", xaxt = "n",
xlab = "Lag", ylab = "ACF", main = "ACF Data Setelah Differencing (d=1, D=1)")
axis(1, at = 1:48, labels = 1:48)
abline(h = c(0, conf_bound, -conf_bound), col = c("black", "blue", "blue"), lty = c(1, 2, 2))
abline(v = seq(12, 48, by = 12), col = rgb(1, 0, 0, 0.4), lty = 2)
pacf_res <- pacf(dif_oriseason, lag.max = 48, plot = FALSE)
plot(as.vector(pacf_res$acf), type = "h", xaxt = "n",
xlab = "Lag", ylab = "PACF", main = "PACF Data Setelah Differencing (d=1, D=1)")
axis(1, at = 1:48, labels = 1:48)
abline(h = c(0, conf_bound, -conf_bound), col = c("black", "blue", "blue"), lty = c(1, 2, 2))
abline(v = seq(12, 48, by = 12), col = rgb(1, 0, 0, 0.4), lty = 2)Interpretasi: Garis biru putus-putus menunjukkan batas signifikansi (interval kepercayaan 95%). Lag yang melewati batas ini dianggap signifikan.
Berdasarkan pola decay/cut-off pada kedua plot tersebut, beberapa model kandidat SARIMA(p,d,q)(P,D,Q)[12] dengan d=1 dan D=1 diajukan pada bagian berikut, ditambah hasil pencarian otomatis auto.arima() sebagai pembanding.
M1 <- Arima(data, order = c(0,1,1), seasonal = list(order = c(0,1,1), period = 12))
M2 <- Arima(data, order = c(1,1,0), seasonal = list(order = c(1,1,0), period = 12))
M3 <- Arima(data, order = c(0,1,1), seasonal = list(order = c(1,1,0), period = 12))
M4 <- Arima(data, order = c(1,1,0), seasonal = list(order = c(0,1,1), period = 12))
M5 <- Arima(data, order = c(1,1,1), seasonal = list(order = c(1,1,1), period = 12))
Mauto <- auto.arima(data, stepwise = FALSE, approximation = FALSE)
models <- list(M1, M2, M3, M4, M5, Mauto)
model_names <- c("SARIMA(0,1,1)(0,1,1)[12]",
"SARIMA(1,1,0)(1,1,0)[12]",
"SARIMA(0,1,1)(1,1,0)[12]",
"SARIMA(1,1,0)(0,1,1)[12]",
"SARIMA(1,1,1)(1,1,1)[12]",
paste0("auto.arima -> ", arimaorder(Mauto)[1], ",",
arimaorder(Mauto)[2], ",", arimaorder(Mauto)[3], "x",
arimaorder(Mauto)[4], ",", arimaorder(Mauto)[5], ",",
arimaorder(Mauto)[6], "[12]"))
aic_df <- data.frame(
Model = model_names,
AIC = round(sapply(models, AIC), 2),
BIC = round(sapply(models, BIC), 2)
)
datatable(aic_df, options = list(dom = 't'),
caption = "Tabel 2. Perbandingan AIC dan BIC Model Kandidat") %>%
formatStyle(columns = "AIC", backgroundColor = styleEqual(min(aic_df$AIC), "lightgreen"))best_idx <- which.min(aic_df$AIC)
best_model <- models[[best_idx]]
cat("Model terbaik berdasarkan AIC terendah:", aic_df$Model[best_idx],
"\nAIC =", aic_df$AIC[best_idx],
"| BIC =", aic_df$BIC[best_idx], "\n")## Model terbaik berdasarkan AIC terendah: SARIMA(1,1,1)(1,1,1)[12]
## AIC = 2864.06 | BIC = 2876.83
Interpretasi: Tabel di atas membandingkan enam model kandidat SARIMA berdasarkan nilai AIC dan BIC (semakin kecil semakin baik). Model dengan AIC terendah, yaitu SARIMA(1,1,1)(1,1,1)[12] (AIC = 2864.06, BIC = 2876.83), dipilih sebagai model terbaik untuk digunakan pada analisis selanjutnya.
## Series: data
## ARIMA(1,1,1)(1,1,1)[12]
##
## Coefficients:
## ar1 ma1 sar1 sma1
## 0.8276 -0.8934 0.2604 -0.9999
## s.e. 0.4644 0.4045 0.1201 0.1486
##
## sigma^2 = 5.461e+11: log likelihood = -1427.03
## AIC=2864.06 AICc=2864.73 BIC=2876.83
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set 6788.919 678356.8 417328.6 -11.72763 22.71989 0.3132201 0.0141989
Interpretasi: Output di atas menampilkan estimasi koefisien AR/MA (musiman dan non-musiman) beserta standard error-nya, serta ukuran akurasi in-sample seperti RMSE, MAE, dan MAPE. Koefisien dengan nilai |koefisien| jauh lebih besar dari standard error-nya (rasio > 2) dapat dianggap signifikan secara statistik.
##
## Ljung-Box test
##
## data: Residuals from ARIMA(1,1,1)(1,1,1)[12]
## Q* = 26.64, df = 18, p-value = 0.08601
##
## Model df: 4. Total lags used: 22
Interpretasi: Uji Ljung-Box menghasilkan p-value sebesar 0.08601.
Pada kasus ini, p-value sebesar 0.08601> 0.05, sehingga residual model memenuhi asumsi white noise (model layak digunakan). Histogram residual pada plot di atas juga menunjukkan apakah residual mendekati distribusi normal.
df_fit <- data.frame(
Time = as.numeric(time(data)),
Aktual = as.numeric(data),
Fitted = as.numeric(fitted(best_model))
)
p_fit <- ggplot(df_fit, aes(x = Time)) +
geom_line(aes(y = Aktual, color = "Aktual"), linewidth = 0.9) +
geom_line(aes(y = Fitted, color = "Fitted"), linewidth = 0.9) +
scale_color_manual(values = c("Aktual" = "steelblue", "Fitted" = "red")) +
scale_y_continuous(labels = comma) +
labs(title = "Perbandingan Nilai Aktual vs Fitted",
x = "Tahun", y = "Jumlah Penumpang", color = NULL) +
theme_minimal(base_size = 12) +
theme(legend.position = "bottom")
ggplotly(p_fit)Interpretasi: Plot interaktif di atas menunjukkan bahwa nilai fitted (merah) secara umum mengikuti pola data aktual (biru), termasuk pola musiman dan penurunan tajam pada periode pandemi. Kedekatan kedua garis mengindikasikan model SARIMA terpilih cukup baik dalam menangkap pola historis data. Arahkan kursor pada grafik untuk melihat nilai pada titik waktu tertentu.
fc <- forecast(best_model, h = 12)
fc_df <- data.frame(
Periode = format(seq(as.Date(paste0(end(data)[1], "-", end(data)[2], "-01")),
by = "month", length.out = 13)[-1], "%b %Y"),
Forecast = round(as.numeric(fc$mean), 0),
Lo80 = round(as.numeric(fc$lower[,1]), 0),
Hi80 = round(as.numeric(fc$upper[,1]), 0),
Lo95 = round(as.numeric(fc$lower[,2]), 0),
Hi95 = round(as.numeric(fc$upper[,2]), 0)
)
datatable(fc_df, options = list(pageLength = 12, dom = 't'),
caption = "Tabel 3. Hasil Peramalan 12 Bulan ke Depan") %>%
formatCurrency(columns = 2:6, currency = "", interval = 3, mark = ",", digits = 0)Interpretasi: Berdasarkan tabel dan grafik peramalan, hasil peramalan untuk 12 bulan mendatang (Januari–Desember 2026) menunjukkan prediksi titik (forecast) yang berkisar antara 4.013.081 hingga 5.224.828 penumpang per bulan, beserta interval kepercayaan 80% (Lo80–Hi80) dan 95% (Lo95–Hi95) yang digambarkan sebagai pita biru dan abu-abu pada grafik. Pola musiman pada periode peramalan mengikuti pola historis, dengan nilai yang relatif lebih rendah pada awal hingga pertengahan tahun (Februari–Maret di kisaran 4,0–4,2 juta) dan meningkat pada bulan Juli serta Desember (masing-masing 4.991.996 dan 5.224.828), sesuai karakteristik musiman yang teridentifikasi sebelumnya. Lebar interval kepercayaan yang semakin membesar untuk horizon yang lebih jauh menunjukkan meningkatnya ketidakpastian peramalan jangka panjang.
test_lengths <- c(3, 6, 12)
eval_list <- list()
for (n_test in test_lengths) {
train <- head(data, -n_test)
test <- tail(data, n_test)
mdl <- Arima(train,
order = best_model$arma[c(1,6,2)],
seasonal = list(order = best_model$arma[c(3,7,4)],
period = frequency(data)))
fcast <- forecast(mdl, h = n_test)$mean
eval_list[[as.character(n_test)]] <- data.frame(
h = n_test,
MAPE = round(mean(abs((test - fcast) / test)) * 100, 4),
MSE = round(mean((test - fcast)^2), 2)
)
}
eval_df <- do.call(rbind, eval_list)
datatable(eval_df, options = list(dom = 't'),
caption = "Tabel 4. Evaluasi Akurasi Peramalan pada Berbagai Horizon")Interpretasi: Tabel di atas menunjukkan akurasi model pada data uji (out-of-sample) dengan horizon peramalan h = 3, 6, dan 12 bulan terakhir.
Pada horizon h=3, MAPE sebesar 3.179%, tergolong sangat akurat. Pada horizon h=12, MAPE sebesar 3.7303%, masih tergolong sangat akurat.
n <- length(data)
train <- head(data, -3)
test_3 <- tail(data, 3)
mdl3 <- Arima(train,
order = best_model$arma[c(1,6,2)],
seasonal = list(order = best_model$arma[c(3,7,4)],
period = frequency(data)))
fc3 <- forecast(mdl3, h = 3)$mean
fitted3 <- fitted(mdl3)
df_plot <- data.frame(
Time = 1:n,
Aktual = as.numeric(data),
Fitted = c(as.numeric(fitted3), rep(NA, 3)),
Forecast = c(rep(NA, n-3), as.numeric(fc3)),
IsTest = c(rep(FALSE, n-3), rep(TRUE, 3))
)
ggplot(df_plot) +
geom_line(data = df_plot[!df_plot$IsTest, ],
aes(x=Time, y=Aktual, color="Data Asli"), linewidth=1) +
geom_line(data = df_plot[df_plot$IsTest, ],
aes(x=Time, y=Aktual, color="3 Data Testing"), linewidth=1) +
geom_line(data = df_plot[!df_plot$IsTest, ],
aes(x=Time, y=Fitted, color="Fitted"), linewidth=1) +
geom_line(data = df_plot[df_plot$IsTest, ],
aes(x=Time, y=Forecast, color="Forecast"), linewidth=1) +
scale_color_manual(values=c("Data Asli"="steelblue",
"3 Data Testing"="purple",
"Fitted"="red",
"Forecast"="green4")) +
scale_y_continuous(labels = comma) +
theme_minimal(base_size=13) +
labs(title="SARIMA: Forecast vs Aktual (H=3)",
x="Time Index", y="Jumlah Penumpang",
color=NULL) +
theme(legend.position="bottom")n <- length(data)
train <- head(data, -3)
test_3 <- tail(data, 3)
mdl3 <- Arima(train,
order = best_model$arma[c(1,6,2)],
seasonal = list(order = best_model$arma[c(3,7,4)],
period = frequency(data)))
fc3 <- forecast(mdl3, h = 3)$mean
fitted3 <- fitted(mdl3)
plot_df <- data.frame(
Time = 1:n,
Original = as.numeric(data),
Fitted = c(as.numeric(fitted3), rep(NA, 3)),
Forecast = c(rep(NA, n - 3), as.numeric(fc3)),
IsLast3 = c(rep(FALSE, n - 3), rep(TRUE, 3))
)
p_h3 <- ggplot() +
geom_line(data = plot_df[1:(n-3), ],
aes(x = Time, y = Original, color = "Data Asli"), linewidth = 1) +
geom_line(data = plot_df[plot_df$IsLast3, ],
aes(x = Time, y = Original, color = "3 Data Terakhir (Aktual)"), linewidth = 1) +
geom_line(data = plot_df[1:(n-3), ],
aes(x = Time, y = Fitted, color = "Fitted Values"), linewidth = 1) +
geom_line(data = plot_df,
aes(x = Time, y = Forecast, color = "Forecast"), linewidth = 1) +
scale_color_manual(values = c("Data Asli" = "steelblue",
"3 Data Terakhir (Aktual)" = "purple",
"Fitted Values" = "red",
"Forecast" = "green4")) +
scale_y_continuous(labels = comma) +
coord_cartesian(xlim = c(n - 14, n)) +
theme_minimal(base_size = 12) +
labs(title = "SARIMA Forecast vs Aktual (H=3) - 15 Data Terakhir",
x = "Time Index", y = "Jumlah Penumpang", color = NULL) +
theme(legend.position = "bottom")
ggplotly(p_h3)Interpretasi: Grafik di atas memfokuskan pada 15 observasi terakhir, membandingkan:
Kedekatan antara garis Forecast (hijau) dan 3 Data Terakhir (ungu) mengindikasikan akurasi peramalan jangka pendek model. Semakin berdekatan kedua garis tersebut, semakin baik kinerja model dalam memprediksi nilai aktual pada horizon dekat.
Berdasarkan analisis deret waktu terhadap data jumlah penumpang pesawat domestik di Indonesia periode 2017–2025, diperoleh beberapa kesimpulan sebagai berikut:
Karakteristik Data
Data jumlah penumpang pesawat domestik menunjukkan adanya pola tren dan musiman bulanan yang cukup jelas. Selain itu, terdapat penurunan yang sangat signifikan pada periode pandemi COVID-19 tahun 2020–2021 yang menyebabkan terjadinya gangguan struktural (structural break) pada deret waktu.
Stasioneritas Data
Hasil uji stasioneritas menggunakan Augmented Dickey-Fuller (ADF) menunjukkan bahwa data asli belum stasioner dengan nilai p-value sebesar 0,6803. Setelah dilakukan differencing non-musiman orde satu (d = 1) dan differencing musiman orde satu (D = 1), data menjadi stasioner dengan p-value sebesar 0,01, sehingga memenuhi asumsi untuk pemodelan SARIMA.
Model Terbaik
Berdasarkan proses identifikasi dan pemilihan model menggunakan kriteria Akaike Information Criterion (AIC) dan Bayesian Information Criterion (BIC), model terbaik yang diperoleh adalah SARIMA(1,1,1)(1,1,1)[12] dengan nilai AIC = 2864,06 dan BIC = 2876,83.
Diagnostik Residual
Hasil uji Ljung–Box menghasilkan p-value sebesar 0,08601. Karena nilai tersebut lebih besar dari taraf signifikansi 5%, maka gagal menolak hipotesis nol yang menyatakan bahwa residual tidak mengandung autokorelasi. Dengan demikian, residual model dapat dianggap bersifat white noise sehingga model SARIMA yang diperoleh dinilai memadai (adequate) untuk digunakan dalam peramalan.
Akurasi Peramalan
Evaluasi akurasi peramalan menunjukkan bahwa model memiliki kinerja yang sangat baik. Nilai Mean Absolute Percentage Error (MAPE) yang diperoleh sebesar 3,179% untuk horizon peramalan 3 periode (h = 3) dan 3,7303% untuk horizon peramalan 12 periode (h = 12). Nilai MAPE yang berada di bawah 10% menunjukkan bahwa hasil peramalan memiliki tingkat akurasi yang sangat baik.
Implikasi Praktis
Model SARIMA(1,1,1)(1,1,1)[12] dapat digunakan sebagai dasar dalam melakukan peramalan jumlah penumpang pesawat domestik untuk mendukung perencanaan kapasitas transportasi udara, pengambilan keputusan operasional oleh bandara dan maskapai penerbangan, serta penyusunan kebijakan terkait pengembangan sektor transportasi udara di Indonesia.
Secara keseluruhan, model SARIMA(1,1,1)(1,1,1)[12] mampu menangkap pola tren dan musiman pada data jumlah penumpang pesawat domestik Indonesia dengan baik. Hasil diagnostik residual dan evaluasi akurasi menunjukkan bahwa model telah memenuhi asumsi yang diperlukan serta menghasilkan performa peramalan yang baik, sehingga layak digunakan untuk peramalan jangka pendek hingga menengah.
File .Rmd ini bersifat reproducible: pastikan file data_pesawat.csv berada pada direktori kerja (working directory) yang sama dengan file .Rmd ini sebelum melakukan Knit. Pustaka R yang dibutuhkan: forecast, tseries, ggplot2, scales, DT, dan plotly.