# ============================================================================
# ANALISIS DAN PROYEKSI EMISI CO2 INDONESIA (1970–2024)
# Metode: Regresi Linear, ARIMA, ARCH/GARCH, dan Forecasting
# Sumber Data: Worldometer – Indonesia CO2 Emissions
# Penulis: [Nama Penulis]
# ============================================================================
# Memuat semua library
library(readxl)
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.5.2 ✔ tibble 3.2.1
## ✔ lubridate 1.9.3 ✔ tidyr 1.3.1
## ✔ purrr 1.0.2
## ── 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(forecast)
## Registered S3 method overwritten by 'quantmod':
## method from
## as.zoo.data.frame zoo
library(tseries)
library(lmtest)
## Loading required package: zoo
##
## Attaching package: 'zoo'
##
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
library(rugarch)
## Loading required package: parallel
##
## Attaching package: 'rugarch'
##
## The following object is masked from 'package:purrr':
##
## reduce
##
## The following object is masked from 'package:stats':
##
## sigma
library(FinTS)
##
## Attaching package: 'FinTS'
##
## The following object is masked from 'package:forecast':
##
## Acf
library(scales)
##
## Attaching package: 'scales'
##
## The following object is masked from 'package:purrr':
##
## discard
##
## The following object is masked from 'package:readr':
##
## col_factor
library(patchwork)
# ==========================
# 1. IMPORT & PRAPEMROSESAN DATA
# ==========================
# Membaca data dari file Excel
raw_data <- read_excel("d:/Training/C02_Emisi.xlsx")
# Menampilkan struktur awal data
cat("=== STRUKTUR DATA ===\n")
## === STRUKTUR DATA ===
str(raw_data)
## tibble [55 × 5] (S3: tbl_df/tbl/data.frame)
## $ Year : num [1:55] 2024 2023 2022 2021 2020 ...
## $ Fossil CO2 Emissions (tons) : num [1:55] 8.12e+08 7.73e+08 7.23e+08 6.23e+08 5.96e+08 ...
## $ YoY Change (%) : num [1:55] 5.13 6.9 16.06 4.43 -6.48 ...
## $ CO2 per Capita (tons/person): num [1:55] 2.88 2.76 2.61 2.27 2.19 2.37 2.24 2.03 1.94 1.98 ...
## $ Global Share (%) : num [1:55] 2.05 1.98 1.87 1.63 1.65 1.68 1.57 1.45 1.39 1.41 ...
cat("\n=== RINGKASAN STATISTIK DESKRIPTIF ===\n")
##
## === RINGKASAN STATISTIK DESKRIPTIF ===
summary(raw_data)
## Year Fossil CO2 Emissions (tons) YoY Change (%)
## Min. :1970 Min. : 31123671 Min. :-6.480
## 1st Qu.:1984 1st Qu.: 97023342 1st Qu.: 1.722
## Median :1997 Median :275520703 Median : 5.695
## Mean :1997 Mean :295431061 Mean : 6.434
## 3rd Qu.:2010 3rd Qu.:459323580 3rd Qu.: 8.773
## Max. :2024 Max. :812204159 Max. :36.690
## NA's :1
## CO2 per Capita (tons/person) Global Share (%)
## Min. :0.270 Min. :0.2000
## 1st Qu.:0.630 1st Qu.:0.4950
## Median :1.350 Median :1.1200
## Mean :1.295 Mean :0.9767
## 3rd Qu.:1.855 3rd Qu.:1.3100
## Max. :2.880 Max. :2.0500
##
# Pra-pemrosesan: rename kolom, urutkan berdasarkan tahun (ascending)
df <- raw_data %>%
rename(
year = `Year`,
co2_tons = `Fossil CO2 Emissions (tons)`,
yoy_change = `YoY Change (%)`,
per_capita = `CO2 per Capita (tons/person)`,
global_pct = `Global Share (%)`
) %>%
arrange(year)
# Konversi ke satuan Juta Ton (Mt) untuk keterbacaan
df <- df %>%
mutate(co2_mt = co2_tons / 1e6)
cat("\n=== DATA SETELAH PRAPEMROSESAN (5 baris pertama) ===\n")
##
## === DATA SETELAH PRAPEMROSESAN (5 baris pertama) ===
print(head(df, 10))
## # A tibble: 10 × 6
## year co2_tons yoy_change per_capita global_pct co2_mt
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1970 31123671 NA 0.27 0.2 31.1
## 2 1971 31496130 1.2 0.27 0.2 31.5
## 3 1972 37263373 18.3 0.31 0.23 37.3
## 4 1973 42033316 12.8 0.34 0.24 42.0
## 5 1974 46956608 11.7 0.37 0.27 47.0
## 6 1975 48794745 3.91 0.37 0.28 48.8
## 7 1976 52527133 7.65 0.39 0.29 52.5
## 8 1977 71798713 36.7 0.52 0.38 71.8
## 9 1978 84466597 17.6 0.6 0.43 84.5
## 10 1979 90919613 7.64 0.63 0.45 90.9
# Membuat objek time series (ts)
# Frekuensi = 1 karena data tahunan, dimulai tahun 1970
co2_ts <- ts(df$co2_mt, start = 1970, frequency = 1)
cat("\n=== OBJEK TIME SERIES ===\n")
##
## === OBJEK TIME SERIES ===
print(co2_ts)
## Time Series:
## Start = 1970
## End = 2024
## Frequency = 1
## [1] 31.12367 31.49613 37.26337 42.03332 46.95661 48.79474 52.52713
## [8] 71.79871 84.46660 90.91961 90.59942 95.65866 96.40196 95.42208
## [15] 97.64472 106.03832 117.10361 120.21502 128.66807 134.48484 161.76870
## [22] 174.65927 182.55245 199.85071 212.74749 239.09898 252.00756 275.52070
## [29] 278.24342 295.25001 299.07024 319.56204 324.93886 353.62302 360.15132
## [36] 362.59705 383.41937 401.79343 397.25537 411.34908 443.68204 499.93621
## [43] 504.25725 474.96512 505.07617 512.39726 507.09651 535.74741 596.46923
## [50] 637.56916 596.28393 622.68684 722.69958 772.56179 812.20416
# ============================================================================
# INTERPRETASI: Data emisi CO2 Indonesia mencakup 55 observasi tahunan
# (1970–2024). Emisi meningkat secara signifikan dari ~31 Mt (1970)
# menjadi ~812 Mt (2024), menunjukkan tren naik (upward trend) yang kuat.
# ============================================================================
# ==========================
# 2. REGRESI LINEAR KLASIK (BASELINE)
# ==========================
cat("\n\n", paste(rep("=", 60), collapse = ""), "\n")
##
##
## ============================================================
cat("BAGIAN 2: REGRESI LINEAR KLASIK\n")
## BAGIAN 2: REGRESI LINEAR KLASIK
cat(paste(rep("=", 60), collapse = ""), "\n\n")
## ============================================================
# Model regresi linear: CO2 (Mt) sebagai fungsi dari tren waktu (Year)
# Y = β0 + β1*Year + ε
model_lm <- lm(co2_mt ~ year, data = df)
cat("=== RINGKASAN MODEL REGRESI LINEAR ===\n")
## === RINGKASAN MODEL REGRESI LINEAR ===
summary(model_lm)
##
## Call:
## lm(formula = co2_mt ~ year, data = df)
##
## Residuals:
## Min 1Q Median 3Q Max
## -56.78 -35.26 -20.09 28.73 165.23
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -2.571e+04 8.417e+02 -30.54 <2e-16 ***
## year 1.302e+01 4.215e-01 30.89 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 49.62 on 53 degrees of freedom
## Multiple R-squared: 0.9474, Adjusted R-squared: 0.9464
## F-statistic: 954.2 on 1 and 53 DF, p-value: < 2.2e-16
# UJI ASUMSI KLASIK REGRESI
# 2a. Uji Normalitas Residual (Shapiro-Wilk)
cat("\n--- Uji Normalitas Residual (Shapiro-Wilk) ---\n")
##
## --- Uji Normalitas Residual (Shapiro-Wilk) ---
shapiro_test <- shapiro.test(residuals(model_lm))
print(shapiro_test)
##
## Shapiro-Wilk normality test
##
## data: residuals(model_lm)
## W = 0.84656, p-value = 5.41e-06
cat("Interpretasi: ")
## Interpretasi:
if (shapiro_test$p.value > 0.05) {
cat("p-value > 0.05 → Residual berdistribusi normal (H0 tidak ditolak).\n")
} else {
cat("p-value <= 0.05 → Residual TIDAK berdistribusi normal (H0 ditolak).\n")
}
## p-value <= 0.05 → Residual TIDAK berdistribusi normal (H0 ditolak).
# 2b. Uji Heteroskedastisitas (Breusch-Pagan)
cat("\n--- Uji Heteroskedastisitas (Breusch-Pagan) ---\n")
##
## --- Uji Heteroskedastisitas (Breusch-Pagan) ---
bp_test <- bptest(model_lm)
print(bp_test)
##
## studentized Breusch-Pagan test
##
## data: model_lm
## BP = 2.5139, df = 1, p-value = 0.1128
cat("Interpretasi: ")
## Interpretasi:
if (bp_test$p.value > 0.05) {
cat("p-value > 0.05 → Tidak ada heteroskedastisitas (homokedastis).\n")
} else {
cat("p-value <= 0.05 → Terdapat heteroskedastisitas → asumsi OLS dilanggar.\n")
}
## p-value > 0.05 → Tidak ada heteroskedastisitas (homokedastis).
# 2c. Uji Autokorelasi (Durbin-Watson)
cat("\n--- Uji Autokorelasi (Durbin-Watson) ---\n")
##
## --- Uji Autokorelasi (Durbin-Watson) ---
dw_test <- dwtest(model_lm)
print(dw_test)
##
## Durbin-Watson test
##
## data: model_lm
## DW = 0.18417, p-value < 2.2e-16
## alternative hypothesis: true autocorrelation is greater than 0
cat("Interpretasi: ")
## Interpretasi:
if (dw_test$p.value > 0.05) {
cat("p-value > 0.05 → Tidak ada autokorelasi pada residual.\n")
} else {
cat("p-value <= 0.05 → Terdapat autokorelasi → OLS tidak efisien.\n")
}
## p-value <= 0.05 → Terdapat autokorelasi → OLS tidak efisien.
# ============================================================================
# INTERPRETASI REGRESI:
# Koefisien β1 (slope) menunjukkan peningkatan rata-rata emisi CO2 per tahun.
# Nilai R² menunjukkan proporsi variasi emisi yang dijelaskan oleh tren waktu.
# Pelanggaran asumsi klasik (terutama autokorelasi) menegaskan perlunya
# model time series (ARIMA) yang lebih tepat untuk data runtun waktu.
# ============================================================================
# ==========================
# 3. MODEL TIME SERIES — ARIMA
# ==========================
cat("\n\n", paste(rep("=", 60), collapse = ""), "\n")
##
##
## ============================================================
cat("BAGIAN 3: PEMODELAN ARIMA\n")
## BAGIAN 3: PEMODELAN ARIMA
cat(paste(rep("=", 60), collapse = ""), "\n\n")
## ============================================================
# 3a. UJI STASIONERITAS — Augmented Dickey-Fuller (ADF)
cat("--- Uji ADF pada Data Level (Original) ---\n")
## --- Uji ADF pada Data Level (Original) ---
adf_level <- adf.test(co2_ts, alternative = "stationary")
## Warning in adf.test(co2_ts, alternative = "stationary"): p-value greater than
## printed p-value
print(adf_level)
##
## Augmented Dickey-Fuller Test
##
## data: co2_ts
## Dickey-Fuller = 1.2364, Lag order = 3, p-value = 0.99
## alternative hypothesis: stationary
cat("Interpretasi: ")
## Interpretasi:
if (adf_level$p.value > 0.05) {
cat("p-value > 0.05 → Data TIDAK stasioner pada level.\n")
cat(" → Diperlukan differencing untuk mencapai stasioneritas.\n")
} else {
cat("p-value <= 0.05 → Data sudah stasioner pada level.\n")
}
## p-value > 0.05 → Data TIDAK stasioner pada level.
## → Diperlukan differencing untuk mencapai stasioneritas.
# Differencing orde pertama (d = 1)
co2_diff1 <- diff(co2_ts, differences = 1)
cat("\n--- Uji ADF pada Data Setelah Differencing (d=1) ---\n")
##
## --- Uji ADF pada Data Setelah Differencing (d=1) ---
adf_diff1 <- adf.test(co2_diff1, alternative = "stationary")
print(adf_diff1)
##
## Augmented Dickey-Fuller Test
##
## data: co2_diff1
## Dickey-Fuller = -2.1618, Lag order = 3, p-value = 0.5094
## alternative hypothesis: stationary
cat("Interpretasi: ")
## Interpretasi:
if (adf_diff1$p.value > 0.05) {
cat("p-value > 0.05 → Masih BELUM stasioner setelah differencing 1x.\n")
cat(" → Coba differencing orde 2 (d=2).\n")
co2_diff2 <- diff(co2_ts, differences = 2)
cat("\n--- Uji ADF pada Data Setelah Differencing (d=2) ---\n")
adf_diff2 <- adf.test(co2_diff2, alternative = "stationary")
print(adf_diff2)
} else {
cat("p-value <= 0.05 → Data STASIONER setelah differencing 1x (d=1).\n")
}
## p-value > 0.05 → Masih BELUM stasioner setelah differencing 1x.
## → Coba differencing orde 2 (d=2).
##
## --- Uji ADF pada Data Setelah Differencing (d=2) ---
## Warning in adf.test(co2_diff2, alternative = "stationary"): p-value smaller
## than printed p-value
##
## Augmented Dickey-Fuller Test
##
## data: co2_diff2
## Dickey-Fuller = -4.9452, Lag order = 3, p-value = 0.01
## alternative hypothesis: stationary
# 3b. PLOT ACF DAN PACF
cat("\n--- Membuat Plot ACF dan PACF ---\n")
##
## --- Membuat Plot ACF dan PACF ---
# Plot ACF & PACF dari data yang sudah di-differencing
# Digunakan untuk identifikasi order p (AR) dan q (MA)
par(mfrow = c(1, 2))
acf(co2_diff1, main = "ACF — Emisi CO2 (Differenced, d=1)", lag.max = 20)
pacf(co2_diff1, main = "PACF — Emisi CO2 (Differenced, d=1)", lag.max = 20)

