Skripsi Hubungan Simultan Utang Luar Negeri & Pertumbuhan Ekonomi

1 Library

library(readxl)
library(dplyr)
library(AER)
library(lmtest)
library(sandwich)
library(ivreg2r)
library(tseries)
library(car)
library(scales)
library(ggplot2)
library(urca)
library(dplyr)
library(knitr)
library(broom)

2 Persiapan Data

# Import data
data1 <- read_excel(
  "D:/STIS/Semester 7/Skripsi/Data/data skripsi.xlsx",
  sheet = 6
)
# Data asli
data_asli <- data.frame(
  LPDB = data1$LGDP,
  RULN = data1$ULN_PERCENTOFGDP,
  FDI = data1$FDI,
  LDEF = data1$LDEF,
  LRES = data1$LRES,
  LEMPLOYMENT = data1$LEMPLOYMENT,
  TOT = data1$TOT,
  LEXCHANGE = data1$LEXCHANGE
)

# Membuat first difference
data <- data.frame(
  d_LPDB = diff(data1$LGDP),
  d_RULN = diff(data1$ULN_PERCENTOFGDP),
  d_FDI = diff(data1$FDI),
  d_LDEF = diff(data1$LDEF),
  d_LRES = diff(data1$LRES),
  d_LEMPLOYMENT = diff(data1$LEMPLOYMENT),
  d_TOT = diff(data1$TOT),
  d_LEXCHANGE = diff(data1$LEXCHANGE)
)

3 Uji Stasioneritas

# ============================================================
# UJI STASIONERITAS AUGMENTED DICKEY-FULLER (ADF)
# Spesifikasi: Intercept + SIC/BIC
# Max Lag: 3
# Format Output: Menyerupai EViews
# ============================================================

# ------------------------------------------------------------
# 1. DATA YANG DIGUNAKAN
# ------------------------------------------------------------

data_level <- data_asli
data_diff  <- data


# ------------------------------------------------------------
# 2. FUNGSI P-VALUE MACKINNON (seperti EViews)
# ------------------------------------------------------------

pvalue_mackinnon <- function(stat, n) {

  # Koefisien respons permukaan MacKinnon (1996)
  # Model dengan intercept (drift), tanpa trend
  df_quantile <- function(p, n) {
    if (p == 0.01) {
      b0 <- -3.43035; b1 <- -6.5393; b2 <- -16.786
    } else if (p == 0.05) {
      b0 <- -2.86154; b1 <- -2.8903; b2 <- -4.234
    } else if (p == 0.10) {
      b0 <- -2.56677; b1 <- -1.5384; b2 <- -2.809
    } else {
      return(NA_real_)
    }
    return(b0 + b1 / n + b2 / n^2)
  }

  q01 <- df_quantile(0.01, n)
  q05 <- df_quantile(0.05, n)
  q10 <- df_quantile(0.10, n)

  if (stat <= q01) return(0.0000)
  if (stat <= q05) return(0.01 * (stat - q01) / (q05 - q01))
  if (stat <= q10) return(0.05 * (stat - q05) / (q10 - q05) + 0.05)
  return(0.10 + 0.90 * (stat - q10) / (abs(q10) * 2))
}


# ------------------------------------------------------------
# 3. FUNGSI UJI ADF (FORMAT EVIEWS)
# ------------------------------------------------------------

uji_adf_eviews <- function(dataset, nama_dataset) {

  variabel_numerik <- names(dataset)[
    sapply(dataset, is.numeric)
  ]

  hasil <- lapply(variabel_numerik, function(nama) {

    x <- dataset[[nama]]
    x <- x[is.finite(x)]
    n <- length(x)

    if (n < 10 || length(unique(x)) < 2) {
      return(data.frame(
        Dataset = nama_dataset,
        Variabel = nama,
        N = n,
        `Statistik ADF` = NA_real_,
        `P-value` = NA_real_,
        Kesimpulan = "Tidak dapat diuji",
        check.names = FALSE
      ))
    }

    # ------------------------------------------------------
    # MAX LAG = 3 (fixed, sesuai permintaan)
    # ------------------------------------------------------
    max_lag <- 3
    max_lag <- min(max_lag, floor(n / 2) - 2)
    max_lag <- max(0, max_lag)

    hasil_adf <- tryCatch(
      urca::ur.df(y = x, type = "drift",
                  lags = max_lag, selectlags = "BIC"),
      error = function(e) NULL
    )

    if (is.null(hasil_adf)) {
      return(data.frame(
        Dataset = nama_dataset,
        Variabel = nama,
        N = n,
        `Statistik ADF` = NA_real_,
        `P-value` = NA_real_,
        Kesimpulan = "Uji gagal",
        check.names = FALSE
      ))
    }

    stat <- as.numeric(hasil_adf@teststat[1, "tau2"])
    cval <- hasil_adf@cval["tau2", ]
    pval <- pvalue_mackinnon(stat, n)
    stasioner <- stat < cval["5pct"]

    data.frame(
      Dataset = nama_dataset,
      Variabel = nama,
      N = n,
      `Statistik ADF` = stat,
      `P-value` = pval,
      Kesimpulan = ifelse(stasioner, "Stasioner", "Tidak stasioner"),
      check.names = FALSE
    )
  })

  bind_rows(hasil)
}


