library(readxl)
## Warning: package 'readxl' was built under R version 4.3.3
library(ggplot2)
library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.3.3
## Warning: package 'tibble' was built under R version 4.3.2
## Warning: package 'tidyr' was built under R version 4.3.3
## Warning: package 'readr' was built under R version 4.3.3
## Warning: package 'purrr' was built under R version 4.3.3
## Warning: package 'dplyr' was built under R version 4.3.3
## Warning: package 'stringr' was built under R version 4.3.3
## Warning: package 'forcats' was built under R version 4.3.3
## Warning: package 'lubridate' was built under R version 4.3.3
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ lubridate 1.9.4 ✔ tibble 3.2.1
## ✔ purrr 1.0.2 ✔ tidyr 1.3.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(dplyr)
library(forecast)
## Warning: package 'forecast' was built under R version 4.3.3
## Registered S3 method overwritten by 'quantmod':
## method from
## as.zoo.data.frame zoo
library(tseries)
## Warning: package 'tseries' was built under R version 4.3.3
library(lmtest)
## Warning: package 'lmtest' was built under R version 4.3.3
## Loading required package: zoo
## Warning: package 'zoo' was built under R version 4.3.3
##
## Attaching package: 'zoo'
##
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
library(nlme)
## Warning: package 'nlme' was built under R version 4.3.3
##
## Attaching package: 'nlme'
##
## The following object is masked from 'package:forecast':
##
## getResponse
##
## The following object is masked from 'package:dplyr':
##
## collapse
data <- read_excel("C:/Users/Lenovo/Documents/Sinar Matahari per Bulan di Kota Bandung (Persen).xlsx")
View(data)
summary(data)
## Bulan Tahun 2019 tahun 2020 Tahun 2021
## Length:12 Min. :48.00 Min. :33.66 Min. :38.50
## Class :character 1st Qu.:58.75 1st Qu.:49.92 1st Qu.:49.30
## Mode :character Median :68.00 Median :58.14 Median :54.95
## Mean :68.92 Mean :60.81 Mean :55.97
## 3rd Qu.:83.25 3rd Qu.:77.27 3rd Qu.:63.40
## Max. :86.00 Max. :81.50 Max. :77.90
## Tahun 2022 tahun 2023 Tahun 2024
## Min. :38.00 Min. :34.00 Min. :39.00
## 1st Qu.:45.58 1st Qu.:48.50 1st Qu.:48.50
## Median :54.35 Median :51.50 Median :63.00
## Mean :53.48 Mean :58.92 Mean :60.58
## 3rd Qu.:61.15 3rd Qu.:74.75 3rd Qu.:71.50
## Max. :67.70 Max. :90.00 Max. :78.00
sum(duplicated(data))
## [1] 0
colSums(is.na(data))
## Bulan Tahun 2019 tahun 2020 Tahun 2021 Tahun 2022 tahun 2023 Tahun 2024
## 0 0 0 0 0 0 0
data_long <- data %>%
pivot_longer(
cols = -Bulan,
names_to = "Tahun",
values_to = "Produksi"
) %>%
mutate(
# Ambil angka tahun dari nama kolom (misal "Tahun 2019" → 2019)
Tahun = str_extract(Tahun, "\\d+") |> as.numeric(),
# Ubah nama bulan ke angka (1 = Januari, dst)
Bulan = match(Bulan, month.name)
) %>%
arrange(Tahun, Bulan)
#Buat boxplot per tahun
ggplot(data_long, aes(x = as.factor(Tahun), y = Produksi, group = Tahun)) +
geom_boxplot(fill = "skyblue", color = "darkblue") +
labs(
title = "Boxplot Produksi per Tahun",
x = "Tahun",
y = "Produksi"
) +
theme_minimal()

#Boxplot per bulan
ggplot(data_long, aes(x = factor(Bulan, labels = month.name), y = Produksi)) +
geom_boxplot(fill = "lightgreen", color = "darkgreen") +
labs(
title = "Boxplot Produksi per Bulan (Gabungan Semua Tahun)",
x = "Bulan",
y = "Produksi"
) +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