par(mfrow = c(1, 1))
# ============================================================================
# INTERPRETASI ACF/PACF:
# - ACF: Jika korelasi menurun secara gradual → komponen AR dominan.
# Jika terpotong tajam setelah lag-q → komponen MA order q.
# - PACF: Jika terpotong tajam setelah lag-p → komponen AR order p.
# Pola ini menjadi dasar pemilihan order (p, d, q) secara manual.
# ============================================================================
# 3c. ESTIMASI MODEL ARIMA
# Metode 1: auto.arima (seleksi otomatis berdasarkan AICc)
cat("\n--- Model ARIMA Otomatis (auto.arima) ---\n")
##
## --- Model ARIMA Otomatis (auto.arima) ---
model_auto <- auto.arima(
co2_ts,
seasonal = FALSE, # data tahunan, tidak ada pola musiman
stepwise = FALSE, # pencarian menyeluruh (exhaustive search)
approximation = FALSE, # tanpa aproksimasi untuk akurasi
trace = TRUE # tampilkan semua model yang dievaluasi
)
##
## ARIMA(0,2,0) : 498.6663
## ARIMA(0,2,1) : 478.1594
## ARIMA(0,2,2) : 476.1763
## ARIMA(0,2,3) : 471.4411
## ARIMA(0,2,4) : 472.0159
## ARIMA(0,2,5) : 473.4288
## ARIMA(1,2,0) : 498.73
## ARIMA(1,2,1) : 479.4677
## ARIMA(1,2,2) : 476.4028
## ARIMA(1,2,3) : 473.2929
## ARIMA(1,2,4) : 474.108
## ARIMA(2,2,0) : 474.472
## ARIMA(2,2,1) : 468.2624
## ARIMA(2,2,2) : 470.5711
## ARIMA(2,2,3) : Inf
## ARIMA(3,2,0) : 469.8265
## ARIMA(3,2,1) : 470.5541
## ARIMA(3,2,2) : 473.0648
## ARIMA(4,2,0) : 471.763
## ARIMA(4,2,1) : 473.0536
## ARIMA(5,2,0) : 474.227
##
##
##
## Best model: ARIMA(2,2,1)
cat("\n=== MODEL ARIMA TERPILIH (auto.arima) ===\n")
##
## === MODEL ARIMA TERPILIH (auto.arima) ===
summary(model_auto)
## Series: co2_ts
## ARIMA(2,2,1)
##
## Coefficients:
## ar1 ar2 ma1
## 0.0215 -0.5317 -0.6742
## s.e. 0.1455 0.1244 0.1602
##
## sigma^2 = 349.7: log likelihood = -229.71
## AIC=467.43 AICc=468.26 BIC=475.31
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set 3.378189 17.83073 12.69953 1.181027 4.438248 0.7260615 -0.05919132
# Metode 2: Estimasi manual berdasarkan pola ACF/PACF
# Sebagai perbandingan, dicoba beberapa spesifikasi
cat("\n--- Perbandingan Model ARIMA Manual ---\n")
##
## --- Perbandingan Model ARIMA Manual ---
# Kandidat model berdasarkan inspeksi visual ACF/PACF
candidates <- list(
c(1, 1, 0), # AR(1) dengan d=1
c(1, 1, 1), # ARMA(1,1) dengan d=1
c(2, 1, 0), # AR(2) dengan d=1
c(2, 1, 1), # ARMA(2,1) dengan d=1
c(0, 1, 1), # MA(1) dengan d=1
c(0, 1, 2), # MA(2) dengan d=1
c(2, 1, 2), # ARMA(2,2) dengan d=1
c(1, 2, 1) # ARMA(1,1) dengan d=2 (jika d=2 diperlukan)
)
# Evaluasi AIC & BIC untuk setiap kandidat
comparison_results <- data.frame(
Model = character(),
AIC = numeric(),
BIC = numeric(),
stringsAsFactors = FALSE
)
for (params in candidates) {
model_name <- paste0("ARIMA(", params[1], ",", params[2], ",", params[3], ")")
tryCatch({
fit <- Arima(co2_ts, order = params)
comparison_results <- rbind(comparison_results, data.frame(
Model = model_name,
AIC = round(fit$aic, 2),
BIC = round(fit$bic, 2)
))
}, error = function(e) {
cat(" ⚠ Model", model_name, "gagal diestimasi:", conditionMessage(e), "\n")
})
}
# Urutkan berdasarkan AIC (terkecil = terbaik)
comparison_results <- comparison_results %>% arrange(AIC)
cat("\n=== PERBANDINGAN MODEL ARIMA (diurutkan berdasarkan AIC) ===\n")
##
## === PERBANDINGAN MODEL ARIMA (diurutkan berdasarkan AIC) ===
print(comparison_results)
## Model AIC BIC
## 1 ARIMA(1,2,1) 478.98 484.89
## 2 ARIMA(2,1,2) 486.20 496.14
## 3 ARIMA(0,1,1) 491.01 494.99
## 4 ARIMA(1,1,1) 492.91 498.87
## 5 ARIMA(0,1,2) 492.92 498.89
## 6 ARIMA(1,1,0) 493.85 497.83
## 7 ARIMA(2,1,1) 494.75 502.71
## 8 ARIMA(2,1,0) 495.25 501.21
# Pilih model terbaik: model dengan AIC terkecil
best_order <- candidates[[which.min(sapply(candidates, function(p) {
tryCatch(Arima(co2_ts, order = p)$aic, error = function(e) Inf)
}))]]
model_best <- Arima(co2_ts, order = best_order)
cat("\n=== MODEL ARIMA TERBAIK (Manual) ===\n")
##
## === MODEL ARIMA TERBAIK (Manual) ===
cat("Order:", paste0("ARIMA(", best_order[1], ",", best_order[2], ",", best_order[3], ")\n"))
## Order: ARIMA(1,2,1)
summary(model_best)
## Series: co2_ts
## ARIMA(1,2,1)
##
## Coefficients:
## ar1 ma1
## 0.1445 -0.9028
## s.e. 0.1492 0.0661
##
## sigma^2 = 444.8: log likelihood = -236.49
## AIC=478.98 AICc=479.47 BIC=484.89
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set 3.766276 20.30994 12.76764 1.350541 4.19482 0.7299557 0.01300726
# Memutuskan model final: bandingkan auto.arima vs manual
if (model_auto$aic <= model_best$aic) {
model_arima <- model_auto
cat("\n✔ Model final dipilih: auto.arima →",
paste0("ARIMA(", model_auto$arma[1], ",", model_auto$arma[6], ",", model_auto$arma[2], ")"),
"| AIC =", round(model_auto$aic, 2), "\n")
} else {
model_arima <- model_best
cat("\n✔ Model final dipilih: Manual →",
paste0("ARIMA(", best_order[1], ",", best_order[2], ",", best_order[3], ")"),
"| AIC =", round(model_best$aic, 2), "\n")
}
##
## ✔ Model final dipilih: auto.arima → ARIMA(2,2,1) | AIC = 467.43
# 3d. DIAGNOSTIK RESIDUAL ARIMA
cat("\n--- Diagnostik Residual Model ARIMA ---\n")
##
## --- Diagnostik Residual Model ARIMA ---
# Ljung-Box test: menguji apakah residual bersifat white noise
cat("\n--- Uji Ljung-Box pada Residual ARIMA ---\n")
##
## --- Uji Ljung-Box pada Residual ARIMA ---
lb_test <- Box.test(residuals(model_arima), lag = 10, type = "Ljung-Box")
print(lb_test)
##
## Box-Ljung test
##
## data: residuals(model_arima)
## X-squared = 10.813, df = 10, p-value = 0.3722
cat("Interpretasi: ")
## Interpretasi:
if (lb_test$p.value > 0.05) {
cat("p-value > 0.05 → Residual bersifat white noise (model memadai).\n")
} else {
cat("p-value <= 0.05 → Residual masih mengandung autokorelasi.\n")
}
## p-value > 0.05 → Residual bersifat white noise (model memadai).
# Plot diagnostik
checkresiduals(
model_arima,
test = FALSE,
main = "Diagnostik Residual Model ARIMA"
)