# ------------------------------------------------------------
# 4. FUNGSI FORMAT TABEL GAYA EVIEWS
# ------------------------------------------------------------

tabel_eviews <- function(hasil, judul) {

  df_tampil <- hasil %>%
    mutate(
      `P-value` = ifelse(is.na(`P-value`), "NA",
                         formatC(`P-value`, format = "f", digits = 4)),
      `Statistik ADF` = formatC(`Statistik ADF`, format = "f", digits = 6)
    )

  knitr::kable(
    df_tampil,
    col.names = c("Dataset", "Variabel", "Obs",
                  "t-Statistic", "Prob.*", "Kesimpulan"),
    caption = judul,
    align = c("l", "l", "r", "r", "r", "l")
  )
}


# ------------------------------------------------------------
# 5. UJI ADF DATA LEVEL
# ------------------------------------------------------------

hasil_level <- uji_adf_eviews(
  dataset = data_level,
  nama_dataset = "Level"
)

tabel_eviews(
  hasil_level,
  "Augmented Dickey-Fuller Unit Root Test - Level (Intercept)"
)
Augmented Dickey-Fuller Unit Root Test - Level (Intercept)
Dataset Variabel Obs t-Statistic Prob.* Kesimpulan
5pct…1 Level LPDB 45 -0.715963 0.4262 Tidak stasioner
5pct…2 Level RULN 45 -2.282055 0.1554 Tidak stasioner
5pct…3 Level FDI 45 -2.647044 0.0931 Tidak stasioner
5pct…4 Level LDEF 45 -2.830056 0.0650 Tidak stasioner
5pct…5 Level LRES 45 -1.254965 0.3330 Tidak stasioner
5pct…6 Level LEMPLOYMENT 45 -3.713029 0.0000 Stasioner
5pct…7 Level TOT 45 -3.215208 0.0056 Stasioner
5pct…8 Level LEXCHANGE 45 -1.727680 0.2512 Tidak stasioner
# ------------------------------------------------------------
# 6. UJI ADF DATA FIRST DIFFERENCE
# ------------------------------------------------------------

hasil_diff <- uji_adf_eviews(
  dataset = data_diff,
  nama_dataset = "First Difference"
)

tabel_eviews(
  hasil_diff,
  "Augmented Dickey-Fuller Unit Root Test - First Difference (Intercept)"
)
Augmented Dickey-Fuller Unit Root Test - First Difference (Intercept)
Dataset Variabel Obs t-Statistic Prob.* Kesimpulan
5pct…1 First Difference d_LPDB 44 -4.139761 0.0000 Stasioner
5pct…2 First Difference d_RULN 44 -4.580529 0.0000 Stasioner
5pct…3 First Difference d_FDI 44 -4.657713 0.0000 Stasioner
5pct…4 First Difference d_LDEF 44 -5.012285 0.0000 Stasioner
5pct…5 First Difference d_LRES 44 -5.522325 0.0000 Stasioner
5pct…6 First Difference d_LEMPLOYMENT 44 -3.845244 0.0000 Stasioner
5pct…7 First Difference d_TOT 44 -4.044882 0.0000 Stasioner
5pct…8 First Difference d_LEXCHANGE 44 -4.849907 0.0000 Stasioner

4 Persamaan GDP

lag_d_RULN <- lag(data$d_RULN)
lag_d_LPDB <- lag(data$d_LPDB)

eq_gdp <- ivreg2(
  d_LPDB ~
    d_FDI +
    d_LEMPLOYMENT +
    d_LRES
  |
    d_RULN
  |
    d_LEXCHANGE +
    d_TOT +
    d_LDEF,
  data = data,
  vcov = "iid"
)

summary(eq_gdp)
## 
## 2SLS Estimation
## 
## Call:
## ivreg2(formula = d_LPDB ~ d_FDI + d_LEMPLOYMENT + d_LRES | d_RULN | 
##     d_LEXCHANGE + d_TOT + d_LDEF, data = data, vcov = "iid")
## 
## Observations: 44 
## VCV type:     Classical (iid) 
## 
## Coefficients:
##                Estimate Std. Error z value Pr(>|z|)    
## (Intercept)    0.033492   0.007387   4.534 5.79e-06 ***
## d_RULN        -0.013887   0.002948  -4.710 2.48e-06 ***
## d_FDI          0.013139   0.005117   2.568  0.01023 *  
## d_LEMPLOYMENT  0.723710   0.257441   2.811  0.00494 ** 
## d_LRES         0.031478   0.033181   0.949  0.34278    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## ---
## R-squared:      0.2959 
## Adj. R-squared: 0.2237 
## Wald chi2(4):  8.3 (p = 0.0001)
## Root MSE:       0.0282 
## 
## Underidentification test (Anderson canon. corr. LM statistic):
##   Chi-sq(3) = 22.64 (p = 0.0000)
## 
## Weak identification test:
##   Cragg-Donald Wald F:           13.07 
##   Stock-Yogo critical values (IV size):
##      10%  maximal IV size       22.30 
##      15%  maximal IV size       12.83 
##      20%  maximal IV size       9.54 
##      25%  maximal IV size       7.80 
##   Stock-Yogo critical values (IV relative bias):
##      5%  maximal IV relative bias   13.91 
##      10%  maximal IV relative bias   9.08 
##      20%  maximal IV relative bias   6.46 
##      30%  maximal IV relative bias   5.39 
## 
## Overidentification test (Sargan):
##   Chi-sq(2) = 3.92 (p = 0.1407)
## 
## Weak-instrument-robust inference:
##   H0: B1=0 and orthogonality conditions are valid
##   Anderson-Rubin Wald F(3,37) = 15.31 (p = 0.0000)
##   Anderson-Rubin Wald Chi-sq(3) = 54.61 (p = 0.0000)
##   Stock-Wright LM S Chi-sq(3) = 24.37 (p = 0.0000)
## 
## Endogeneity test:
##   Chi-sq(1) = 12.44 (p = 0.0004)
##   Tested: d_RULN
## 
## First-stage diagnostics:
##   Endogenous        F-stat   p-value  Partial R2  Shea PR2      SW F      AP F
##   d_RULN             13.07    0.0000      0.5146    0.5146     13.07     13.07
## 
## Instrumented:          d_RULN 
## Included instruments:  d_FDI, d_LEMPLOYMENT, d_LRES 
## Excluded instruments:  d_LEXCHANGE, d_TOT, d_LDEF

