Sumber Data

library(readxl)    
library(forecast)  
library(urca)      
library(tseries)   
library(dynlm)     
library(lmtest)    
library(sandwich)  
library(knitr)

Hasil Pemodelan

Membaca dan menyiapkan data

file_data <- "C:/TUGAS DAN MATERI STIS/Tingkat 2/Semester 4/Analisis Runtun WaktU/Project UAS/Studi Kasus 3/pdb_triwulanan.xlsx"
raw <- read_excel(file_data, col_names = FALSE, .name_repair = "minimal")

header_triwulan <- as.character(unlist(raw[3, ]))
kolom_tw <- which(grepl("Triwulan", header_triwulan))   # buang kolom "Tahunan"

ambil <- function(pola) {
  baris <- which(grepl(pola, raw[[1]]))
  suppressWarnings(as.numeric(unlist(raw[baris, kolom_tw])))  # "-" jadi NA
}
C <- ambil("Konsumsi Rumahtangga")
Y <- ambil("PRODUK DOMESTIK BRUTO")
ok <- !is.na(C) & !is.na(Y)                                   
C <- ts(C[ok], start = c(2010, 1), frequency = 4)
Y <- ts(Y[ok], start = c(2010, 1), frequency = 4)

cat("Jumlah observasi:", length(C), "| periode:",
    paste(start(C), collapse = "Q"), "s.d.", paste(end(C), collapse = "Q"), "\n")
## Jumlah observasi: 66 | periode: 2010Q1 s.d. 2026Q2
kable(head(data.frame(Periode = as.character(zoo::as.yearqtr(time(C))),
                      Konsumsi_RT = as.numeric(C), PDB = as.numeric(Y)), 8),
      format.args = list(big.mark = "."), caption = "Cuplikan data (miliar rupiah, ADHK 2010)")
Cuplikan data (miliar rupiah, ADHK 2010)
Periode Konsumsi_RT PDB
2010 Q1 926.097.5 1.642.356
2010 Q2 937.226.8 1.709.132
2010 Q3 959.649.9 1.775.110
2010 Q4 963.088.7 1.737.535
2011 Q1 964.261.9 1.748.731
2011 Q2 980.156.6 1.816.268
2011 Q3 1.016.155.4 1.881.850
2011 Q4 1.016.714.7 1.840.786

Transformasi log dan penyesuaian musiman

lnC_asli <- log(C); lnY_asli <- log(Y)
lnC <- seasadj(stl(lnC_asli, s.window = 9))   
lnY <- seasadj(stl(lnY_asli, s.window = 9))   
par(mfrow = c(2, 1), mar = c(3, 4, 2.5, 1))
ts.plot(lnC_asli, lnC, col = c("grey60", "firebrick"), lwd = c(1, 2),
        main = "ln Konsumsi Rumah Tangga (abu = asli, merah = disesuaikan musiman)", ylab = "ln C")
ts.plot(lnY_asli, lnY, col = c("grey60", "navy"), lwd = c(1, 2),
        main = "ln PDB (abu = asli, biru = disesuaikan musiman)", ylab = "ln Y")

rasio <- C / Y
plot(rasio, type = "o", pch = 16, cex = .6, col = "darkgreen",
     main = "Rasio Konsumsi RT terhadap PDB", ylab = "C / Y", xlab = "")
abline(v = 2021, lty = 2, col = "red")

Uji stasioneritas

uji_ar <- function(x, nama, tipe_adf, tipe_kpss) {
  adf  <- ur.df(x, type = tipe_adf, lags = 4, selectlags = "AIC")
  stat <- adf@teststat[1]; cv5 <- adf@cval[1, "5pct"]
  kp   <- kpss.test(x, null = tipe_kpss)
  data.frame(Variabel = nama, `ADF stat` = round(stat, 3), `CV 5%` = cv5,
             `Keputusan ADF` = ifelse(stat < cv5, "Stasioner", "Tidak stasioner"),
             `KPSS p-value` = round(kp$p.value, 3),
             `Keputusan KPSS` = ifelse(kp$p.value < .05, "Tidak stasioner", "Stasioner"),
             check.names = FALSE)
}
tabel_ur <- rbind(
  uji_ar(lnC,       "ln C (level)",         "trend", "Trend"),
  uji_ar(lnY,       "ln Y (level)",         "trend", "Trend"),
  uji_ar(diff(lnC), "Δ ln C (diff. 1)",     "drift", "Level"),
  uji_ar(diff(lnY), "Δ ln Y (diff. 1)",     "drift", "Level"))