# ============================================================================
# INTERPRETASI ARIMA:
# Model ARIMA yang dipilih menangkap pola autokorelasi dalam data emisi.
# AIC/BIC yang lebih rendah menunjukkan model yang lebih parsimoni.
# Residual yang white noise mengkonfirmasi bahwa model telah menangkap
# seluruh pola sistematik dalam data.
# ============================================================================
# ==========================
# 4. UJI EFEK ARCH & MODEL GARCH
# ==========================
cat("\n\n", paste(rep("=", 60), collapse = ""), "\n")
##
##
## ============================================================
cat("BAGIAN 4: UJI EFEK ARCH & MODEL GARCH\n")
## BAGIAN 4: UJI EFEK ARCH & MODEL GARCH
cat(paste(rep("=", 60), collapse = ""), "\n\n")
## ============================================================
# 4a. UJI ARCH-LM PADA RESIDUAL ARIMA
residual_arima <- residuals(model_arima)
# Uji ARCH-LM menggunakan paket FinTS
cat("--- Uji ARCH-LM (Engle's LM Test) pada Residual ARIMA ---\n")
## --- Uji ARCH-LM (Engle's LM Test) pada Residual ARIMA ---
arch_test <- ArchTest(residual_arima, lags = 5, demean = TRUE)
print(arch_test)
##
## ARCH LM-test; Null hypothesis: no ARCH effects
##
## data: residual_arima
## Chi-squared = 27.932, df = 5, p-value = 3.753e-05
cat("Interpretasi: ")
## Interpretasi:
if (arch_test$p.value > 0.05) {
cat("p-value > 0.05 → TIDAK terdeteksi efek ARCH.\n")
cat(" → Volatilitas residual konstan (homoskedastik).\n")
cat(" → Model ARIMA sudah cukup, GARCH opsional.\n")
arch_detected <- FALSE
} else {
cat("p-value <= 0.05 → Terdeteksi efek ARCH (heteroskedastisitas).\n")
cat(" → Volatilitas residual berubah-ubah seiring waktu.\n")
cat(" → Model GARCH diperlukan untuk menangkap pola volatilitas.\n")
arch_detected <- TRUE
}
## p-value <= 0.05 → Terdeteksi efek ARCH (heteroskedastisitas).
## → Volatilitas residual berubah-ubah seiring waktu.
## → Model GARCH diperlukan untuk menangkap pola volatilitas.
# 4b. ESTIMASI MODEL GARCH (tetap dilakukan untuk kelengkapan analisis)
cat("\n--- Estimasi Model GARCH(1,1) ---\n")
##
## --- Estimasi Model GARCH(1,1) ---
cat("(Model GARCH diestimasi untuk kelengkapan analisis jurnal)\n\n")
## (Model GARCH diestimasi untuk kelengkapan analisis jurnal)
# Spesifikasi GARCH(1,1) dengan mean model ARMA
# Mengambil order AR dan MA dari model ARIMA terpilih
arima_order <- arimaorder(model_arima)
p_ar <- arima_order["p"]
q_ma <- arima_order["q"]
# Spesifikasi model menggunakan rugarch
# sGARCH = standard GARCH; norm = distribusi normal
garch_spec <- ugarchspec(
variance.model = list(
model = "sGARCH", # Model GARCH standar
garchOrder = c(1, 1) # GARCH(1,1): alpha + beta
),
mean.model = list(
armaOrder = c(p_ar, q_ma), # Mean equation: ARMA dari ARIMA
include.mean = TRUE
),
distribution.model = "norm" # Distribusi error: Normal
)
# Estimasi model pada data yang sudah di-differencing sesuai order d
d_order <- arima_order["d"]
if (d_order > 0) {
co2_diff_garch <- diff(co2_ts, differences = d_order)
} else {
co2_diff_garch <- co2_ts
}
# Fit model GARCH
garch_fit <- tryCatch({
ugarchfit(spec = garch_spec, data = co2_diff_garch, solver = "hybrid")
}, error = function(e) {
cat(" ⚠ GARCH(1,1) dengan ARMA(", p_ar, ",", q_ma, ") gagal.\n")
cat(" → Mencoba GARCH(1,1) dengan mean konstan...\n\n")
# Fallback: GARCH(1,1) tanpa komponen ARMA
spec_simple <- ugarchspec(
variance.model = list(model = "sGARCH", garchOrder = c(1, 1)),
mean.model = list(armaOrder = c(0, 0), include.mean = TRUE),
distribution.model = "norm"
)
ugarchfit(spec = spec_simple, data = co2_diff_garch, solver = "hybrid")
})
## Warning in .sgarchfit(spec = spec, data = data, out.sample = out.sample, :
## ugarchfit-->waring: using less than 100 data
## points for estimation
cat("\n=== RINGKASAN MODEL GARCH ===\n")
##
## === RINGKASAN MODEL GARCH ===
show(garch_fit)
##
## *---------------------------------*
## * GARCH Model Fit *
## *---------------------------------*
##
## Conditional Variance Dynamics
## -----------------------------------
## GARCH Model : sGARCH(1,1)
## Mean Model : ARFIMA(2,0,1)
## Distribution : norm
##
## Optimal Parameters
## ------------------------------------
## Estimate Std. Error t value Pr(>|t|)
## mu 0.38502 0.084123 4.57687 0.000005
## ar1 0.11880 0.151878 0.78219 0.434103
## ar2 -0.32069 0.161855 -1.98135 0.047552
## ma1 -1.00000 0.110894 -9.01764 0.000000
## omega 0.00000 0.027946 0.00000 1.000000
## alpha1 0.31491 0.139048 2.26477 0.023527
## beta1 0.80756 0.079991 10.09558 0.000000
##
## Robust Standard Errors:
## Estimate Std. Error t value Pr(>|t|)
## mu 0.38502 0.109931 3.50239 0.000461
## ar1 0.11880 0.160394 0.74066 0.458900
## ar2 -0.32069 0.189466 -1.69261 0.090531
## ma1 -1.00000 0.095009 -10.52531 0.000000
## omega 0.00000 0.000029 0.00000 1.000000
## alpha1 0.31491 0.083214 3.78438 0.000154
## beta1 0.80756 0.061888 13.04865 0.000000
##
## LogLikelihood : -214.5257
##
## Information Criteria
## ------------------------------------
##
## Akaike 8.3595
## Bayes 8.6197
## Shibata 8.3297
## Hannan-Quinn 8.4595
##
## Weighted Ljung-Box Test on Standardized Residuals
## ------------------------------------
## statistic p-value
## Lag[1] 0.657 0.4176
## Lag[2*(p+q)+(p+q)-1][8] 3.080 0.9950
## Lag[4*(p+q)+(p+q)-1][14] 6.768 0.6060
## d.o.f=3
## H0 : No serial correlation
##
## Weighted Ljung-Box Test on Standardized Squared Residuals
## ------------------------------------
## statistic p-value
## Lag[1] 2.854 0.09116
## Lag[2*(p+q)+(p+q)-1][5] 4.764 0.17300
## Lag[4*(p+q)+(p+q)-1][9] 7.674 0.14903
## d.o.f=2
##
## Weighted ARCH LM Tests
## ------------------------------------
## Statistic Shape Scale P-Value
## ARCH Lag[3] 0.03437 0.500 2.000 0.8529
## ARCH Lag[5] 1.66013 1.440 1.667 0.5512
## ARCH Lag[7] 3.75252 2.315 1.543 0.3837
##
## Nyblom stability test
## ------------------------------------
## Joint Statistic: 4.551
## Individual Statistics:
## mu 0.03604
## ar1 0.12107
## ar2 0.36800
## ma1 0.30139
## omega 0.16183
## alpha1 0.11552
## beta1 0.31751
##
## Asymptotic Critical Values (10% 5% 1%)
## Joint Statistic: 1.69 1.9 2.35
## Individual Statistic: 0.35 0.47 0.75
##
## Sign Bias Test
## ------------------------------------
## t-value prob sig
## Sign Bias 0.1311 0.8963
## Negative Sign Bias 1.0141 0.3156
## Positive Sign Bias 0.3655 0.7164
## Joint Effect 1.4392 0.6964
##
##
## Adjusted Pearson Goodness-of-Fit Test:
## ------------------------------------
## group statistic p-value(g-1)
## 1 20 15.30 0.7032
## 2 30 24.55 0.7015
## 3 40 32.28 0.7681
## 4 50 46.06 0.5932
##
##
## Elapsed time : 0.4542799
# Koefisien GARCH
cat("\n--- Koefisien Model GARCH ---\n")
##
## --- Koefisien Model GARCH ---
print(coef(garch_fit))
## mu ar1 ar2 ma1 omega
## 3.850210e-01 1.187975e-01 -3.206920e-01 -1.000000e+00 2.220446e-16
## alpha1 beta1
## 3.149128e-01 8.075602e-01
# Informasi kriteria
cat("\n--- Kriteria Informasi ---\n")
##
## --- Kriteria Informasi ---
print(infocriteria(garch_fit))
##
## Akaike 8.359459
## Bayes 8.619686
## Shibata 8.329709
## Hannan-Quinn 8.459530
# ============================================================================
# INTERPRETASI GARCH:
# - omega (ω): konstanta dalam persamaan varians
# - alpha1 (α₁): koefisien ARCH, mengukur dampak shock periode sebelumnya
# terhadap volatilitas saat ini (short-term shock)
# - beta1 (β₁): koefisien GARCH, mengukur persistensi volatilitas
# (long-term memory)
# - α₁ + β₁ < 1 → volatilitas bersifat mean-reverting (stabil)
# - α₁ + β₁ ≈ 1 → volatilitas sangat persisten (mendekati IGARCH)
#
# Jika efek ARCH tidak signifikan (Bagian 4a), maka model ARIMA murni
# sudah cukup, dan GARCH hanya bersifat komplementer.
# ============================================================================
# ==========================
# 5. FORECASTING & VISUALISASI
# ==========================
cat("\n\n", paste(rep("=", 60), collapse = ""), "\n")
##
##
## ============================================================
cat("BAGIAN 5: PERAMALAN (FORECASTING) 10 TAHUN KE DEPAN\n")
## BAGIAN 5: PERAMALAN (FORECASTING) 10 TAHUN KE DEPAN
cat(paste(rep("=", 60), collapse = ""), "\n\n")
## ============================================================
# 5a. PERAMALAN ARIMA (10 Tahun: 2025–2034)
h_forecast <- 10 # horizon peramalan
fc_arima <- forecast(model_arima, h = h_forecast, level = c(80, 95))
cat("=== HASIL PERAMALAN ARIMA (2025–2034) ===\n")
## === HASIL PERAMALAN ARIMA (2025–2034) ===
print(fc_arima)
## Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
## 2025 851.1820 827.2156 875.1483 814.5286 887.8353
## 2026 895.5798 855.3687 935.7908 834.0823 957.0773
## 2027 940.4473 891.7145 989.1801 865.9169 1014.9776
## 2028 982.4429 924.7868 1040.0989 894.2655 1070.6202
## 2029 1024.1271 953.2523 1095.0018 915.7335 1132.5207
## 2030 1067.3317 982.0085 1152.6548 936.8412 1197.8222
## 2031 1110.7345 1011.8837 1209.5853 959.5553 1261.9137
## 2032 1153.3331 1040.4873 1266.1789 980.7503 1325.9159
## 2033 1195.8091 1067.5053 1324.1128 999.5855 1392.0327
## 2034 1238.7100 1094.1493 1383.2707 1017.6235 1459.7965
# Membuat dataframe untuk plotting
fc_df <- data.frame(
year = 2025:(2024 + h_forecast),
forecast = as.numeric(fc_arima$mean),
lo80 = as.numeric(fc_arima$lower[, 1]),
hi80 = as.numeric(fc_arima$upper[, 1]),
lo95 = as.numeric(fc_arima$lower[, 2]),
hi95 = as.numeric(fc_arima$upper[, 2])
)
cat("\n=== TABEL PERAMALAN ===\n")
##
## === TABEL PERAMALAN ===
print(fc_df %>% mutate(across(where(is.numeric) & !matches("year"), ~round(., 2))))
## year forecast lo80 hi80 lo95 hi95
## 1 2025 851.18 827.22 875.15 814.53 887.84
## 2 2026 895.58 855.37 935.79 834.08 957.08
## 3 2027 940.45 891.71 989.18 865.92 1014.98
## 4 2028 982.44 924.79 1040.10 894.27 1070.62
## 5 2029 1024.13 953.25 1095.00 915.73 1132.52
## 6 2030 1067.33 982.01 1152.65 936.84 1197.82
## 7 2031 1110.73 1011.88 1209.59 959.56 1261.91
## 8 2032 1153.33 1040.49 1266.18 980.75 1325.92
## 9 2033 1195.81 1067.51 1324.11 999.59 1392.03
## 10 2034 1238.71 1094.15 1383.27 1017.62 1459.80
# 5b. PERAMALAN GARCH (Conditional Volatility)
fc_garch <- ugarchforecast(garch_fit, n.ahead = h_forecast)
cat("\n=== PERAMALAN VOLATILITAS GARCH (10 Tahun) ===\n")
##
## === PERAMALAN VOLATILITAS GARCH (10 Tahun) ===
cat("Series (Mean Forecast - differenced scale):\n")
## Series (Mean Forecast - differenced scale):
print(fitted(fc_garch))
## 2024-01-01
## T+1 -21.27355484
## T+2 1.21293112
## T+3 7.42910763
## T+4 0.95633663
## T+5 -1.80609068
## T+6 -0.05849394
## T+7 1.03500463
## T+8 0.60446914
## T+9 0.20264631
## T+10 0.29298008
cat("\nSigma (Conditional Volatility Forecast):\n")
##
## Sigma (Conditional Volatility Forecast):
print(sigma(fc_garch))
## 2024-01-01
## T+1 42.72754
## T+2 45.26847
## T+3 47.96051
## T+4 50.81264
## T+5 53.83438
## T+6 57.03582
## T+7 60.42764
## T+8 64.02116
## T+9 67.82839
## T+10 71.86203
# 5c. VISUALISASI UTAMA — GRAFIK JURNAL
cat("\n--- Membuat visualisasi untuk jurnal ---\n")
##
## --- Membuat visualisasi untuk jurnal ---
# Warna palette yang konsisten dan profesional
color_hist <- "#2C3E50" # biru tua (data historis)
color_fc <- "#E74C3C" # merah (forecast)
color_ci95 <- "#F5B7B1" # merah muda terang (CI 95%)
color_ci80 <- "#EC7063" # merah muda (CI 80%)
color_grid <- "#ECF0F1" # abu terang (grid)
# Data historis untuk plotting
hist_df <- df %>% select(year, co2_mt)
# PLOT 1: Grafik Utama — Historical + Forecast
p_main <- ggplot() +
# Confidence interval 95%
geom_ribbon(
data = fc_df,
aes(x = year, ymin = lo95, ymax = hi95),
fill = color_ci95, alpha = 0.5
) +
# Confidence interval 80%
geom_ribbon(
data = fc_df,
aes(x = year, ymin = lo80, ymax = hi80),
fill = color_ci80, alpha = 0.5
) +
# Garis data historis
geom_line(
data = hist_df,
aes(x = year, y = co2_mt),
color = color_hist, linewidth = 0.9
) +
geom_point(
data = hist_df,
aes(x = year, y = co2_mt),
color = color_hist, size = 1.2, alpha = 0.6
) +
# Garis peramalan
geom_line(
data = fc_df,
aes(x = year, y = forecast),
color = color_fc, linewidth = 1, linetype = "dashed"
) +
geom_point(
data = fc_df,
aes(x = year, y = forecast),
color = color_fc, size = 2, shape = 17
) +
# Garis pemisah historis vs forecast
geom_vline(
xintercept = 2024.5,
linetype = "dotted", color = "grey40", linewidth = 0.5
) +
# Anotasi
annotate(
"text", x = 2010, y = max(fc_df$hi95) * 0.95,
label = "Data Historis",
color = color_hist, fontface = "bold", size = 3.5, hjust = 0
) +
annotate(
"text", x = 2028, y = max(fc_df$hi95) * 0.95,
label = "Peramalan ARIMA",
color = color_fc, fontface = "bold", size = 3.5, hjust = 0
) +
# Formatting
scale_x_continuous(
breaks = seq(1970, 2035, by = 5),
expand = expansion(mult = c(0.02, 0.02))
) +
scale_y_continuous(
labels = label_comma(suffix = " Mt"),
expand = expansion(mult = c(0.05, 0.1))
) +
labs(
title = "Proyeksi Emisi CO\u2082 Fossil Indonesia (1970\u20132034)",
subtitle = paste0(
"Model: ", paste0(
"ARIMA(", arimaorder(model_arima)["p"], ",",
arimaorder(model_arima)["d"], ",",
arimaorder(model_arima)["q"], ")"
),
" | Horizon: 10 Tahun | CI: 80% & 95%"
),
x = "Tahun",
y = "Emisi CO\u2082 (Juta Ton)",
caption = "Sumber Data: Worldometer | Analisis: R (forecast, rugarch)"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 14, hjust = 0,
margin = margin(b = 4)),
plot.subtitle = element_text(color = "grey40", size = 10, hjust = 0,
margin = margin(b = 12)),
plot.caption = element_text(color = "grey50", size = 8, hjust = 1,
margin = margin(t = 10)),
axis.title = element_text(face = "bold", size = 10),
axis.text = element_text(size = 9),
panel.grid.minor = element_blank(),
panel.grid.major = element_line(color = color_grid, linewidth = 0.3),
plot.margin = margin(15, 15, 10, 10)
)
print(p_main)