4.1 Uji Asumsi Normalitas

# Ambil residual model IV
resid_gdp <- residuals(eq_gdp)

# Uji normalitas Jarque-Bera
jarque.bera.test(resid_gdp)
## 
##  Jarque Bera Test
## 
## data:  resid_gdp
## X-squared = 1.6889, df = 2, p-value = 0.4298

4.2 Uji Asumsi Homoskedastisitas

# 1. Ambil sampel estimasi dan residual model 2SLS
mf <- model.frame(eq_gdp)
res <- as.numeric(residuals(eq_gdp))

# 2. Bentuk data regresi bantu
bp_data_gdp <- data.frame(
  res2 = res^2,
  d_RULN = mf$d_RULN,
  d_FDI = mf$d_FDI,
  d_LEMPLOYMENT = mf$d_LEMPLOYMENT,
  d_LRES = mf$d_LRES
)

# 3. Regresi bantu BP
aux_bp_gdp <- lm(
  res2 ~ d_RULN + d_FDI +
    d_LEMPLOYMENT + d_LRES,
  data = bp_data_gdp
)

# 4. Statistik LM = n * R-squared
LM_BP_gdp <- nobs(aux_bp_gdp) * summary(aux_bp_gdp)$r.squared

# 5. p-value Chi-square
p_BP_gdp <- pchisq(
  LM_BP_gdp,
  df = 4,
  lower.tail = FALSE
)

# 6. Tampilkan hasil
cat("Breusch-Pagan Test - Persamaan GDP\n")
## Breusch-Pagan Test - Persamaan GDP
cat("LM statistic:", LM_BP_gdp, "\n")
## LM statistic: 0.5276542
cat("df:", 4, "\n")
## df: 4
cat("Prob. Chi-Square:", p_BP_gdp, "\n")
## Prob. Chi-Square: 0.9707536

4.3 Uji Asumsi Non-Autokorelasi

bgtest(eq_gdp)
## 
##  Breusch-Godfrey test for serial correlation of order up to 1
## 
## data:  eq_gdp
## LM test = 3.6325, df = 1, p-value = 0.05666

4.4 Syarat Non-Multikolinieritas

# Data sesuai sampel estimasi
mf_gdp <- model.frame(eq_gdp)

# Regresi bantu untuk menghitung VIF
aux_gdp <- lm(
  d_LPDB ~ d_RULN + d_FDI +
    d_LEMPLOYMENT + d_LRES,
  data = mf_gdp
)

# Nilai VIF
vif(aux_gdp)
##        d_RULN         d_FDI d_LEMPLOYMENT        d_LRES 
##      1.213540      1.043241      1.108079      1.098211

5 Persamaan ULN

lag_d_LPDB <- lag(data$d_LPDB)
lag_d_RULN <- lag(data$d_RULN)

eq_uln <- ivreg2(
  d_RULN ~
    lag_d_RULN +
    d_LEXCHANGE +
    d_LDEF +
    d_TOT +
    d_LRES
  |
    d_LPDB
  |
    d_LEMPLOYMENT +
    d_FDI +
    lag_d_LPDB,
  data = data,
  vcov = "iid"
)