#Boxplot keseluruhan
ggplot(data_long, aes(y = Produksi)) +
geom_boxplot(fill = "orange", color = "darkred") +
labs(
title = "Boxplot Produksi Keseluruhan (2019–2024)",
x = "",
y = "Produksi"
) +
theme_minimal()

# objek time series (2019 Jan - 2024 Des, frekuensi bulanan = 12)
ts_data <- ts(data_long$Produksi, start = c(2019, 1), frequency = 12)
plot(decompose(ts_data))

plot(ts_data, main = "plot awal")

# Uji Augmented Dickey-Fuller (ADF)
train <- window(ts_data, end = c(2023, 12))
test <- window(ts_data, start = c(2024, 1))
adf_test <- adf.test(train)
## Warning in adf.test(train): p-value smaller than printed p-value
adf_test
##
## Augmented Dickey-Fuller Test
##
## data: train
## Dickey-Fuller = -5.3257, Lag order = 3, p-value = 0.01
## alternative hypothesis: stationary
diff_train <- diff(train)
# ACF dan PACF
par(mfrow = c(1, 2))
acf(diff_train, main = "ACF Plot")
pacf(diff_train, main = "PACF Plot")

#HOLT winter (data trend dan musiman)
hw_add <- hw(train, seasonal = "additive", h = length(test))
hw_mul <- hw(train, seasonal = "multiplicative", h = length(test))
accuracy(hw_add, test)
## ME RMSE MAE MPE MAPE MASE
## Training set -0.5432959 9.703822 7.575665 -3.869459 13.82597 0.7090553
## Test set 10.4339870 13.682548 11.144196 15.359650 17.18070 1.0430571
## ACF1 Theil's U
## Training set 0.3519338 NA
## Test set -0.2713243 1.108512
accuracy(hw_mul, test)
## ME RMSE MAE MPE MAPE MASE
## Training set 0.2400055 9.637644 7.457130 -2.231937 13.34665 0.6979609
## Test set 7.3236643 11.453074 9.286543 9.739277 14.63761 0.8691874
## ACF1 Theil's U
## Training set 0.293569 NA
## Test set -0.264863 0.9176958
#holt winter multiplicative karena RMSE dan MAPE lebih kecil dibandingkan dengan additive
hw_model_mult <- HoltWinters(train, seasonal = "multiplicative")
hw_model_mult
## Holt-Winters exponential smoothing with trend and multiplicative seasonal component.
##
## Call:
## HoltWinters(x = train, seasonal = "multiplicative")
##
## Smoothing parameters:
## alpha: 0.00823339
## beta : 1
## gamma: 0.3385724
##
## Coefficients:
## [,1]
## a 53.4102778
## b 0.4554378
## s1 0.9476000
## s2 0.7856314
## s3 0.8845751
## s4 0.9697713
## s5 0.9938133
## s6 0.9439605
## s7 1.3092273
## s8 1.4054740
## s9 1.3126250
## s10 1.1345236
## s11 0.9220484
## s12 0.8523128
# Plot fitting model terhadap data training
plot(hw_model_mult, main = "Fitting Holt-Winters Multiplicative") #garis pink hasil peramalan

#melaukan peramalan untuk data testing
forecast_hw_mult <- forecast(hw_model_mult, h = length(test))
# Plot hasil forecast dan bandingkan dengan data aktual
autoplot(forecast_hw_mult) +
autolayer(test, series = "Actual", color = "green") +
ggtitle("Peramalan Holt–Winters Multiplicative") +
ylab("Produksi") +
xlab("Tahun") +
theme_minimal()