# Simpan plot utama (resolusi tinggi untuk jurnal)
ggsave(
filename = "d:/Training/CO2_Forecast_Main.png",
plot = p_main,
width = 10, height = 6, dpi = 300, bg = "white"
)
cat("✔ Plot utama disimpan: d:/Training/CO2_Forecast_Main.png\n")
## ✔ Plot utama disimpan: d:/Training/CO2_Forecast_Main.png
# PLOT 2: ACF/PACF menggunakan ggplot2 (versi estetis untuk jurnal)
# Hitung ACF dan PACF secara manual untuk ggplot
acf_vals <- acf(co2_diff1, plot = FALSE, lag.max = 20)
pacf_vals <- pacf(co2_diff1, plot = FALSE, lag.max = 20)
acf_df <- data.frame(
lag = as.numeric(acf_vals$lag[-1]),
acf = as.numeric(acf_vals$acf[-1])
)
pacf_df <- data.frame(
lag = as.numeric(pacf_vals$lag),
pacf = as.numeric(pacf_vals$acf)
)
# Batas signifikansi (95% CI ≈ ±1.96/√n)
n_obs <- length(co2_diff1)
ci_bound <- 1.96 / sqrt(n_obs)
p_acf <- ggplot(acf_df, aes(x = lag, y = acf)) +
geom_hline(yintercept = 0, color = "grey40", linewidth = 0.4) +
geom_hline(yintercept = c(-ci_bound, ci_bound),
linetype = "dashed", color = "#3498DB", linewidth = 0.4) +
geom_segment(aes(xend = lag, yend = 0), color = color_hist, linewidth = 0.7) +
geom_point(color = color_hist, size = 2) +
labs(title = "ACF — Data Differenced (d=1)", x = "Lag", y = "Autokorelasi") +
theme_minimal(base_size = 11) +
theme(
plot.title = element_text(face = "bold", size = 11, hjust = 0.5),
panel.grid.minor = element_blank()
)
p_pacf <- ggplot(pacf_df, aes(x = lag, y = pacf)) +
geom_hline(yintercept = 0, color = "grey40", linewidth = 0.4) +
geom_hline(yintercept = c(-ci_bound, ci_bound),
linetype = "dashed", color = "#3498DB", linewidth = 0.4) +
geom_segment(aes(xend = lag, yend = 0), color = "#8E44AD", linewidth = 0.7) +
geom_point(color = "#8E44AD", size = 2) +
labs(title = "PACF — Data Differenced (d=1)", x = "Lag", y = "Autokorelasi Parsial") +
theme_minimal(base_size = 11) +
theme(
plot.title = element_text(face = "bold", size = 11, hjust = 0.5),
panel.grid.minor = element_blank()
)
p_acf_pacf <- p_acf + p_pacf +
plot_annotation(
title = "Correlogram Emisi CO\u2082 Indonesia",
caption = "Garis biru putus-putus: batas signifikansi 95%",
theme = theme(
plot.title = element_text(face = "bold", size = 13, hjust = 0.5),
plot.caption = element_text(color = "grey50", size = 8, hjust = 0.5)
)
)
print(p_acf_pacf)