summary(eq_uln)
## 
## 2SLS Estimation
## 
## Call:
## ivreg2(formula = d_RULN ~ lag_d_RULN + d_LEXCHANGE + d_LDEF + 
##     d_TOT + d_LRES | d_LPDB | d_LEMPLOYMENT + d_FDI + lag_d_LPDB, 
##     data = data, vcov = "iid")
## 
## Observations: 43 
## VCV type:     Classical (iid) 
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)    
## (Intercept) -2.76289    0.96629  -2.859  0.00425 ** 
## d_LPDB      40.63598   16.27648   2.497  0.01254 *  
## lag_d_RULN   0.24487    0.11513   2.127  0.03343 *  
## d_LEXCHANGE 10.38662    2.32348   4.470 7.81e-06 ***
## d_LDEF      -1.73402    0.58266  -2.976  0.00292 ** 
## d_TOT       -0.05942    0.02354  -2.525  0.01158 *  
## d_LRES       4.69292    1.82980   2.565  0.01033 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## ---
## R-squared:      0.4908 
## Adj. R-squared: 0.4059 
## Wald chi2(6):  7.8 (p = 0.0000)
## Root MSE:       1.6000 
## 
## Underidentification test (Anderson canon. corr. LM statistic):
##   Chi-sq(3) = 20.92 (p = 0.0001)
## 
## Weak identification test:
##   Cragg-Donald Wald F:           10.74 
##   Stock-Yogo critical values (IV size):
##      10%  maximal IV size       22.30 
##      15%  maximal IV size       12.83 
##      20%  maximal IV size       9.54 
##      25%  maximal IV size       7.80 
##   Stock-Yogo critical values (IV relative bias):
##      5%  maximal IV relative bias   13.91 
##      10%  maximal IV relative bias   9.08 
##      20%  maximal IV relative bias   6.46 
##      30%  maximal IV relative bias   5.39 
## 
## Overidentification test (Sargan):
##   Chi-sq(2) = 0.84 (p = 0.6556)
## 
## Weak-instrument-robust inference:
##   H0: B1=0 and orthogonality conditions are valid
##   Anderson-Rubin Wald F(3,34) = 2.89 (p = 0.0497)
##   Anderson-Rubin Wald Chi-sq(3) = 10.96 (p = 0.0120)
##   Stock-Wright LM S Chi-sq(3) = 8.73 (p = 0.0331)
## 
## Endogeneity test:
##   Chi-sq(1) = 10.15 (p = 0.0014)
##   Tested: d_LPDB
## 
## First-stage diagnostics:
##   Endogenous        F-stat   p-value  Partial R2  Shea PR2      SW F      AP F
##   d_LPDB             10.74    0.0000      0.4865    0.4865     10.74     10.74
## 
## Instrumented:          d_LPDB 
## Included instruments:  lag_d_RULN, d_LEXCHANGE, d_LDEF, d_TOT, d_LRES 
## Excluded instruments:  d_LEMPLOYMENT, d_FDI, lag_d_LPDB

5.1 Uji Asumsi Normalitas

# Ambil residual model IV
resid_uln <- residuals(eq_uln)

# Uji normalitas Jarque-Bera
jarque.bera.test(resid_uln)
## 
##  Jarque Bera Test
## 
## data:  resid_uln
## X-squared = 0.13431, df = 2, p-value = 0.9351

5.2 Uji Asumsi Homoskedastisitas

# 1. Ambil sampel estimasi dan residual model 2SLS
mf <- model.frame(eq_uln)
res <- as.numeric(residuals(eq_uln))

# 2. Bentuk data regresi bantu
bp_data_uln <- data.frame(
  res2 = res^2,
  lag_d_RULN = mf$lag_d_RULN,
  d_LEXCHANGE = mf$d_LEXCHANGE,
  d_LDEF = mf$d_LDEF,
  d_TOT = mf$d_TOT,
  d_LRES = mf$d_LRES,
  d_LPDB = mf$d_LPDB
)

# 3. Regresi bantu BP
aux_bp_uln <- lm(
  res2 ~ lag_d_RULN + d_LEXCHANGE +
    d_LDEF + d_TOT + d_LRES + d_LPDB,
  data = bp_data_uln
)

# 4. Statistik LM = n * R-squared
LM_BP_uln <- nobs(aux_bp_uln) * summary(aux_bp_uln)$r.squared

# 5. p-value Chi-square
p_BP_uln <- pchisq(
  LM_BP_uln,
  df = 6,
  lower.tail = FALSE
)

# 6. Tampilkan hasil
cat("Breusch-Pagan Test - Persamaan ULN\n")
## Breusch-Pagan Test - Persamaan ULN
cat("LM statistic:", LM_BP_uln, "\n")
## LM statistic: 3.885615
cat("df:", 6, "\n")
## df: 6
cat("Prob. Chi-Square:", p_BP_uln, "\n")
## Prob. Chi-Square: 0.6921525

5.3 Uji Asumsi Non-Autokorelasi

bgtest(eq_uln)
## 
##  Breusch-Godfrey test for serial correlation of order up to 1
## 
## data:  eq_uln
## LM test = 0.75211, df = 1, p-value = 0.3858

5.4 Syarat Non-Multikolinieritas

# Data sesuai sampel estimasi
mf_uln <- model.frame(eq_uln)

# Regresi bantu untuk menghitung VIF
aux_uln <- lm(
  d_RULN ~ d_LPDB + lag_d_RULN +
    d_LEXCHANGE + d_LDEF + d_TOT + d_LRES,
  data = mf_uln
)

# Nilai VIF
vif(aux_uln)
##      d_LPDB  lag_d_RULN d_LEXCHANGE      d_LDEF       d_TOT      d_LRES 
##    2.463923    1.106669    2.396716    1.124633    1.222149    1.065291

6 Scatter

dataa <- read_excel(
  "D:/STIS/Semester 7/Skripsi/Data/data skripsi.xlsx",
  sheet = 3
)