# Hitung RMSE
rmse_mult <- sqrt(mean((test - forecast_hw_mult$mean)^2))
# Hitung MAPE
mape_mult <- mean(abs((test - forecast_hw_mult$mean) / test)) * 100
# Tampilkan hasil evaluasi
cat("Evaluasi Model Holt–Winters (Multiplicative):\n")
## Evaluasi Model Holt–Winters (Multiplicative):
cat("RMSE =", round(rmse_mult, 2), "\n")
## RMSE = 10.5
cat("MAPE =", round(mape_mult, 2), "%\n")
## MAPE = 16.22 %
#menggunakan regresi time series karena data trend dan musiman
data_long$t <- 1:nrow(data_long) # variabel trend
data_long$bulan_factor <- as.factor(data_long$Bulan) # variabel musiman (bulan)
# Model regresi dengan trend dan musiman
model_ts <- lm(Produksi ~ t + bulan_factor, data = data_long)
summary(model_ts)
##
## Call:
## lm(formula = Produksi ~ t + bulan_factor, data = data_long)
##
## Residuals:
## Min 1Q Median 3Q Max
## -25.5906 -7.5412 0.4657 5.7436 19.7132
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 55.27885 4.70318 11.754 < 2e-16 ***
## t -0.11867 0.06071 -1.955 0.055367 .
## bulan_factor2 -1.73799 6.09581 -0.285 0.776556
## bulan_factor3 -1.16265 6.09671 -0.191 0.849414
## bulan_factor4 5.42935 6.09823 0.890 0.376912
## bulan_factor5 10.53469 6.10034 1.727 0.089418 .
## bulan_factor6 10.72003 6.10306 1.757 0.084192 .
## bulan_factor7 25.20870 6.10638 4.128 0.000117 ***
## bulan_factor8 25.87904 6.11030 4.235 8.11e-05 ***
## bulan_factor9 22.14938 6.11483 3.622 0.000609 ***
## bulan_factor10 13.25139 6.11995 2.165 0.034422 *
## bulan_factor11 -0.29994 6.12567 -0.049 0.961113
## bulan_factor12 -3.97793 6.13198 -0.649 0.519037
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 10.56 on 59 degrees of freedom
## Multiple R-squared: 0.5534, Adjusted R-squared: 0.4626
## F-statistic: 6.093 on 12 and 59 DF, p-value: 8.405e-07
res <- resid(model_ts)
# Plot residual untuk melihat pola
plot(res, type = "l", col = "darkblue",
main = "Residual Regresi Time Series",
ylab = "Residuals", xlab = "Waktu")

# Uji autokorelasi residual (Durbin-Watson)
dwtest(model_ts)
##
## Durbin-Watson test
##
## data: model_ts
## DW = 1.3218, p-value = 0.003005
## alternative hypothesis: true autocorrelation is greater than 0
# Plot ACF residual untuk cek pola autokorelasi
acf(res, main = "ACF Residual Regresi Time Series")

#karena terdapat autokorelasi maka harus di atasi
# Kita fit model gls dengan korelasi AR(1) terhadap urutan waktu 't'
model_gls_ar1 <- gls(Produksi ~ t, correlation = corAR1(form = ~ t), data = data_long)
summary(model_gls_ar1)
## Generalized least squares fit by REML
## Model: Produksi ~ t
## Data: data_long
## AIC BIC logLik
## 563.1964 572.1904 -277.5982
##
## Correlation Structure: AR(1)
## Formula: ~t
## Parameter estimate(s):
## Phi
## 0.6176659
##
## Coefficients:
## Value Std.Error t-value p-value
## (Intercept) 63.55220 6.938891 9.158841 0.0000
## t -0.11544 0.163382 -0.706567 0.4822
##
## Correlation:
## (Intr)
## t -0.859
##
## Standardized residuals:
## Min Q1 Med Q3 Max
## -1.8901968 -0.7164912 -0.1072045 0.8726974 2.2001326
##
## Residual standard error: 14.95931
## Degrees of freedom: 72 total; 70 residual
# Residual GLS
res_gls <- residuals(model_gls_ar1, type = "normalized")
# Plot & ACF residual GLS
plot(res_gls, type = "l", col = "darkgreen",
main = "Residual GLS AR(1)",
ylab = "Residuals", xlab = "Waktu (t)")

acf(res_gls, main = "ACF Residual GLS AR(1)")