ggsave(
filename = "d:/Training/CO2_ACF_PACF.png",
plot = p_acf_pacf,
width = 10, height = 5, dpi = 300, bg = "white"
)
cat("✔ Plot ACF/PACF disimpan: d:/Training/CO2_ACF_PACF.png\n")
## ✔ Plot ACF/PACF disimpan: d:/Training/CO2_ACF_PACF.png
# PLOT 3: Diagnostik Residual ARIMA (ggplot2)
resid_df <- data.frame(
year = time(residual_arima),
residual = as.numeric(residual_arima)
)
p_resid_ts <- ggplot(resid_df, aes(x = year, y = residual)) +
geom_hline(yintercept = 0, linetype = "dashed", color = "grey50") +
geom_line(color = color_hist, linewidth = 0.5) +
geom_point(color = color_hist, size = 1, alpha = 0.6) +
labs(title = "Residual Time Series", x = "Tahun", y = "Residual (Mt)") +
theme_minimal(base_size = 10) +
theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 10),
panel.grid.minor = element_blank())
p_resid_hist <- ggplot(resid_df, aes(x = residual)) +
geom_histogram(
aes(y = after_stat(density)),
bins = 15, fill = color_hist, alpha = 0.7, color = "white"
) +
geom_density(color = color_fc, linewidth = 0.8) +
labs(title = "Distribusi Residual", x = "Residual (Mt)", y = "Density") +
theme_minimal(base_size = 10) +
theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 10),
panel.grid.minor = element_blank())
p_resid_qq <- ggplot(resid_df, aes(sample = residual)) +
stat_qq(color = color_hist, size = 1.5, alpha = 0.7) +
stat_qq_line(color = color_fc, linewidth = 0.7) +
labs(title = "Q-Q Plot Residual", x = "Theoretical Quantiles", y = "Sample Quantiles") +
theme_minimal(base_size = 10) +
theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 10),
panel.grid.minor = element_blank())
p_diagnostics <- p_resid_ts + p_resid_hist + p_resid_qq +
plot_layout(ncol = 3) +
plot_annotation(
title = "Diagnostik Residual Model ARIMA",
theme = theme(plot.title = element_text(face = "bold", size = 13, hjust = 0.5))
)
print(p_diagnostics)
## Don't know how to automatically pick scale for object of type <ts>. Defaulting
## to continuous.