ggplot(dataa, aes(x = LEXCHANGE, y = ULN_PERCENTOFGDP)) +
  geom_point(
    shape = 21, fill = "#5DA5DA", color = "#1F4E79",
    size = 3, alpha = 0.8, stroke = 0.8
  ) +
  geom_smooth(
    method = "lm", se = TRUE, color = "#1F4E79",
    fill = "#A8C8E8", alpha = 0.25, linewidth = 1
  ) +
  scale_y_continuous(labels = scales::comma) +
  scale_x_continuous(labels = scales::comma) +
  labs(
    x = "Nilai Tukar (Rupiah/US$)",
    y = "Utang Luar Negeri (% terhadap PDB)"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    axis.title = element_text(face = "bold", color = "#1A1A1A"),
    axis.text = element_text(color = "grey30"),
    panel.grid.major = element_line(color = "grey92", linewidth = 0.4),
    panel.grid.minor = element_blank(),
    plot.background = element_rect(fill = "white", color = NA)
  )
## `geom_smooth()` using formula = 'y ~ x'

ggplot(dataa, aes(x = TOT, y = ULN_PERCENTOFGDP)) +
  geom_point(
    shape = 21, fill = "#5DA5DA", color = "#1F4E79",
    size = 3, alpha = 0.8, stroke = 0.8
  ) +
  geom_smooth(
    method = "lm", se = TRUE, color = "#1F4E79",
    fill = "#A8C8E8", alpha = 0.25, linewidth = 1
  ) +
  scale_y_continuous(labels = scales::comma) +
  scale_x_continuous(labels = scales::comma) +
  labs(
    x = "Terms of Trade (2000=100)",
    y = "Utang Luar Negeri (% terhadap PDB)"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    axis.title = element_text(face = "bold", color = "#1A1A1A"),
    axis.text = element_text(color = "grey30"),
    panel.grid.major = element_line(color = "grey92", linewidth = 0.4),
    panel.grid.minor = element_blank(),
    plot.background = element_rect(fill = "white", color = NA)
  )
## `geom_smooth()` using formula = 'y ~ x'

ggplot(dataa, aes(x = LDEF, y = ULN_PERCENTOFGDP)) +
  geom_point(
    shape = 21, fill = "#5DA5DA", color = "#1F4E79",
    size = 3, alpha = 0.8, stroke = 0.8
  ) +
  geom_smooth(
    method = "lm", se = TRUE, color = "#1F4E79",
    fill = "#A8C8E8", alpha = 0.25, linewidth = 1
  ) +
  scale_y_continuous(labels = scales::comma) +
  scale_x_continuous(labels = scales::comma) +
  labs(
    x = "Defisit Anggaran (Milyar Rupiah)",
    y = "Utang Luar Negeri (% terhadap PDB)"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    axis.title = element_text(face = "bold", color = "#1A1A1A"),
    axis.text = element_text(color = "grey30"),
    panel.grid.major = element_line(color = "grey92", linewidth = 0.4),
    panel.grid.minor = element_blank(),
    plot.background = element_rect(fill = "white", color = NA)
  )
## `geom_smooth()` using formula = 'y ~ x'

ggplot(dataa, aes(x = LRES, y = ULN_PERCENTOFGDP)) +
  geom_point(
    shape = 21, fill = "#5DA5DA", color = "#1F4E79",
    size = 3, alpha = 0.8, stroke = 0.8
  ) +
  geom_smooth(
    method = "lm", se = TRUE, color = "#1F4E79",
    fill = "#A8C8E8", alpha = 0.25, linewidth = 1
  ) +
  scale_y_continuous(labels = scales::comma) +
  scale_x_continuous(
    labels = label_number(scale = 1e-9, accuracy = 1),
    name = "Cadangan Devisa (Milyar US$)"
  ) +
  labs(y = "Utang Luar Negeri (% terhadap PDB)") +
  theme_minimal(base_size = 13) +
  theme(
    axis.title = element_text(face = "bold", color = "#1A1A1A"),
    axis.text = element_text(color = "grey30"),
    panel.grid.major = element_line(color = "grey92", linewidth = 0.4),
    panel.grid.minor = element_blank(),
    plot.background = element_rect(fill = "white", color = NA)
  )
## `geom_smooth()` using formula = 'y ~ x'

ggplot(dataa, aes(x = FDI, y = LGDP)) +
  geom_point(
    shape = 21, fill = "#7BC96F", color = "#1B5E20",
    size = 3, alpha = 0.8, stroke = 0.8
  ) +
  geom_smooth(
    method = "lm", se = TRUE, color = "#2E7D32",
    fill = "#A5D6A7", alpha = 0.25, linewidth = 1
  ) +
  scale_y_continuous(
    labels = label_number(scale = 1e-9, suffix = "", accuracy = 1),
    name = "Pertumbuhan Ekonomi (Milyar US$)"
  ) +
  scale_x_continuous(labels = scales::comma) +
  labs(x = "Foreign Direct Investment (% terhadap PDB)") +
  theme_minimal(base_size = 13) +
  theme(
    axis.title = element_text(face = "bold", color = "#1A1A1A"),
    axis.text = element_text(color = "grey30"),
    panel.grid.major = element_line(color = "grey92", linewidth = 0.4),
    panel.grid.minor = element_blank(),
    plot.background = element_rect(fill = "white", color = NA)
  )
## `geom_smooth()` using formula = 'y ~ x'