kable(tabel_ur, caption = "Uji ADF dan KPSS (catatan: p-value KPSS dibatasi 0,01–0,10)")
Uji ADF dan KPSS (catatan: p-value KPSS dibatasi 0,01–0,10)
Variabel ADF stat CV 5% Keputusan ADF KPSS p-value Keputusan KPSS
ln C (level) -1.942 -3.45 Tidak stasioner 0.01 Tidak stasioner
ln Y (level) -2.122 -3.45 Tidak stasioner 0.01 Tidak stasioner
Δ ln C (diff. 1) -4.941 -2.89 Stasioner 0.10 Stasioner
Δ ln Y (diff. 1) -4.925 -2.89 Stasioner 0.10 Stasioner

Persamaan jangka panjang (regresi kointegrasi)

waktu <- time(lnC)
kandidat <- seq(2019, 2022.75, by = 0.25)
ssr <- sapply(kandidat, function(b) {
  D <- as.numeric(waktu >= b - 1e-6); sum(resid(lm(lnC ~ lnY + D))^2)
})
tgl_break <- kandidat[which.min(ssr)]
plot(kandidat, ssr * 1e4, type = "b", pch = 16, xlab = "Awal dummy", ylab = "SSR (x 10^-4)",
     main = "Pemilihan tanggal patahan struktural")
abline(v = tgl_break, col = "red", lty = 2)

cat("Tanggal patahan terpilih:", as.character(zoo::as.yearqtr(tgl_break)), "\n")
## Tanggal patahan terpilih: 2021 Q1
D <- ts(as.numeric(waktu >= tgl_break - 1e-6), start = c(2010, 1), frequency = 4)
lr <- dynlm(lnC ~ lnY + D)
summary(lr)
## 
## Time series regression with "ts" data:
## Start = 2010(1), End = 2026(2)
## 
## Call:
## dynlm(formula = lnC ~ lnY + D)
## 
## Residuals:
##        Min         1Q     Median         3Q        Max 
## -0.0087579 -0.0022956  0.0001153  0.0017527  0.0169457 
## 
## Coefficients:
##              Estimate Std. Error t value             Pr(>|t|)    
## (Intercept) -0.196455   0.054828  -3.583             0.000662 ***
## lnY          0.971736   0.003751 259.039 < 0.0000000000000002 ***
## D           -0.020003   0.001646 -12.156 < 0.0000000000000002 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.004049 on 63 degrees of freedom
## Multiple R-squared:  0.9996, Adjusted R-squared:  0.9996 
## F-statistic: 7.559e+04 on 2 and 63 DF,  p-value: < 0.00000000000000022

Uji kointegrasi Engle–Granger

ect <- ts(resid(lr), start = c(2010, 1), frequency = 4)
eg <- ur.df(ect, type = "none", lags = 4, selectlags = "BIC")
summary(eg)
## 
## ############################################### 
## # Augmented Dickey-Fuller Test Unit Root Test # 
## ############################################### 
## 
## Test regression none 
## 
## 
## Call:
## lm(formula = z.diff ~ z.lag.1 - 1 + z.diff.lag)
## 
## Residuals:
##        Min         1Q     Median         3Q        Max 
## -0.0080400 -0.0011218  0.0003518  0.0012444  0.0096004 
## 
## Coefficients:
##            Estimate Std. Error t value Pr(>|t|)    
## z.lag.1     -0.5285     0.1397  -3.782 0.000365 ***
## z.diff.lag  -0.1137     0.1269  -0.896 0.373977    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.002805 on 59 degrees of freedom
## Multiple R-squared:  0.3139, Adjusted R-squared:  0.2906 
## F-statistic:  13.5 on 2 and 59 DF,  p-value: 0.00001492
## 
## 
## Value of test-statistic is: -3.7822 
## 
## Critical values for test statistics: 
##      1pct  5pct 10pct
## tau1 -2.6 -1.95 -1.61
plot(ect, type = "o", pch = 16, cex = .6, col = "purple",
     main = "Residual jangka panjang (ECT): simpangan dari keseimbangan", ylab = "u_t", xlab = "")
abline(h = 0, lty = 2)

tau <- eg@teststat[1]
cat("Statistik ADF residual =", round(tau, 3),
    "| nilai kritis MacKinnon 5% ≈ -3,37 ->",
    ifelse(tau < -3.37, "TOLAK H0: residual stasioner, C dan Y BERKOINTEGRASI",
                        "Gagal tolak H0"), "\n")
## Statistik ADF residual = -3.782 | nilai kritis MacKinnon 5% ≈ -3,37 -> TOLAK H0: residual stasioner, C dan Y BERKOINTEGRASI