ggsave(
filename = "d:/Training/CO2_Residual_Diagnostics.png",
plot = p_diagnostics,
width = 12, height = 4.5, dpi = 300, bg = "white"
)
## Don't know how to automatically pick scale for object of type <ts>. Defaulting
## to continuous.
cat("✔ Plot diagnostik disimpan: d:/Training/CO2_Residual_Diagnostics.png\n")
## ✔ Plot diagnostik disimpan: d:/Training/CO2_Residual_Diagnostics.png
# PLOT 4: Conditional Volatility (dari GARCH)
sigma_hist <- sigma(garch_fit)
vol_df <- data.frame(
year = time(co2_diff_garch),
volatility = as.numeric(sigma_hist)
)
p_vol <- ggplot(vol_df, aes(x = year, y = volatility)) +
geom_area(fill = "#F39C12", alpha = 0.3) +
geom_line(color = "#E67E22", linewidth = 0.8) +
labs(
title = "Conditional Volatility Emisi CO\u2082 — Model GARCH(1,1)",
subtitle = "Estimasi volatilitas bersyarat dari residual ARIMA",
x = "Tahun", y = "Conditional Std. Dev. (Mt)",
caption = "Sumber: Model GARCH(1,1) via rugarch"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 13, hjust = 0),
plot.subtitle = element_text(color = "grey40", size = 9, hjust = 0),
plot.caption = element_text(color = "grey50", size = 8),
panel.grid.minor = element_blank()
)
print(p_vol)
## Don't know how to automatically pick scale for object of type <ts>. Defaulting
## to continuous.