ggplot(dataa, aes(x = LEMPLOYMENT, y = LGDP)) +
  geom_point(
    shape = 21, fill = "#7BC96F", color = "#1B5E20",
    size = 3, alpha = 0.8, stroke = 0.8
  ) +
  geom_smooth(
    method = "lm", se = TRUE, color = "#2E7D32",
    fill = "#A5D6A7", alpha = 0.25, linewidth = 1
  ) +
  scale_y_continuous(
    labels = label_number(scale = 1e-9, suffix = "", accuracy = 1),
    name = "Pertumbuhan Ekonomi (Milyar US$)"
  ) +
  scale_x_continuous(
    labels = label_number(scale = 1e-6, accuracy = 1),
    name = "Jumlah Angkatan Kerja (Juta Jiwa)"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    axis.title = element_text(face = "bold", color = "#1A1A1A"),
    axis.text = element_text(color = "grey30"),
    panel.grid.major = element_line(color = "grey92", linewidth = 0.4),
    panel.grid.minor = element_blank(),
    plot.background = element_rect(fill = "white", color = NA)
  )
## `geom_smooth()` using formula = 'y ~ x'

ggplot(dataa, aes(x = LRES, y = LGDP)) +
  geom_point(
    shape = 21, fill = "#7BC96F", color = "#1B5E20",
    size = 3, alpha = 0.8, stroke = 0.8
  ) +
  geom_smooth(
    method = "lm", se = TRUE, color = "#2E7D32",
    fill = "#A5D6A7", alpha = 0.25, linewidth = 1
  ) +
  scale_y_continuous(
    labels = label_number(scale = 1e-9, suffix = "", accuracy = 1),
    name = "Pertumbuhan Ekonomi (Milyar US$)"
  ) +
  scale_x_continuous(
    labels = label_number(scale = 1e-9, accuracy = 1),
    name = "Cadangan Devisa (Milyar US$)"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    axis.title = element_text(face = "bold", color = "#1A1A1A"),
    axis.text = element_text(color = "grey30"),
    panel.grid.major = element_line(color = "grey92", linewidth = 0.4),
    panel.grid.minor = element_blank(),
    plot.background = element_rect(fill = "white", color = NA)
  )
## `geom_smooth()` using formula = 'y ~ x'

7 Summary Model

# ============================================================
# SUMMARY MODEL IV/2SLS DAN UJI ASUMSI
# ============================================================



# ------------------------------------------------------------
# 1. FUNGSI KOEFISIEN REGRESI
# ------------------------------------------------------------

ambil_koefisien <- function(model, nama_persamaan) {
  hasil <- broom::tidy(model)

  data.frame(
    Persamaan = nama_persamaan,
    Variabel = hasil$term,
    Koefisien = hasil$estimate,
    `Standar Error` = hasil$std.error,
    Prob = hasil$p.value,
    check.names = FALSE
  )
}

koef_gdp <- ambil_koefisien(eq_gdp, "Persamaan GDP")
koef_uln <- ambil_koefisien(eq_uln, "Persamaan ULN")

# ------------------------------------------------------------
# 2. FUNGSI MERAPIKAN DIAGNOSTIK IV
# ------------------------------------------------------------

rapikan_diagnostik <- function(data, nama_persamaan) {

  # Sesuaikan nama kolom
  nama_kolom <- names(data)

  kolom_uji <- intersect(
    c("test", "diagnostic", "name", "Variabel"),
    nama_kolom
  )[1]

  kolom_stat <- intersect(
    c("statistic", "stat", "Koefisien"),
    nama_kolom
  )[1]

  kolom_prob <- intersect(
    c("p_value", "p.value", "pvalue", "Prob"),
    nama_kolom
  )[1]

  if (is.na(kolom_uji) || is.na(kolom_stat)) {
    stop("Periksa struktur output diagnostics() pada ivreg2r.")
  }

  hasil <- data.frame(
    Persamaan = nama_persamaan,
    Variabel = as.character(data[[kolom_uji]]),
    Koefisien = as.numeric(data[[kolom_stat]]),
    `Standar Error` = NA_real_,
    Prob = if (!is.na(kolom_prob)) {
      as.numeric(data[[kolom_prob]])
    } else {
      NA_real_
    },
    check.names = FALSE
  )

  nama_baru <- c(
    underid = "Underidentification test",
    weak_id = "Weak identification test",
    overid = "Overidentification test (Sargan/Hansen)",
    endogeneity = "Endogeneity test",
    anderson_rubin_f = "Anderson-Rubin F test",
    anderson_rubin_chi2 = "Anderson-Rubin Chi-square test",
    stock_wright = "Stock-Wright test"
  )

  hasil %>%
    filter(Variabel %in% names(nama_baru)) %>%
    mutate(Variabel = unname(nama_baru[Variabel]))
}

diag_gdp <- rapikan_diagnostik(
  as.data.frame(ivreg2r::diagnostics(eq_gdp)),
  "Persamaan GDP"
)

diag_uln <- rapikan_diagnostik(
  as.data.frame(ivreg2r::diagnostics(eq_uln)),
  "Persamaan ULN"
)

# ------------------------------------------------------------
# 3. FUNGSI UJI ASUMSI
# ------------------------------------------------------------

