R Markdown
library(kardl)
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.4 ✔ tidyr 1.3.1
## ✔ purrr 1.0.4
## ── 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(readxl)
library(kardl)
library(lmtest)
## Loading required package: zoo
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
library(car)
## Loading required package: carData
##
## Attaching package: 'car'
## The following object is masked from 'package:dplyr':
##
## recode
## The following object is masked from 'package:purrr':
##
## some
# Read the pi data (assumed to be the same for all sections)
# Initialize an empty data frame to store results
results <- data.frame(
Section = character(),
Intercept = numeric(),
L1.lpitr_POS = numeric(),
L1.lpitr_NEG = numeric(),
L1.lrer_POS = numeric(),
L1.lrer_NEG = numeric(),
F_stat = numeric(),
RESET_F = numeric(),
PSS_F = numeric(),
LM_stat = numeric(),
Wald_lpitr = numeric(),
Wald_lrer = numeric(),
R_squared = numeric(),
# Add columns for p-values
p_Intercept = numeric(),
p_L1.lpitr_POS = numeric(),
p_L1.lpitr_NEG = numeric(),
p_L1.lrer_POS = numeric(),
p_L1.lrer_NEG = numeric(),
p_F_stat = numeric(),
p_RESET_F = numeric(),
p_PSS_F = numeric(),
p_LM_stat = numeric(),
p_Wald_lpitr = numeric(),
p_Wald_lrer = numeric(),
stringsAsFactors = FALSE
)
for (i in 1:21) {
tryCatch({
cat("Processing section", i, "\n")
section_data <- read_excel(paste0("section", i, ".xlsx"))
df <- bind_cols(section_data, pi)
# Filter out invalid rows
df <- df %>%
filter(EXPTR > 0 & !is.na(EXPTR) &
RER > 0 & !is.na(RER) &
TurPI > 0 & !is.na(TurPI) &
GerPI > 0 & !is.na(GerPI)) %>%
mutate(exptr = ifelse(EXPTR < 1000, EXPTR * 1000, EXPTR))
# Transformations
df$lexpger <- log(df$exptr)
df$lrer <- log(df$RER)
df$lpitr <- log(df$TurPI)
df$lpitr <- log(df$GerPI)
# Check logged variables
if (any(is.na(df$lexpger)) || any(is.na(df$lrer)) || any(is.na(df$lpitr)) ||
any(is.infinite(df$lexpger)) || any(is.infinite(df$lrer)) || any(is.infinite(df$lpitr))) {
warning(paste("Section", i, "still has NA/Inf in model variables after filtering"))
next
}
# Fit the model
kardl_m <- kardl(df, lexpger ~ trend + asym(lpitr + lrer), maxlag = 3, mode = "performance")
# Extract coefficients
coef_names <- c("(Intercept)", "L1.lpitr_POS", "L1.lpitr_NEG", "L1.lrer_POS", "L1.lrer_NEG")
coefs <- kardl_m$finalModel$model$coefficients[coef_names]
# Extract p-values for coefficients
sum_model <- summary(kardl_m$finalModel$model)
# Make sure to handle potential missing coefficients
coef_p_values <- rep(NA, length(coef_names))
names(coef_p_values) <- coef_names
for (name in coef_names) {
if (name %in% rownames(sum_model$coefficients)) {
coef_p_values[name] <- sum_model$coefficients[name, "Pr(>|t|)"]
}
}
# Get F-statistic, p-value, and R-squared
F_stat <- sum_model$fstatistic[1]
F_p_value <- pf(sum_model$fstatistic[1], sum_model$fstatistic[2], sum_model$fstatistic[3], lower.tail = FALSE)
R_squared <- sum_model$r.squared
# Perform RESET test
reset_test <- resettest(kardl_m$finalModel$model)
RESET_F <- reset_test$statistic[1]
RESET_p <- reset_test$p.value
# Perform PSS F-test for cointegration
hypothesis <- c("L1.lexpger = 0", "L1.lpitr_POS = 0", "L1.lpitr_NEG = 0",
"L1.lrer_POS = 0", "L1.lrer_NEG = 0")
wald_test <- linearHypothesis(kardl_m$finalModel$model, hypothesis)
PSS_F <- wald_test[2, "F"]
PSS_p <- wald_test[2, "Pr(>F)"]
# Perform LM test for serial correlation
lm_test <- bgtest(kardl_m$finalModel$model, order = 1)
LM_stat <- lm_test$statistic
LM_p <- lm_test$p.value
# Perform asymmetry tests and extract Wald F-statistics and p-values
ast <- asymmetrytest(kardl_m)
# The asymmetry test results have columns "F" and "P" (not "Pr(>F)")
Wald_lpitr <- ast$Lwald["lpitr", "F"]
Wald_lpitr_p <- ast$Lwald["lpitr", "P"]
Wald_lrer <- ast$Lwald["lrer", "F"]
Wald_lrer_p <- ast$Lwald["lrer", "P"]
# Collect results into a data frame row
row <- data.frame(
Section = paste("Section", i),
Intercept = coefs["(Intercept)"],
L1.lpitr_POS = coefs["L1.lpitr_POS"],
L1.lpitr_NEG = coefs["L1.lpitr_NEG"],
L1.lrer_POS = coefs["L1.lrer_POS"],
L1.lrer_NEG = coefs["L1.lrer_NEG"],
F_stat = F_stat,
RESET_F = RESET_F,
PSS_F = PSS_F,
LM_stat = LM_stat,
Wald_lpitr = Wald_lpitr,
Wald_lrer = Wald_lrer,
R_squared = R_squared,
# Add p-values
p_Intercept = coef_p_values["(Intercept)"],
p_L1.lpitr_POS = coef_p_values["L1.lpitr_POS"],
p_L1.lpitr_NEG = coef_p_values["L1.lpitr_NEG"],
p_L1.lrer_POS = coef_p_values["L1.lrer_POS"],
p_L1.lrer_NEG = coef_p_values["L1.lrer_NEG"],
p_F_stat = F_p_value,
p_RESET_F = RESET_p,
p_PSS_F = PSS_p,
p_LM_stat = LM_p,
p_Wald_lpitr = Wald_lpitr_p,
p_Wald_lrer = Wald_lrer_p,
stringsAsFactors = FALSE
)
# Append to results
results <- rbind(results, row)
cat("Completed section", i, "\n")
}, error = function(e) {
warning(paste("Error processing section", i, ":", e$message))
})
}
## Processing section 1
## Warning in value[[3L]](cond): Error processing section 1 : `path` does not
## exist: 'section1.xlsx'
## Processing section 2
## Warning in value[[3L]](cond): Error processing section 2 : `path` does not
## exist: 'section2.xlsx'
## Processing section 3
## Warning in value[[3L]](cond): Error processing section 3 : `path` does not
## exist: 'section3.xlsx'
## Processing section 4
## Warning in value[[3L]](cond): Error processing section 4 : `path` does not
## exist: 'section4.xlsx'
## Processing section 5
## Warning in value[[3L]](cond): Error processing section 5 : `path` does not
## exist: 'section5.xlsx'
## Processing section 6
## Warning in value[[3L]](cond): Error processing section 6 : `path` does not
## exist: 'section6.xlsx'
## Processing section 7
## Warning in value[[3L]](cond): Error processing section 7 : `path` does not
## exist: 'section7.xlsx'
## Processing section 8
## Warning in value[[3L]](cond): Error processing section 8 : `path` does not
## exist: 'section8.xlsx'
## Processing section 9
## Warning in value[[3L]](cond): Error processing section 9 : `path` does not
## exist: 'section9.xlsx'
## Processing section 10
## Warning in value[[3L]](cond): Error processing section 10 : `path` does not
## exist: 'section10.xlsx'
## Processing section 11
## Warning in value[[3L]](cond): Error processing section 11 : `path` does not
## exist: 'section11.xlsx'
## Processing section 12
## Warning in value[[3L]](cond): Error processing section 12 : `path` does not
## exist: 'section12.xlsx'
## Processing section 13
## Warning in value[[3L]](cond): Error processing section 13 : `path` does not
## exist: 'section13.xlsx'
## Processing section 14
## Warning in value[[3L]](cond): Error processing section 14 : `path` does not
## exist: 'section14.xlsx'
## Processing section 15
## Warning in value[[3L]](cond): Error processing section 15 : `path` does not
## exist: 'section15.xlsx'
## Processing section 16
## Warning in value[[3L]](cond): Error processing section 16 : `path` does not
## exist: 'section16.xlsx'
## Processing section 17
## Warning in value[[3L]](cond): Error processing section 17 : `path` does not
## exist: 'section17.xlsx'
## Processing section 18
## Warning in value[[3L]](cond): Error processing section 18 : `path` does not
## exist: 'section18.xlsx'
## Processing section 19
## Warning in value[[3L]](cond): Error processing section 19 : `path` does not
## exist: 'section19.xlsx'
## Processing section 20
## Warning in value[[3L]](cond): Error processing section 20 : `path` does not
## exist: 'section20.xlsx'
## Processing section 21
## Warning in value[[3L]](cond): Error processing section 21 : `path` does not
## exist: 'section21.xlsx'
# Convert numeric columns to numeric (in case of any coercion)
numeric_cols <- names(results)[2:23]
results[, numeric_cols] <- lapply(results[, numeric_cols], as.numeric)
# Create a function to add significance stars
add_stars <- function(value, p_value) {
if (is.na(value) || is.na(p_value)) return(as.character(round(value, 4)))
stars <- ""
if (p_value < 0.01) stars <- "***"
else if (p_value < 0.05) stars <- "**"
else if (p_value < 0.1) stars <- "*"
return(paste0(round(value, 4), stars))
}
# Create a new results table with stars
results_with_stars <- data.frame(
Section = results$Section,
Intercept = mapply(add_stars, results$Intercept, results$p_Intercept),
L1.lpitr_POS = mapply(add_stars, results$L1.lpitr_POS, results$p_L1.lpitr_POS),
L1.lpitr_NEG = mapply(add_stars, results$L1.lpitr_NEG, results$p_L1.lpitr_NEG),
L1.lrer_POS = mapply(add_stars, results$L1.lrer_POS, results$p_L1.lrer_POS),
L1.lrer_NEG = mapply(add_stars, results$L1.lrer_NEG, results$p_L1.lrer_NEG),
F_stat = mapply(add_stars, results$F_stat, results$p_F_stat),
RESET_F = mapply(add_stars, results$RESET_F, results$p_RESET_F),
PSS_F = mapply(add_stars, results$PSS_F, results$p_PSS_F),
LM_stat = mapply(add_stars, results$LM_stat, results$p_LM_stat),
Wald_lpitr = mapply(add_stars, results$Wald_lpitr, results$p_Wald_lpitr),
Wald_lrer = mapply(add_stars, results$Wald_lrer, results$p_Wald_lrer),
R_squared = round(results$R_squared, 4)
)
# View the resulting table with significance indicators
print(results_with_stars)
## [1] Section R_squared
## <0 rows> (or 0-length row.names)
# Optional: Write to CSV
write.csv(results_with_stars, "kardl_results_with_significance.csv", row.names = FALSE)