Estimasi Error Correction Model

ecm <- dynlm(d(lnC) ~ d(lnY) + L(ect, 1))
summary(ecm)
## 
## Time series regression with "ts" data:
## Start = 2010(2), End = 2026(2)
## 
## Call:
## dynlm(formula = d(lnC) ~ d(lnY) + L(ect, 1))
## 
## Residuals:
##        Min         1Q     Median         3Q        Max 
## -0.0086942 -0.0004715  0.0006710  0.0016902  0.0042509 
## 
## Coefficients:
##              Estimate Std. Error t value             Pr(>|t|)    
## (Intercept) -0.001378   0.000531  -2.596               0.0118 *  
## d(lnY)       1.042131   0.034840  29.912 < 0.0000000000000002 ***
## L(ect, 1)   -0.391369   0.087135  -4.492            0.0000314 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.002782 on 62 degrees of freedom
## Multiple R-squared:  0.9392, Adjusted R-squared:  0.9373 
## F-statistic:   479 on 2 and 62 DF,  p-value: < 0.00000000000000022
coeftest(ecm, vcov = NeweyWest(ecm))
## 
## t test of coefficients:
## 
##               Estimate Std. Error t value              Pr(>|t|)    
## (Intercept) -0.0013782  0.0005392 -2.5560              0.013054 *  
## d(lnY)       1.0421307  0.0272499 38.2435 < 0.00000000000000022 ***
## L(ect, 1)   -0.3913686  0.1271170 -3.0788              0.003095 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
t_ect <- summary(ecm)$coefficients["L(ect, 1)", "t value"]
cat("t-stat ECT =", round(t_ect, 3), "->",
    ifelse(t_ect < -3.19, "signifikan (mendukung adanya kointegrasi)", "tidak signifikan"), "\n")
## t-stat ECT = -4.492 -> signifikan (mendukung adanya kointegrasi)

Uji diagnostik

diag_tab <- data.frame(
  Uji = c("Breusch-Godfrey (lag 1)", "Breusch-Godfrey (lag 4)",
          "Breusch-Pagan", "Jarque-Bera", "Ramsey RESET"),
  H0  = c("Tidak ada autokorelasi", "Tidak ada autokorelasi", "Homoskedastis",
          "Residual normal", "Spesifikasi linear tepat"),
  `p-value` = c(bgtest(ecm, 1)$p.value, bgtest(ecm, 4)$p.value, bptest(ecm)$p.value,
                jarque.bera.test(resid(ecm))$p.value, resettest(ecm)$p.value),
  check.names = FALSE)
diag_tab$Keputusan <- ifelse(diag_tab$`p-value` < 0.05, "Tolak H0", "Gagal tolak H0")
diag_tab$`p-value` <- format(signif(diag_tab$`p-value`, 3), scientific = FALSE, drop0trailing = TRUE)
kable(diag_tab, caption = "Uji asumsi residual ECM (α = 5%)")
Uji asumsi residual ECM (α = 5%)
Uji H0 p-value Keputusan
Breusch-Godfrey (lag 1) Tidak ada autokorelasi 0.756 Gagal tolak H0
Breusch-Godfrey (lag 4) Tidak ada autokorelasi 0.522 Gagal tolak H0
Breusch-Pagan Homoskedastis 0.41 Gagal tolak H0
Jarque-Bera Residual normal 0.000000387 Tolak H0
Ramsey RESET Spesifikasi linear tepat 0.938 Gagal tolak H0
par(mfrow = c(2, 2), mar = c(4, 4, 2.5, 1))
plot(resid(ecm), type = "o", pch = 16, cex = .5, main = "Residual ECM", ylab = "", xlab = "")
abline(h = 0, lty = 2)
acf(as.numeric(resid(ecm)), main = "ACF residual", lag.max = 12)
hist(resid(ecm), breaks = 15, col = "lightblue", main = "Histogram residual", xlab = "")
qqnorm(resid(ecm)); qqline(resid(ecm), col = "red")

r <- resid(ecm)
kable(data.frame(Periode = as.character(zoo::as.yearqtr(time(r)))[order(r)[1:3]],
                 Residual = round(sort(as.numeric(r))[1:3], 4)),
      caption = "Tiga residual paling ekstrem")
Tiga residual paling ekstrem
Periode Residual
2010 Q3 -0.0087
2021 Q1 -0.0076
2020 Q4 -0.0076

Kecepatan penyesuaian