baris_uji <- function(persamaan, nama_uji, statistik, prob) {
  data.frame(
    Persamaan = persamaan,
    Variabel = nama_uji,
    Koefisien = as.numeric(statistik),
    `Standar Error` = NA_real_,
    Prob = as.numeric(prob),
    check.names = FALSE
  )
}

# ============================================================
# 4. PERSAMAAN GDP
# ============================================================

mf_gdp <- model.frame(eq_gdp)
res_gdp <- as.numeric(residuals(eq_gdp))

# Normalitas
jb_gdp <- tseries::jarque.bera.test(res_gdp)

# Heteroskedastisitas: Breusch-Pagan
bp_data_gdp <- data.frame(
  res2 = res_gdp^2,
  d_RULN = mf_gdp$d_RULN,
  d_FDI = mf_gdp$d_FDI,
  d_LEMPLOYMENT = mf_gdp$d_LEMPLOYMENT,
  d_LRES = mf_gdp$d_LRES
)

aux_bp_gdp <- lm(
  res2 ~ d_RULN + d_FDI + d_LEMPLOYMENT + d_LRES,
  data = bp_data_gdp
)

LM_BP_gdp <- nobs(aux_bp_gdp) * summary(aux_bp_gdp)$r.squared
p_BP_gdp <- pchisq(LM_BP_gdp, df = 4, lower.tail = FALSE)

# Autokorelasi: Breusch-Godfrey orde 1
bg_gdp <- lmtest::bgtest(eq_gdp, order = 1, type = "Chisq")

# Multikolinearitas: VIF dari OLS bantu
aux_gdp <- lm(
  d_LPDB ~ d_RULN + d_FDI + d_LEMPLOYMENT + d_LRES,
  data = mf_gdp
)

vif_gdp <- car::vif(aux_gdp)

uji_asumsi_gdp <- bind_rows(
  baris_uji(
    "Persamaan GDP", "Normalitas (Jarque-Bera)",
    jb_gdp$statistic, jb_gdp$p.value
  ),
  baris_uji(
    "Persamaan GDP", "Heteroskedastisitas (Breusch-Pagan)",
    LM_BP_gdp, p_BP_gdp
  ),
  baris_uji(
    "Persamaan GDP", "Autokorelasi (Breusch-Godfrey)",
    bg_gdp$statistic, bg_gdp$p.value
  ),
  data.frame(
    Persamaan = "Persamaan GDP",
    Variabel = paste0("VIF: ", names(vif_gdp)),
    Koefisien = as.numeric(vif_gdp),
    `Standar Error` = NA_real_,
    Prob = NA_real_,
    check.names = FALSE
  )
)

# ============================================================
# 5. PERSAMAAN ULN
# ============================================================

mf_uln <- model.frame(eq_uln)
res_uln <- as.numeric(residuals(eq_uln))

# Normalitas
jb_uln <- tseries::jarque.bera.test(res_uln)

# Heteroskedastisitas: Breusch-Pagan
bp_data_uln <- data.frame(
  res2 = res_uln^2,
  lag_d_RULN = mf_uln$lag_d_RULN,
  d_LEXCHANGE = mf_uln$d_LEXCHANGE,
  d_LDEF = mf_uln$d_LDEF,
  d_TOT = mf_uln$d_TOT,
  d_LRES = mf_uln$d_LRES,
  d_LPDB = mf_uln$d_LPDB
)

aux_bp_uln <- lm(
  res2 ~ lag_d_RULN + d_LEXCHANGE + d_LDEF +
    d_TOT + d_LRES + d_LPDB,
  data = bp_data_uln
)

LM_BP_uln <- nobs(aux_bp_uln) * summary(aux_bp_uln)$r.squared
p_BP_uln <- pchisq(LM_BP_uln, df = 6, lower.tail = FALSE)

# Autokorelasi: Breusch-Godfrey orde 1
bg_uln <- lmtest::bgtest(eq_uln, order = 1, type = "Chisq")

# Multikolinearitas: VIF dari OLS bantu
aux_uln <- lm(
  d_RULN ~ d_LPDB + lag_d_RULN + d_LEXCHANGE +
    d_LDEF + d_TOT + d_LRES,
  data = mf_uln
)

vif_uln <- car::vif(aux_uln)

uji_asumsi_uln <- bind_rows(
  baris_uji(
    "Persamaan ULN", "Normalitas (Jarque-Bera)",
    jb_uln$statistic, jb_uln$p.value
  ),
  baris_uji(
    "Persamaan ULN", "Heteroskedastisitas (Breusch-Pagan)",
    LM_BP_uln, p_BP_uln
  ),
  baris_uji(
    "Persamaan ULN", "Autokorelasi (Breusch-Godfrey)",
    bg_uln$statistic, bg_uln$p.value
  ),
  data.frame(
    Persamaan = "Persamaan ULN",
    Variabel = paste0("VIF: ", names(vif_uln)),
    Koefisien = as.numeric(vif_uln),
    `Standar Error` = NA_real_,
    Prob = NA_real_,
    check.names = FALSE
  )
)

# ------------------------------------------------------------
# 6. GABUNGKAN HASIL PERSAMAAN GDP
# ------------------------------------------------------------