# Ljung-Box untuk residual GLS
Box.test(res_gls, lag = 12, type = "Ljung-Box", fitdf = length(coef(model_gls_ar1)))
##
## Box-Ljung test
##
## data: res_gls
## X-squared = 24.939, df = 10, p-value = 0.005463
# Untuk GLS: fitted values (predict)
data_long$Fitted_GLS <- fitted(model_gls_ar1)
# Hitung RMSE dan MAPE (hanya pada baris yg tidak NA pada fitted masing2)
rmse <- function(obs, pred) sqrt(mean((obs - pred)^2, na.rm = TRUE))
mape <- function(obs, pred) mean(abs((obs - pred) / obs) * 100, na.rm = TRUE)
cat("Evaluasi Model (2019-2024):\n")
## Evaluasi Model (2019-2024):
cat("GLS - RMSE =", round(rmse(data_long$Produksi, data_long$Fitted_GLS), 3),
" | MAPE =", round(mape(data_long$Produksi, data_long$Fitted_GLS), 3), "%\n")
## GLS - RMSE = 14.167 | MAPE = 21.09 %
# Visualisasi: Actual vs Fitted (GLS)
plot_df <- data_long %>%
select(t, Produksi, Fitted_GLS) %>%
pivot_longer(cols = starts_with("Fitted"), names_to = "Model", values_to = "Fitted")
ggplot(plot_df, aes(x = t)) +
geom_line(aes(y = Produksi, color = "Aktual"), size = 1) +
geom_line(aes(y = Fitted, color = Model), size = 0.9, linetype = "dashed") +
scale_color_manual(values = c("Aktual" = "yellow",
"Fitted_GLS" = "darkgreen")) +
labs(title = "Actual vs Fitted (OLS, GLS-AR1)",
x = "Waktu (t)", y = "Produksi") +
theme_minimal()
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

# MODEL ARIMA & SARIMA
# Buat data training dan testing kembali
train <- window(ts_data, end = c(2023, 12))
test <- window(ts_data, start = c(2024, 1))
# Plot awal untuk cek pola musiman
plot(train, main = "Data Training (2019–2023)", ylab = "Produksi", xlab = "Tahun")

# Differencing musiman (lag = 12)
diff_seasonal <- diff(train, lag = 12)
# Plot hasil differencing musiman
plot(diff_seasonal, main = "Differencing Musiman (lag = 12)",
ylab = "Differenced Produksi", xlab = "Tahun")

# Uji stasioneritas pada data yang sudah di-differencing
adf.test(na.omit(diff_seasonal))
## Warning in adf.test(na.omit(diff_seasonal)): p-value smaller than printed
## p-value
##
## Augmented Dickey-Fuller Test
##
## data: na.omit(diff_seasonal)
## Dickey-Fuller = -4.6305, Lag order = 3, p-value = 0.01
## alternative hypothesis: stationary
# ACF dan PACF untuk data yang sudah differencing
par(mfrow = c(1, 2))
acf(na.omit(diff_seasonal), main = "ACF Setelah Differencing (12)")
pacf(na.omit(diff_seasonal), main = "PACF Setelah Differencing (12)")