lambda <- coef(ecm)["L(ect, 1)"]
half_life <- log(0.5) / log(1 + lambda)
t90 <- log(0.1) / log(1 + lambda)
cat("Koefisien ECT (lambda)          :", round(lambda, 4), "\n",
    "Porsi ketidakseimbangan dikoreksi per triwulan:", round(-lambda * 100, 1), "%\n",
    "Half-life                       :", round(half_life, 2), "triwulan\n",
    "Waktu sampai 90% terkoreksi     :", round(t90, 2), "triwulan\n")
## Koefisien ECT (lambda)          : -0.3914 
##  Porsi ketidakseimbangan dikoreksi per triwulan: 39.1 %
##  Half-life                       : 1.4 triwulan
##  Waktu sampai 90% terkoreksi     : 4.64 triwulan
# Simulasi: kalau hari ini konsumsi 1% di atas keseimbangan, bagaimana simpangannya menyusut?
h <- 0:10
simpangan <- 1 * (1 + lambda)^h
barplot(simpangan, names.arg = paste0("t+", h), col = "steelblue",
        main = "Sisa simpangan (%) dari keseimbangan setelah guncangan 1%", ylab = "%")

fit <- fitted(ecm)
ts.plot(diff(lnC), fit,
        col = c("black", "red"), lwd = c(1.5, 1.5), lty = c(1, 2),
        main = "Δ ln C aktual (hitam) vs fitted ECM (merah putus-putus)", ylab = "Δ ln C")

ringkas <- data.frame(
  Komponen = c("Elastisitas jangka panjang (β1)", "Dummy pasca-pandemi (δ)",
               "Elastisitas jangka pendek (γ)", "Koefisien ECT (λ)", "R² ECM"),
  Estimasi = round(c(coef(lr)[2], coef(lr)[3], coef(ecm)[2], coef(ecm)[3],
                     summary(ecm)$r.squared), 4))
kable(ringkas, row.names = FALSE, caption = "Ringkasan hasil")
Ringkasan hasil
Komponen Estimasi
Elastisitas jangka panjang (β1) 0.9717
Dummy pasca-pandemi (δ) -0.0200
Elastisitas jangka pendek (γ) 1.0421
Koefisien ECT (λ) -0.3914
R² ECM 0.9392
sessionInfo()
## R version 4.6.0 (2026-04-24 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 11 x64 (build 26200)
## 
## Matrix products: default
##   LAPACK version 3.12.1
## 
## locale:
## [1] LC_COLLATE=English_United States.utf8 
## [2] LC_CTYPE=English_United States.utf8   
## [3] LC_MONETARY=English_United States.utf8
## [4] LC_NUMERIC=C                          
## [5] LC_TIME=English_United States.utf8    
## 
## time zone: Asia/Jakarta
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] knitr_1.51      sandwich_3.1-3  lmtest_0.9-40   dynlm_0.3-6    
## [5] zoo_1.8-15      tseries_0.10-61 urca_1.3-4      forecast_9.0.2 
## [9] readxl_1.5.0   
## 
## loaded via a namespace (and not attached):
##  [1] sass_0.4.10        generics_0.1.4     lattice_0.22-9     digest_0.6.39     
##  [5] magrittr_2.0.5     evaluate_1.0.5     grid_4.6.0         RColorBrewer_1.1-3
##  [9] fastmap_1.2.0      cellranger_1.1.0   jsonlite_2.0.0     Formula_1.2-6     
## [13] scales_1.4.0       jquerylib_0.1.4    abind_1.4-8        cli_3.6.6         
## [17] rlang_1.2.0        cachem_1.1.0       yaml_2.3.12        otel_0.2.0        
## [21] tools_4.6.0        parallel_4.6.0     dplyr_1.2.1        colorspace_2.1-2  
## [25] ggplot2_4.0.3      curl_7.1.0         vctrs_0.7.3        R6_2.6.1          
## [29] stats4_4.6.0       lifecycle_1.0.5    car_3.1-5          pkgconfig_2.0.3   
## [33] pillar_1.11.1      bslib_0.11.0       gtable_0.3.6       glue_1.8.1        
## [37] quantmod_0.4.28    Rcpp_1.1.1-1.1     xfun_0.57          tibble_3.3.1      
## [41] tidyselect_1.2.1   rstudioapi_0.18.0  farver_2.1.2       htmltools_0.5.9   
## [45] nlme_3.1-169       carData_3.0-6      rmarkdown_2.31     xts_0.14.2        
## [49] timeDate_4052.112  fracdiff_1.5-4     compiler_4.6.0     S7_0.2.2          
## [53] quadprog_1.5-8     TTR_0.24.4