summary_gdp <- bind_rows(
  koef_gdp,
  diag_gdp,
  uji_asumsi_gdp
) %>%
  mutate(
    Koefisien = round(Koefisien, 4),
    `Standar Error` = round(`Standar Error`, 4),
    Prob = round(Prob, 4)
  )

# ------------------------------------------------------------
# 7. GABUNGKAN HASIL PERSAMAAN ULN
# ------------------------------------------------------------

summary_uln <- bind_rows(
  koef_uln,
  diag_uln,
  uji_asumsi_uln
) %>%
  mutate(
    Koefisien = round(Koefisien, 4),
    `Standar Error` = round(`Standar Error`, 4),
    Prob = round(Prob, 4)
  )

# ------------------------------------------------------------
# 8. TABEL RINGKASAN PERSAMAAN GDP
# ------------------------------------------------------------

knitr::kable(
  summary_gdp,
  caption = "Ringkasan Model IV/2SLS dan Uji Asumsi Persamaan GDP",
  col.names = c(
    "Persamaan",
    "Variabel/Pengujian",
    "Koefisien/Statistik",
    "Standar Error",
    "Prob."
  ),
  digits = 4,
  na = "-"
)
Ringkasan Model IV/2SLS dan Uji Asumsi Persamaan GDP
Persamaan Variabel/Pengujian Koefisien/Statistik Standar Error Prob.
Persamaan GDP (Intercept) 0.0335 0.0074 0.0000
Persamaan GDP d_RULN -0.0139 0.0029 0.0000
Persamaan GDP d_FDI 0.0131 0.0051 0.0102
Persamaan GDP d_LEMPLOYMENT 0.7237 0.2574 0.0049
Persamaan GDP d_LRES 0.0315 0.0332 0.3428
Persamaan GDP Underidentification test 22.6416 NA 0.0000
Persamaan GDP Weak identification test 13.0743 NA NA
Persamaan GDP Overidentification test (Sargan/Hansen) 3.9221 NA 0.1407
Persamaan GDP Anderson-Rubin F test 15.3083 NA 0.0000
Persamaan GDP Anderson-Rubin Chi-square test 54.6134 NA 0.0000
Persamaan GDP Stock-Wright test 24.3678 NA 0.0000
Persamaan GDP Endogeneity test 12.4412 NA 0.0004
Persamaan GDP Normalitas (Jarque-Bera) 1.6889 NA 0.4298
Persamaan GDP Heteroskedastisitas (Breusch-Pagan) 0.5277 NA 0.9708
Persamaan GDP Autokorelasi (Breusch-Godfrey) 3.6325 NA 0.0567
Persamaan GDP VIF: d_RULN 1.2135 NA NA
Persamaan GDP VIF: d_FDI 1.0432 NA NA
Persamaan GDP VIF: d_LEMPLOYMENT 1.1081 NA NA
Persamaan GDP VIF: d_LRES 1.0982 NA NA
# ------------------------------------------------------------
# 9. TABEL RINGKASAN PERSAMAAN ULN
# ------------------------------------------------------------

knitr::kable(
  summary_uln,
  caption = "Ringkasan Model IV/2SLS dan Uji Asumsi Persamaan ULN",
  col.names = c(
    "Persamaan",
    "Variabel/Pengujian",
    "Koefisien/Statistik",
    "Standar Error",
    "Prob."
  ),
  digits = 4,
  na = "-"
)
Ringkasan Model IV/2SLS dan Uji Asumsi Persamaan ULN
Persamaan Variabel/Pengujian Koefisien/Statistik Standar Error Prob.
Persamaan ULN (Intercept) -2.7629 0.9663 0.0042
Persamaan ULN d_LPDB 40.6360 16.2765 0.0125
Persamaan ULN lag_d_RULN 0.2449 0.1151 0.0334
Persamaan ULN d_LEXCHANGE 10.3866 2.3235 0.0000
Persamaan ULN d_LDEF -1.7340 0.5827 0.0029
Persamaan ULN d_TOT -0.0594 0.0235 0.0116
Persamaan ULN d_LRES 4.6929 1.8298 0.0103
Persamaan ULN Underidentification test 20.9188 NA 0.0001
Persamaan ULN Weak identification test 10.7368 NA NA
Persamaan ULN Overidentification test (Sargan/Hansen) 0.8445 NA 0.6556
Persamaan ULN Anderson-Rubin F test 2.8883 NA 0.0497
Persamaan ULN Anderson-Rubin Chi-square test 10.9587 NA 0.0120
Persamaan ULN Stock-Wright test 8.7331 NA 0.0331
Persamaan ULN Endogeneity test 10.1477 NA 0.0014
Persamaan ULN Normalitas (Jarque-Bera) 0.1343 NA 0.9351
Persamaan ULN Heteroskedastisitas (Breusch-Pagan) 3.8856 NA 0.6922
Persamaan ULN Autokorelasi (Breusch-Godfrey) 0.7521 NA 0.3858
Persamaan ULN VIF: d_LPDB 2.4639 NA NA
Persamaan ULN VIF: lag_d_RULN 1.1067 NA NA
Persamaan ULN VIF: d_LEXCHANGE 2.3967 NA NA
Persamaan ULN VIF: d_LDEF 1.1246 NA NA
Persamaan ULN VIF: d_TOT 1.2221 NA NA
Persamaan ULN VIF: d_LRES 1.0653 NA NA