par(mfrow = c(1, 1))
# Tentukan model ARIMA
model_auto <- auto.arima(train, D = 1, seasonal = TRUE,
stepwise = FALSE, approximation = FALSE,
trace = TRUE)
##
## ARIMA(0,1,0)(0,1,0)[12] : 399.4989
## ARIMA(0,1,0)(0,1,1)[12] : 389.3651
## ARIMA(0,1,0)(1,1,0)[12] : 384.0676
## ARIMA(0,1,0)(1,1,1)[12] : 384.6412
## ARIMA(0,1,1)(0,1,0)[12] : 383.5969
## ARIMA(0,1,1)(0,1,1)[12] : 381.4137
## ARIMA(0,1,1)(1,1,0)[12] : 381.3311
## ARIMA(0,1,1)(1,1,1)[12] : 383.4443
## ARIMA(0,1,2)(0,1,0)[12] : 385.2921
## ARIMA(0,1,2)(0,1,1)[12] : 381.036
## ARIMA(0,1,2)(1,1,0)[12] : 379.9841
## ARIMA(0,1,2)(1,1,1)[12] : 382.2802
## ARIMA(0,1,3)(0,1,0)[12] : 385.0766
## ARIMA(0,1,3)(0,1,1)[12] : 381.6265
## ARIMA(0,1,3)(1,1,0)[12] : 380.669
## ARIMA(0,1,3)(1,1,1)[12] : 383.0933
## ARIMA(0,1,4)(0,1,0)[12] : 384.616
## ARIMA(0,1,4)(0,1,1)[12] : 382.1461
## ARIMA(0,1,4)(1,1,0)[12] : 380.905
## ARIMA(0,1,5)(0,1,0)[12] : 384.3008
## ARIMA(1,1,0)(0,1,0)[12] : 389.5613
## ARIMA(1,1,0)(0,1,1)[12] : 384.7863
## ARIMA(1,1,0)(1,1,0)[12] : 382.8023
## ARIMA(1,1,0)(1,1,1)[12] : 384.3958
## ARIMA(1,1,1)(0,1,0)[12] : 385.0839
## ARIMA(1,1,1)(0,1,1)[12] : 380.2037
## ARIMA(1,1,1)(1,1,0)[12] : 378.5873
## ARIMA(1,1,1)(1,1,1)[12] : 380.6633
## ARIMA(1,1,2)(0,1,0)[12] : 386.3088
## ARIMA(1,1,2)(0,1,1)[12] : 383.7197
## ARIMA(1,1,2)(1,1,0)[12] : 381.0827
## ARIMA(1,1,2)(1,1,1)[12] : 383.2974
## ARIMA(1,1,3)(0,1,0)[12] : 388.8198
## ARIMA(1,1,3)(0,1,1)[12] : 385.936
## ARIMA(1,1,3)(1,1,0)[12] : 382.6101
## ARIMA(1,1,4)(0,1,0)[12] : 385.3885
## ARIMA(2,1,0)(0,1,0)[12] : 387.0342
## ARIMA(2,1,0)(0,1,1)[12] : 385.5068
## ARIMA(2,1,0)(1,1,0)[12] : 384.4291
## ARIMA(2,1,0)(1,1,1)[12] : 386.3231
## ARIMA(2,1,1)(0,1,0)[12] : 386.6892
## ARIMA(2,1,1)(0,1,1)[12] : 382.4589
## ARIMA(2,1,1)(1,1,0)[12] : 381.0724
## ARIMA(2,1,1)(1,1,1)[12] : 383.2959
## ARIMA(2,1,2)(0,1,0)[12] : 388.8195
## ARIMA(2,1,2)(0,1,1)[12] : 385.0786
## ARIMA(2,1,2)(1,1,0)[12] : 383.6928
## ARIMA(2,1,3)(0,1,0)[12] : Inf
## ARIMA(3,1,0)(0,1,0)[12] : 387.2514
## ARIMA(3,1,0)(0,1,1)[12] : 387.4847
## ARIMA(3,1,0)(1,1,0)[12] : 386.8387
## ARIMA(3,1,0)(1,1,1)[12] : 388.9414
## ARIMA(3,1,1)(0,1,0)[12] : 386.1482
## ARIMA(3,1,1)(0,1,1)[12] : 387.441
## ARIMA(3,1,1)(1,1,0)[12] : 382.7638
## ARIMA(3,1,2)(0,1,0)[12] : 386.3502
## ARIMA(4,1,0)(0,1,0)[12] : 378.4864
## ARIMA(4,1,0)(0,1,1)[12] : 379.7115
## ARIMA(4,1,0)(1,1,0)[12] : 379.7309
## ARIMA(4,1,1)(0,1,0)[12] : 378.9049
## ARIMA(5,1,0)(0,1,0)[12] : 380.4918
##
##
##
## Best model: ARIMA(4,1,0)(0,1,0)[12]
summary(model_auto)
## Series: train
## ARIMA(4,1,0)(0,1,0)[12]
##
## Coefficients:
## ar1 ar2 ar3 ar4
## -0.4469 -0.2491 -0.0494 -0.5044
## s.e. 0.1287 0.1615 0.1574 0.1363
##
## sigma^2 = 151.6: log likelihood = -183.51
## AIC=377.02 AICc=378.49 BIC=386.27
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set 1.130434 10.4231 7.251782 0.7133535 12.67464 0.678741 -0.07150646
# Diagnostik residual
checkresiduals(model_auto)