ggsave(
filename = "d:/Training/CO2_GARCH_Volatility.png",
plot = p_vol,
width = 10, height = 5, dpi = 300, bg = "white"
)
## Don't know how to automatically pick scale for object of type <ts>. Defaulting
## to continuous.
cat("✔ Plot volatilitas GARCH disimpan: d:/Training/CO2_GARCH_Volatility.png\n")
## ✔ Plot volatilitas GARCH disimpan: d:/Training/CO2_GARCH_Volatility.png
# ==========================
# 6. RINGKASAN AKHIR
# ==========================
cat("\n\n", paste(rep("=", 60), collapse = ""), "\n")
##
##
## ============================================================
cat("RINGKASAN ANALISIS\n")
## RINGKASAN ANALISIS
cat(paste(rep("=", 60), collapse = ""), "\n\n")
## ============================================================
cat("1. REGRESI LINEAR:\n")
## 1. REGRESI LINEAR:
cat(" - R²:", round(summary(model_lm)$r.squared, 4), "\n")
## - R²: 0.9474
cat(" - Slope (peningkatan per tahun):",
round(coef(model_lm)[2], 2), "Mt/tahun\n")
## - Slope (peningkatan per tahun): 13.02 Mt/tahun
cat(" - Autokorelasi terdeteksi (DW test) → regresi OLS tidak memadai.\n\n")
## - Autokorelasi terdeteksi (DW test) → regresi OLS tidak memadai.
cat("2. MODEL ARIMA:\n")
## 2. MODEL ARIMA:
cat(" - Model terpilih:", paste0(
"ARIMA(", arimaorder(model_arima)["p"], ",",
arimaorder(model_arima)["d"], ",",
arimaorder(model_arima)["q"], ")\n"))
## - Model terpilih: ARIMA(2,2,1)
cat(" - AIC:", round(model_arima$aic, 2), "\n")
## - AIC: 467.43
cat(" - BIC:", round(model_arima$bic, 2), "\n")
## - BIC: 475.31
cat(" - Residual white noise (Ljung-Box p =", round(lb_test$p.value, 4), ")\n\n")
## - Residual white noise (Ljung-Box p = 0.3722 )
cat("3. EFEK ARCH/GARCH:\n")
## 3. EFEK ARCH/GARCH:
cat(" - ARCH-LM Test p-value:", round(arch_test$p.value, 4), "\n")
## - ARCH-LM Test p-value: 0
if (arch_detected) {
cat(" - Efek ARCH TERDETEKSI → Model GARCH(1,1) diestimasi.\n")
} else {
cat(" - Efek ARCH TIDAK terdeteksi → GARCH bersifat komplementer.\n")
}
## - Efek ARCH TERDETEKSI → Model GARCH(1,1) diestimasi.
cat(" - GARCH alpha1 + beta1:",
round(sum(coef(garch_fit)[c("alpha1", "beta1")]), 4), "\n\n")
## - GARCH alpha1 + beta1: 1.1225
cat("4. PERAMALAN 2025–2034:\n")
## 4. PERAMALAN 2025–2034:
for (i in 1:nrow(fc_df)) {
cat(sprintf(" %d: %.2f Mt [95%% CI: %.2f — %.2f]\n",
fc_df$year[i], fc_df$forecast[i], fc_df$lo95[i], fc_df$hi95[i]))
}
## 2025: 851.18 Mt [95% CI: 814.53 — 887.84]
## 2026: 895.58 Mt [95% CI: 834.08 — 957.08]
## 2027: 940.45 Mt [95% CI: 865.92 — 1014.98]
## 2028: 982.44 Mt [95% CI: 894.27 — 1070.62]
## 2029: 1024.13 Mt [95% CI: 915.73 — 1132.52]
## 2030: 1067.33 Mt [95% CI: 936.84 — 1197.82]
## 2031: 1110.73 Mt [95% CI: 959.56 — 1261.91]
## 2032: 1153.33 Mt [95% CI: 980.75 — 1325.92]
## 2033: 1195.81 Mt [95% CI: 999.59 — 1392.03]
## 2034: 1238.71 Mt [95% CI: 1017.62 — 1459.80]
cat("\n5. OUTPUT FILES:\n")
##
## 5. OUTPUT FILES:
cat(" - d:/Training/CO2_Forecast_Main.png\n")
## - d:/Training/CO2_Forecast_Main.png
cat(" - d:/Training/CO2_ACF_PACF.png\n")
## - d:/Training/CO2_ACF_PACF.png
cat(" - d:/Training/CO2_Residual_Diagnostics.png\n")
## - d:/Training/CO2_Residual_Diagnostics.png
cat(" - d:/Training/CO2_GARCH_Volatility.png\n")
## - d:/Training/CO2_GARCH_Volatility.png
cat("\n", paste(rep("=", 60), collapse = ""), "\n")
##
## ============================================================
cat("ANALISIS SELESAI.\n")
## ANALISIS SELESAI.
cat(paste(rep("=", 60), collapse = ""), "\n")
## ============================================================