##
## Ljung-Box test
##
## data: Residuals from ARIMA(4,1,0)(0,1,0)[12]
## Q* = 14.038, df = 8, p-value = 0.08079
##
## Model df: 4. Total lags used: 12
# Forecast ke periode testing (2024)
forecast_arima <- forecast(model_auto, h = length(test))
# Evaluasi performa model
rmse_arima <- sqrt(mean((forecast_arima$mean - test)^2))
mape_arima <- mean(abs((forecast_arima$mean - test) / test)) * 100
cat("\nEvaluasi Model ARIMA:\n")
##
## Evaluasi Model ARIMA:
cat("RMSE =", round(rmse_arima, 3), "\n")
## RMSE = 20.125
cat("MAPE =", round(mape_arima, 3), "%\n")
## MAPE = 32.254 %
# Visualisasi hasil forecast ARIMA
autoplot(forecast_arima) +
autolayer(test, series = "Data Aktual", color = "green") +
ggtitle("Peramalan Menggunakan ARIMA (dengan differencing musiman 12)") +
ylab("Produksi") +
xlab("Tahun") +
theme_minimal()

# SARIMA (Seasonal ARIMA)
# Misalnya kita tentukan SARIMA(1,1,1)(1,1,1)[12] sebagai contoh manual
model_sarima <- Arima(train,
order = c(1,1,1), # komponen ARIMA non-musiman (p,d,q)
seasonal = list(order = c(1,1,1), period = 12)) # komponen musiman (P,D,Q)[s]
summary(model_sarima)
## Series: train
## ARIMA(1,1,1)(1,1,1)[12]
##
## Coefficients:
## ar1 ma1 sar1 sma1
## 0.4870 -0.9322 -0.7514 0.3092
## s.e. 0.1679 0.0877 0.2802 0.4277
##
## sigma^2 = 144.6: log likelihood = -184.6
## AIC=379.2 AICc=380.66 BIC=388.45
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set 1.597271 10.17823 7.190001 1.151485 12.74855 0.6729585 -0.03723596
checkresiduals(model_sarima)

##
## Ljung-Box test
##
## data: Residuals from ARIMA(1,1,1)(1,1,1)[12]
## Q* = 17.826, df = 8, p-value = 0.02257
##
## Model df: 4. Total lags used: 12
# Forecast SARIMA
forecast_sarima <- forecast(model_sarima, h = length(test))
# Evaluasi SARIMA
rmse_sarima <- sqrt(mean((forecast_sarima$mean - test)^2))
mape_sarima <- mean(abs((forecast_sarima$mean - test) / test)) * 100
cat("\nEvaluasi Model SARIMA:\n")
##
## Evaluasi Model SARIMA:
cat("RMSE =", round(rmse_sarima, 3), "\n")
## RMSE = 13.965
cat("MAPE =", round(mape_sarima, 3), "%\n")
## MAPE = 20.825 %
# Plot hasil SARIMA
autoplot(forecast_sarima) +
autolayer(test, series = "Data Aktual", color = "green") +
ggtitle("Peramalan Menggunakan SARIMA(1,1,1)(1,1,1)[12]") +
ylab("Produksi") +
xlab("Tahun") +
theme_minimal()

# Bandingkan performa model
cat("\nPerbandingan Model:\n")
##
## Perbandingan Model:
cat("Holt–Winters (Multiplicative): RMSE =", round(rmse_mult, 3),
"| MAPE =", round(mape_mult, 3), "%\n")
## Holt–Winters (Multiplicative): RMSE = 10.502 | MAPE = 16.22 %
cat("ARIMA :", round(rmse_arima, 3),
"| MAPE =", round(mape_arima, 3), "%\n")
## ARIMA : 20.125 | MAPE = 32.254 %
cat("SARIMA :", round(rmse_sarima, 3),
"| MAPE =", round(mape_sarima, 3), "%\n")
## SARIMA : 13.965 | MAPE = 20.825 %