## ----setup, include = FALSE--------------------------------------------------- knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) library("hdMTD") library("dplyr") library("ggplot2") library("lubridate") library("purrr") library("tidyr") replication_dir <- system.file( "extdata", "replication", package = "hdMTD" ) # Allows the vignette to be knitted directly from the package source. if (!nzchar(replication_dir)) { possible_dirs <- c( file.path("inst", "extdata", "replication"), file.path("..", "inst", "extdata", "replication") ) replication_dir <- possible_dirs[dir.exists(possible_dirs)][1] } if (is.na(replication_dir) || !dir.exists(replication_dir)) { stop("Pre-computed replication files were not found.") } precomputed <- readRDS( file.path(replication_dir, "hdMTD_outputs.rds") ) simulated_data <- readRDS( file.path(replication_dir, "simulated_data.rds") ) results_sequential <- readRDS( file.path(replication_dir, "results_sequential_selection.rds") ) ## ----binary-model------------------------------------------------------------- set.seed(11) Lambda <- c(1, 15, 30) A <- c(0, 1) lam0 <- 0.01 lamj <- c(0.39, 0.3, 0.3) p0 <- c(0.5, 0.5) MTD <- MTDmodel(Lambda = Lambda, A = A, lam0 = lam0, lamj = lamj, p0 = p0) summary(MTD) ## ----binary-sample------------------------------------------------------------ X <- perfectSample(MTD, N = 1000) ## ----fs-specific-------------------------------------------------------------- hdMTD_FS(X, d = 40, l = 4) ## ----fs-general--------------------------------------------------------------- FS <- hdMTD(X, d = 40, method = "FS", l = 4) S(FS); summary(FS) ## ----bic-unrestricted, eval=FALSE--------------------------------------------- # BIC_d40_l4 <- hdMTD_BIC(X, d = 40, minl = 4, maxl = 4) # BIC_d40_l4 ## ----bic-unrestricted-output, echo=FALSE-------------------------------------- BIC_d40_l4 <- precomputed$BIC_d40_l4 print(BIC_d40_l4) ## ----bic-custom-set----------------------------------------------------------- hdMTD_BIC(X, d = 40, S = c(1, 5, 10, 15, 17, 20, 27, 30, 35, 40), minl = 4, maxl = 4) ## ----bic-variable-size-------------------------------------------------------- hdMTD_BIC(X, d = 40, S = c(1, 5, 10, 15, 17, 20, 27, 30, 35, 40), minl = 1, maxl = 4) ## ----bic-by-size-------------------------------------------------------------- hdMTD_BIC(X, d = 40, S = c(1, 5, 10, 15, 17, 20, 27, 30, 35, 40), minl = 1, maxl = 4, byl = TRUE, BICvalue = TRUE) ## ----bic-xi------------------------------------------------------------------- hdMTD_BIC(X, d = 40, S = c(1, 5, 10, 15, 17, 20, 27, 30, 35, 40), minl = 1, maxl = 4, byl = TRUE, BICvalue = TRUE, xi = 0.4) ## ----bic-single-matrix-------------------------------------------------------- hdMTD_BIC(X, d = 40, S = c(1, 5, 10, 15, 17, 20, 27, 30, 35, 40), minl = 1, maxl = 4, byl = TRUE, BICvalue = TRUE, single_matrix = TRUE, indep_part = FALSE) ## ----cut-full-candidate-set, eval=FALSE--------------------------------------- # CUT_d40 <- hdMTD_CUT( # X, # d = 40, # S = c(1, 5, 10, 15, 17, 20, 27, 30, 35, 40) # ) # CUT_d40 ## ----cut-full-candidate-set-output, echo=FALSE-------------------------------- CUT_d40 <- precomputed$CUT_d40 print(CUT_d40) ## ----cut-alpha, eval=FALSE---------------------------------------------------- # CUT_d40_alpha <- hdMTD_CUT( # X, # d = 40, # S = c(1, 5, 10, 15, 17, 20, 27, 30, 35, 40), # alpha = 0.13 # ) # CUT_d40_alpha ## ----cut-alpha-output, echo=FALSE--------------------------------------------- CUT_d40_alpha <- precomputed$CUT_d40_alpha print(CUT_d40_alpha) ## ----cut-custom-set----------------------------------------------------------- hdMTD_CUT(X, d = 40, S = c(1, 5, 17, 27, 30, 35), alpha = 0.13) ## ----fsc---------------------------------------------------------------------- hdMTD_FSC(X, d = 40, l = 4, alpha = 0.1, cut_fraction = 0.5) ## ----fs-half-sample----------------------------------------------------------- hdMTD_FS(X[501:1000], d = 40, l = 4) ## ----empirical-probabilities-data-frame--------------------------------------- head(empirical_probs(X, S = c(1, 15, 30)), 6) ## ----empirical-probabilities-matrix------------------------------------------- empirical_probs(X, S = c(1, 15, 30), matrixform = TRUE) ## ----true-oscillations-------------------------------------------------------- oscillation(MTD) ## ----estimated-oscillations--------------------------------------------------- oscillation(X, S = c(1, 15, 30)) ## ----em-initial-values-------------------------------------------------------- init <- list( 'lambdas'= c(0.01, 0.33, 0.33, 0.33), 'p0' = c(0.5, 0.5), 'pj' = rep(list(matrix(c(0.5, 0.5, 0.5, 0.5), ncol = 2, nrow = 2)), 3) ) ## ----em-fit------------------------------------------------------------------- emMTD <- MTDest(X, S = c(1, 15, 30), init = init, iter = TRUE) summary(emMTD) ## ----em-fixed-iterations------------------------------------------------------ emMTD <- MTDest(X, S = c(1, 15, 30), M = NULL, nIter = 9, init = init, oscillations = TRUE) summary(emMTD) ## ----unnamed-chunk-26--------------------------------------------------------- transitP(emMTD) ## ----three-state-model-------------------------------------------------------- set.seed(11) Lambda3 <- c(2, 5) A3 <- c(1, 2, 3) lam0.3 <- 0.05 lamj.3 <- c(0.20, 0.75) p0.3 <- c(0.30, 0.30, 0.40) MTD3 <- MTDmodel( Lambda = Lambda3, A = A3, lam0 = lam0.3, lamj = lamj.3, p0 = p0.3 ) summary(MTD3) ## ----three-state-sample------------------------------------------------------- Y <- perfectSample(MTD3, N = 2000) oscillation(MTD3) ## ----three-state-fs----------------------------------------------------------- Sfs3 <- hdMTD_FS(Y, d = 20, l = 3) Sfs3 ## ----three-state-bic---------------------------------------------------------- Sbic3 <- hdMTD_BIC(Y, S = Sfs3, d = 20) Sbic3 ## ----three-state-probabilities------------------------------------------------ P3 <- empirical_probs(Y, S = Sbic3, matrixform = TRUE) P3 ## ----simulation-model--------------------------------------------------------- set.seed(123) Lambda <- c(1, 5) A <- c(0, 1) lam0 <- 0.01 p0 <- c(0.5, 0.5) MTD <- MTDmodel(Lambda, A, lam0, p0 = p0) # Generates an MTD model ## ----simulation-settings------------------------------------------------------ n <- 100 # Number of replications N <- 10000 # Full sample size m <- c(1000, 1500, 2000, 2500, 3000, 5000, 10000) # Subsample sizes d <- 100 # Max order for FS and Oracle dNaive <- 5 # Max order for Naive pairList <- t(combn(d, 2)) # All possible pairs with digits from 1 to 100 npairs <- nrow(pairList) minP11_P12 <- min(MTD$P[1, 1], MTD$P[1, 2]) ## ----simulation-recompute, eval=FALSE----------------------------------------- # FS <- matrix(0, ncol = length(m), nrow = n) # Naive <- matrix(0, ncol = length(m), nrow = n) # Oracle <- matrix(0, ncol = length(m), nrow = n) # SFS <- matrix(0, ncol = length(m) * 2, nrow = n) # ZOracle <- matrix(0, ncol = length(m) * 2, nrow = n) # # X_list <- vector("list", n) # for (i in seq_len(n)) { # X_list[[i]] <- perfectSample(MTD, N = N) # Generates n samples of size N # } # # # Parallel # # Limit internal BLAS/OpenMP threads to avoid oversubscription across worker # Sys.setenv(OMP_NUM_THREADS = "1", # MKL_NUM_THREADS = "1", # OPENBLAS_NUM_THREADS = "1", # BLIS_NUM_THREADS = "1") # # # Detect cores and choose a safe number of workers # get_smart_workers <- function() { # physical_cores <- parallel::detectCores(logical = FALSE) # # if (physical_cores >= 10) { # return(6) # } else if (physical_cores >= 6) { # return(4) # } else if (physical_cores >= 4) { # return(2) # } else { # return(1) # } # } # # # Manually assign number of workers (n_workers) or leave NULL for automatic choice. # n_workers <- NULL # workers <- ifelse(is.null(n_workers), get_smart_workers(), n_workers) # message(sprintf("Using %d workers", workers)) # future::plan(future::multisession, workers = workers) # op <- options(future.scheduling = 1) # # # Parallelize over replications # one_rep <- function(X) { # FS_i <- Naive_i <- Oracle_i <- numeric(length(m)) # SFS_row <- ZOracle_row <- integer(length(m) * 2) # # for (k in seq_along(m)) { # Y <- X[seq_len(m[k])] # ct <- countsTab(Y, d = d) # # # FS # S <- hdMTD_FS(Y, d = d, l = 2) # SFS_row[(k * 2 - 1):(k * 2)] <- S # p_FS <- freqTab(S = S, A = A, countsTab = ct)$qax_Sj[1] # FS_i[k] <- abs(p_FS - MTD$P[1, 1]) # # # Naive # ct_dNaive <- countsTab(Y, dNaive) # p_Naive <- freqTab(S = seq_len(dNaive), A = A, countsTab = ct_dNaive)$qax_Sj[1] # Naive_i[k] <- abs(p_Naive - MTD$P[1, 1]) # # # Oracle # p_pairs <- numeric(npairs) # for (s in seq_len(npairs)) { # p_pairs[s] <- freqTab(S = pairList[s, ], A = A, countsTab = ct)$qax_Sj[1] # } # minpos <- which.min(abs(p_pairs - MTD$P[1, 1])) # ZOracle_row[(k * 2 - 1):(k * 2)] <- pairList[minpos, ] # p_Oracle <- p_pairs[minpos] # Oracle_i[k] <- abs(p_Oracle - MTD$P[1, 1]) # } # # list(FS = FS_i, Naive = Naive_i, Oracle = Oracle_i, # SFS = SFS_row, ZOracle = ZOracle_row) # } # # indices_to_run <- seq_len(n) # chunks <- split(indices_to_run, ceiling(seq_along(indices_to_run) / workers)) # # # Note that, given X_list the following loop is deterministic # for (bi in seq_along(chunks)) { #takes ~ceiling(100/workers)*90 minutes to run) # rows <- chunks[[bi]] # res_block <- future.apply::future_lapply(X_list[rows], one_rep, future.seed = TRUE) # # #Fill block lines # FS[rows, ] <- do.call(rbind, lapply(res_block, `[[`, "FS")) # Naive[rows, ] <- do.call(rbind, lapply(res_block, `[[`, "Naive")) # Oracle[rows, ] <- do.call(rbind, lapply(res_block, `[[`, "Oracle")) # SFS[rows, ] <- do.call(rbind, lapply(res_block, `[[`, "SFS")) # ZOracle[rows, ] <- do.call(rbind, lapply(res_block, `[[`, "ZOracle")) # } # # future::plan(future::sequential) # options(op) # # FSP <- FS/minP11_P12 # OracleP <- Oracle/minP11_P12 # NaiveP <- Naive/minP11_P12 # # # Store all simulated data in a list # simulated_data <- list( # FS = FS, FSP = FSP, # Oracle = Oracle, OracleP = OracleP, # Naive = Naive, NaiveP = NaiveP, # SFS = SFS, ZOracle = ZOracle # ) ## ----simulation-load, echo=FALSE---------------------------------------------- FS <- simulated_data$FS FSP <- simulated_data$FSP Oracle <- simulated_data$Oracle OracleP <- simulated_data$OracleP Naive <- simulated_data$Naive NaiveP <- simulated_data$NaiveP SFS <- simulated_data$SFS ZOracle <- simulated_data$ZOracle ## ----unnamed-chunk-31--------------------------------------------------------- means_table <- rbind( round(apply(FS, 2, mean), 5), round(apply(Oracle, 2, mean), 5), round(apply(Naive, 2, mean), 5), round(apply(FSP, 2, mean), 5), round(apply(OracleP, 2, mean), 5), round(apply(NaiveP, 2, mean), 5) ) rownames(means_table) <- c( "Delta_FS(m)", "Delta_Oracle(m)", "Delta_Naive,5(m)", "std Delta_FS(m)", "std Delta_Oracle(m)", "std Delta_Naive,5(m)" ) colnames(means_table) <- m ## ----mean-error-table, results='asis', message=FALSE, warning=FALSE----------- suppressWarnings( tbl_1 <- knitr::kable( means_table, caption = "Mean error of estimators", format = "markdown", booktabs = TRUE, escape = FALSE ) ) suppressWarnings(print(tbl_1)) ## ----unnamed-chunk-33--------------------------------------------------------- m_index <- seq(1, length(m)*2, by = 2) names(m_index) <- as.character(m) SFS_vs_ZOracle_diff <- sapply(m_index, function(idx) { SFS_set <- apply(SFS[, c(idx, idx + 1)], 1, function(x) paste(sort(x), collapse = "-")) ZOracle_set <- apply(ZOracle[, c(idx, idx + 1)], 1, function(x) paste(sort(x), collapse = "-")) sum(SFS_set != ZOracle_set) }) SFS_vs_ZOracle_diff ## ----unnamed-chunk-34--------------------------------------------------------- tab <- FS FStab <- rbind(apply(tab, 2, summary),'sd'=apply(tab, 2, sd)) FStab <- rbind(FStab,'sdLo'=FStab[4,]-FStab[7,],'sdUp'=FStab[4,]+FStab[7,]) Fmean <- FStab[4,] FsdUp <- FStab[9,] FsdLo <- FStab[8,] Fq1 <- FStab[2,] Fq2 <- FStab[3,] Fq3 <- FStab[5,] ## ----unnamed-chunk-35--------------------------------------------------------- tab <- Naive Naivetab <- rbind(apply(tab, 2, summary),'sd'=apply(tab, 2, sd)) Naivetab <- rbind(Naivetab,'sdLo'=Naivetab[4,]-Naivetab[7,],'sdUp'=Naivetab[4,]+Naivetab[7,]) Nmean <- Naivetab[4,] NsdUp <- Naivetab[9,] NsdLo <- Naivetab[8,] Nq1 <- Naivetab[2,] Nq2 <- Naivetab[3,] Nq3 <- Naivetab[5,] ## ----unnamed-chunk-36--------------------------------------------------------- tab <- Oracle Oracletab <- rbind(apply(tab, 2, summary),'sd'=apply(tab, 2, sd)) Oracletab <- rbind(Oracletab,'sdLo'=Oracletab[4,]-Oracletab[7,],'sdUp'=Oracletab[4,]+Oracletab[7,]) Omean <- Oracletab[4,] OsdUp <- Oracletab[9,] OsdLo <- Oracletab[8,] Oq1 <- Oracletab[2,] Oq2 <- Oracletab[3,] Oq3 <- Oracletab[5,] ## ----fig1-plot, fig.width=10, fig.height=6, message=FALSE, warning=FALSE------ par(mfrow = c(1,2), oma = c(0,0,0,0)) ## --- Left panel: Mean error with standard deviation bands --- par(mar = c(5,5,3,4), xpd = NA) plot(m/100, Fmean, type = "l", col = "#377EB8", xlab = "m (x100)", ylab = "Mean error", ylim = c(0, 0.12), lwd = 3, frame.plot = FALSE, xaxt = "n", yaxt = "n", xlim = c(10,100), cex.axis = 1.4, cex.lab = 1.6) lines(m/100, Omean, col = "#E41A1C", lwd = 3) lines(m/100, Nmean, col = "#4DAF4A", lwd = 3) points(m/100, Fmean, col = "#377EB8", pch = 19, cex = 0.7) points(m/100, Omean, col = "#E41A1C", pch = 19, cex = 0.7) points(m/100, Nmean, col = "#4DAF4A", pch = 19, cex = 0.7) lines(m/100, FsdUp, col = "#377EB8", lty = 2) lines(m/100, FsdLo, col = "#377EB8", lty = 2) lines(m/100, OsdUp, col = "#E41A1C", lty = 2) lines(m/100, OsdLo, col = "#E41A1C", lty = 2) cap <- 0.12 NsdUp_cut <- ifelse(NsdUp > cap, NA, NsdUp) lines(m/100, NsdUp_cut, col = "#4DAF4A", lty = 2) lines(m/100, NsdLo, col = "#4DAF4A", lty = 2) axis(side = 1, at = m/100, labels = m/100, cex.axis = 1.4) axis(side = 2, cex.axis = 1.4) legend( "topright", inset = c(0.05, 0), legend = c(expression(bar(Delta) ~ "FS"), expression(bar(Delta) ~ "FS" %+-% "sd"), expression(bar(Delta) ~ "Oracle"), expression(bar(Delta) ~ "Oracle" %+-% "sd"), expression(bar(Delta) ~ "Naive"), expression(bar(Delta) ~ "Naive" %+-% "sd")), col = c("#377EB8","#377EB8","#E41A1C","#E41A1C","#4DAF4A","#4DAF4A"), lty = c(1,2,1,2,1,2), lwd = c(3,1.5,3,1.5,3,1.5), bty = "n", y.intersp = 0.95, x.intersp = 0.5, seg.len = 3, cex = 1.4 ) ## --- Right panel: Median and quartiles --- par(mar = c(5,5,3,4), xpd = NA) plot(m/100, Fq2, type = "l", col = "#377EB8", xlab = "m (x100)", ylab = "Quartiles of mean error", ylim = c(0, 0.12), lwd = 3, frame.plot = FALSE, xaxt = "n", yaxt = "n", xlim = c(10,100), cex.axis = 1.4, cex.lab = 1.6) lines(m/100, Oq2, col = "#E41A1C", lwd = 3) lines(m/100, Nq2, col = "#4DAF4A", lwd = 3) points(m/100, Fq2, col = "#377EB8", pch = 19, cex = 0.7) points(m/100, Oq2, col = "#E41A1C", pch = 19, cex = 0.7) points(m/100, Nq2, col = "#4DAF4A", pch = 19, cex = 0.7) lines(m/100, Fq1, col = "#377EB8", lty = 2) lines(m/100, Fq3, col = "#377EB8", lty = 2) lines(m/100, Oq1, col = "#E41A1C", lty = 2) lines(m/100, Oq3, col = "#E41A1C", lty = 2) lines(m/100, Nq1, col = "#4DAF4A", lty = 2) lines(m/100, Nq3, col = "#4DAF4A", lty = 2) axis(side = 1, at = m/100, labels = m/100, cex.axis = 1.4) axis(side = 2, cex.axis = 1.4) legend( "topright", inset = c(0.09, 0), legend = c(expression("Med " ~ bar(Delta) ~ "FS"), expression("q1,q3" ~ bar(Delta) ~ "FS"), expression("Med " ~ bar(Delta) ~ "Oracle"), expression("q1,q3" ~ bar(Delta) ~ "Oracle"), expression("Med " ~ bar(Delta) ~ "Naive"), expression("q1,q3" ~ bar(Delta) ~ "Naive")), col = c("#377EB8","#377EB8","#E41A1C","#E41A1C","#4DAF4A","#4DAF4A"), lty = c(1,2,1,2,1,2), lwd = c(3,1.5,3,1.5,3,1.5), bty = "n", y.intersp = 0.95, x.intersp = 0.5, seg.len = 3, cex = 1.4 ) ## ----unnamed-chunk-38--------------------------------------------------------- data("tempdata") ## ----unnamed-chunk-39--------------------------------------------------------- tempdata <- hdMTD::tempdata %>% filter(DATE >= "2010-08-05") ## ----unnamed-chunk-40--------------------------------------------------------- posNA <- which(is.na(tempdata$MAXTEMP)) ## ----unnamed-chunk-41--------------------------------------------------------- for (i in posNA) { if(!is.na(tempdata$MAXTEMP[i - 1]) && !all(is.na(tempdata$MAXTEMP[(i + 1):(i + 6)]))) { aux <- which(!is.na(tempdata$MAXTEMP[(i + 1):(i + 6)]))[1] tempdata$MAXTEMP[i] <- mean(tempdata$MAXTEMP[i - 1],tempdata$MAXTEMP[i + aux]) } } ## ----unnamed-chunk-42--------------------------------------------------------- posNA <- which(is.na(tempdata$MAXTEMP)) ## ----unnamed-chunk-43--------------------------------------------------------- for (i in posNA) { tempdata$MAXTEMP[i] <- mean(c(tempdata$MAXTEMP[i - 1], tempdata$MAXTEMP[i + 1], tempdata$MAXTEMP[i - 24]),na.rm = TRUE) } ## ----unnamed-chunk-44--------------------------------------------------------- temp <- tempdata %>% group_by(DATE) %>% summarize(MAXTEMP = mean(MAXTEMP), .groups = 'drop') head(temp, 4) ## ----temp-plot, fig.width=9, fig.height=6, message=FALSE, warning=FALSE------- TRIM_DATA <- temp %>% mutate( Y_TRIMESTER = paste0(year(DATE), "-T", quarter(DATE)) ) %>% group_by(Y_TRIMESTER) %>% summarise( MEAN_TEMP = mean(MAXTEMP), DATA_REF = min(DATE) ) %>% ungroup() %>% arrange(DATA_REF) TRIM_DATA <- TRIM_DATA[-c(1, nrow(TRIM_DATA)),] ggplot(TRIM_DATA, aes(x = DATA_REF, y = MEAN_TEMP)) + geom_line(color = "steelblue", linewidth = 0.5) + geom_point(color = "steelblue", size = 1.2) + scale_x_date( date_breaks = "1 year", date_labels = "%Y", minor_breaks = NULL ) + theme_minimal() + theme( axis.text.x = element_text(angle = 45, hjust = 1, size = 12), axis.text.y = element_text(size = 12), panel.grid.major = element_line(color = "gray90"), axis.title.x = element_text(size = 15), axis.title.y = element_text(size = 15), plot.title = element_text(hjust = 0.5, size = 17, face = "bold") ) + labs( title = "Quarterly mean of daily maximum temperatures across the years", x = "Year", y = "Mean Temperature (°C)" ) ## ----unnamed-chunk-46--------------------------------------------------------- xn <- max(temp$MAXTEMP) x1 <- min(temp$MAXTEMP) maxAmp <- xn - x1 temp$MAXTEMP1 <- ifelse(temp$MAXTEMP < x1 + maxAmp/2, 1, 2) head(temp, 4) prop.table(table(temp$MAXTEMP1)) # frequency of thermal regimes ## ----unnamed-chunk-47--------------------------------------------------------- Temp12 <- rev(temp$MAXTEMP1) ## ----temperature-fs-d400, eval=FALSE------------------------------------------ # FS_Temp12_d400 <- hdMTD_FS(Temp12, d = 400, l = 3) # FS_Temp12_d400 ## ----temperature-fs-d400-output, echo=FALSE----------------------------------- FS_Temp12_d400 <- precomputed$FS_Temp12_d400 print(FS_Temp12_d400) ## ----temperature-fs-d364, eval=FALSE------------------------------------------ # FS_Temp12_d364 <- hdMTD_FS(Temp12, d = 364, l = 3) # FS_Temp12_d364 ## ----temperature-fs-d364-output, echo=FALSE----------------------------------- FS_Temp12_d364 <- precomputed$FS_Temp12_d364 print(FS_Temp12_d364) ## ----unnamed-chunk-52--------------------------------------------------------- ndays <- nrow(temp %>% filter(DATE >= "2023-09-01")) # 366 days in the latest year of the sample Temp12_Train <- Temp12[-seq_len(ndays)] # Training data with 4775 days Temp12_Test <- Temp12[seq_len(ndays)] # Test data ## ----temperature-train-fs, eval=FALSE----------------------------------------- # FS_Temp12Train <- hdMTD_FS(Temp12_Train, d = 364, l = 3) # FS_Temp12Train ## ----temperature-train-fs-output, echo=FALSE---------------------------------- FS_Temp12Train <- precomputed$FS_Temp12Train print(FS_Temp12Train) ## ----unnamed-chunk-55--------------------------------------------------------- hdMTD_CUT(Temp12_Train, d = 364, S = c(1, 364, 6)) ## ----unnamed-chunk-56--------------------------------------------------------- hdMTD_BIC(Temp12_Train, d = 364, S = c(1, 364, 6), minl = 1, maxl = 3, byl = TRUE, BICvalue = TRUE ) ## ----unnamed-chunk-59--------------------------------------------------------- P_FS <- empirical_probs(Temp12_Train, S = c(1, 6, 364), matrixform = TRUE) P_FS ## ----unnamed-chunk-60--------------------------------------------------------- ct <- countsTab(Temp12_Train, d = 6) # Table with size 6 sequence counts head(ct,4) ## ----unnamed-chunk-61--------------------------------------------------------- ft <- freqTab(S = 1, A = c(1, 2), countsTab = ct) LL <- sum(log(ft$qax_Sj) * ft$Nxa_Sj) freeParam <- 2 * 1 BICMC1 <- -LL + 0.5 * log(length(Temp12_Train)) * freeParam BICMC1 ## ----unnamed-chunk-62--------------------------------------------------------- ft <- freqTab(S = c(1, 2), A = c(1, 2), countsTab = ct) LL <- sum(log(ft$qax_Sj) * ft$Nxa_Sj) freeParam <- 2^2 * 1 BICMC2 <- -LL + 0.5 * log(length(Temp12_Train)) * freeParam BICMC2 ## ----unnamed-chunk-63--------------------------------------------------------- ft <- freqTab(S = c(1, 2, 3), A = c(1, 2), countsTab = ct) head(ft, 4) LL <- sum(log(ft$qax_Sj) * ft$Nxa_Sj) freeParam <- 2^3 * 1 BICMC3 <- -LL + 0.5 * log(length(Temp12_Train)) * freeParam BICMC3 ## ----unnamed-chunk-64--------------------------------------------------------- ft <- freqTab(S = c(1, 2, 3, 4), A = c(1, 2), countsTab = ct) LL <- sum(log(ft$qax_Sj) * ft$Nxa_Sj) freeParam <- 2^4 * 1 BICMC4 <- -LL + 0.5 * log(length(Temp12_Train)) * freeParam BICMC4 ## ----unnamed-chunk-65--------------------------------------------------------- ft <- freqTab(S = c(1, 2, 3, 4, 5), A = c(1, 2), countsTab = ct) pos <- which(ft$Nxa_Sj > 0) LL <- sum(log(ft$qax_Sj[pos]) * ft$Nxa_Sj[pos]) freeParam <- 2^5 * 1 BICMC5 <- -LL + 0.5 * log(length(Temp12_Train)) * freeParam BICMC5 ## ----unnamed-chunk-66--------------------------------------------------------- ft <- freqTab(S = c(1, 2, 3, 4, 5, 6), A = c(1, 2), countsTab = ct) pos <- which(ft$Nxa_Sj > 0) LL <- sum(log(ft$qax_Sj[pos]) * ft$Nxa_Sj[pos]) freeParam <- 2^6 * 1 BICMC6 <- -LL + 0.5 * log(length(Temp12_Train)) * freeParam BICMC6 ## ----unnamed-chunk-67--------------------------------------------------------- BIC_vals <- c(BICMC1, BICMC2, BICMC3, BICMC4, BICMC5, BICMC6) model_names <- paste0("MC", 1:6) minBIC_idx <- which.min(BIC_vals) BIC_fmt <- sprintf("%.3f", BIC_vals) BIC_fmt[minBIC_idx] <- paste0("**", BIC_fmt[minBIC_idx], "**") minBIC_idx ## ----unnamed-chunk-68--------------------------------------------------------- bic_matrix <- data.frame(matrix(BIC_fmt, nrow = 1)) colnames(bic_matrix) <- model_names rownames(bic_matrix) <- "BIC" ## ----bic-table, results='asis', message=FALSE, warning=FALSE------------------ tbl_2 <- suppressWarnings( knitr::kable( bic_matrix, caption = "BIC values computed for classical Markov chain models of different orders." ) ) suppressWarnings(print(tbl_2)) ## ----unnamed-chunk-70--------------------------------------------------------- P_MC2 <- empirical_probs(Temp12_Train, S = c(1, 2), matrixform = TRUE) P_MC2 ## ----unnamed-chunk-71--------------------------------------------------------- P_Ind <- prop.table(table(Temp12_Train)) P_Ind ## ----unnamed-chunk-72--------------------------------------------------------- Days1 <- which(Temp12_Test == 1) lenDays1 <- length(Days1) lenDays1 / ndays # frequency of low temperature days Temp12_Test <- c(Temp12_Test, Temp12_Train[seq_len(364)]) ## ----unnamed-chunk-73--------------------------------------------------------- set.seed(1) hitInd <- numeric(1000) hitMC2 <- numeric(1000) hitFS <- numeric(1000) T1Ind <- numeric(1000) T1MC2 <- numeric(1000) T1FS <- numeric(1000) F1Ind <- numeric(1000) F1MC2 <- numeric(1000) F1FS <- numeric(1000) pasts2 <- rownames(P_MC2) pastsFS <- rownames(P_FS) ## ----unnamed-chunk-74--------------------------------------------------------- for (j in seq_len(1000)){ u <- runif(ndays) predInd <- numeric(ndays) predMC2 <- numeric(ndays) predFS <- numeric(ndays) for (i in ndays:1) { predInd[i] <- ifelse(u[i] <= P_Ind[1], 1, 2) pastRow <- which(pasts2 == paste0(rev(Temp12_Test[c(i+1, i+2)]), collapse = "")) predMC2[i] <- ifelse(u[i] <= P_MC2[pastRow, 1], 1, 2) pastRow <- which(pastsFS == paste0(rev(Temp12_Test[c(i+1, i+6, i+364)]), collapse = "")) predFS[i] <- ifelse(u[i] <= P_FS[pastRow, 1], 1, 2) } hitInd[j] <- sum(predInd == Temp12_Test[seq_len(ndays)]) hitMC2[j] <- sum(predMC2 == Temp12_Test[seq_len(ndays)]) hitFS[j] <- sum(predFS == Temp12_Test[seq_len(ndays)]) T1Ind[j] <- sum(predInd[Days1] == 1) T1MC2[j] <- sum(predMC2[Days1] == 1) T1FS[j] <- sum(predFS[Days1] == 1) F1Ind[j] <- sum(predInd[-Days1] == 1) F1MC2[j] <- sum(predMC2[-Days1] == 1) F1FS[j] <- sum(predFS[-Days1] == 1) } ## ----unnamed-chunk-75--------------------------------------------------------- AccInd <- mean(hitInd)/ndays AccMC2 <- mean(hitMC2)/ndays AccFS <- mean(hitFS)/ndays AccInd; AccMC2; AccFS ## ----unnamed-chunk-76--------------------------------------------------------- PrecInd <- mean(T1Ind/(T1Ind + F1Ind)) PrecMC2 <- mean(T1MC2/(T1MC2 + F1MC2)) PrecFS <- mean(T1FS/(T1FS + F1FS)) PrecInd; PrecMC2; PrecFS ## ----unnamed-chunk-77--------------------------------------------------------- SensInd <- mean(T1Ind)/lenDays1 SensMC2 <- mean(T1MC2)/lenDays1 SensFS <- mean(T1FS)/lenDays1 SensInd; SensMC2; SensFS ## ----unnamed-chunk-78--------------------------------------------------------- SpecInd <- 1 - mean(F1Ind)/(ndays - lenDays1) SpecMC2 <- 1 - mean(F1MC2)/(ndays - lenDays1) SpecFS <- 1 - mean(F1FS)/(ndays - lenDays1) SpecInd; SpecMC2; SpecFS ## ----unnamed-chunk-79--------------------------------------------------------- F1ScoreInd <- 2 * (PrecInd * SensInd) / (PrecInd + SensInd) F1ScoreMC2 <- 2 * (PrecMC2 * SensMC2) / (PrecMC2 + SensMC2) F1ScoreFS <- 2 * (PrecFS * SensFS) / (PrecFS + SensFS) F1ScoreInd; F1ScoreMC2; F1ScoreFS metric <- c("Accuracy", "Precision", "Sensitivity (Recall)", "Specificity", "F1-Score") formula <- c("(TP+TN)/(TP+TN+FP+FN)", "TP/(TP+FP)", "TP/(TP+FN)", "TN/(TN+FP)", "2(PPV*Recall)/(PPV+Recall)") performance_table <- data.frame( Metric = metric, Formula = formula, indc = round(c(AccInd, PrecInd, SensInd, SpecInd, F1ScoreInd) * 100, 2), mc2c = round(c(AccMC2, PrecMC2, SensMC2, SpecMC2, F1ScoreMC2) * 100, 2), fsc = round(c(AccFS, PrecFS, SensFS, SpecFS, F1ScoreFS) * 100, 2), check.names = FALSE ) names(performance_table) <- c("Metric", "Formula", "Ind (\\%)", "MC2 (\\%)", "FS (\\%)") ## ----performance-table, results='asis', message=FALSE, warning=FALSE---------- suppressWarnings( tbl_3 <- knitr::kable(performance_table, align = "l", caption = "Model performance metrics.") ) suppressWarnings(print(tbl_3)) ## ----accuracy-plot, fig.width=9, fig.height=6, message=FALSE, warning=FALSE---- accuracy_data <- data.frame( MC2 = hitMC2 / ndays, FS = hitFS / ndays ) %>% pivot_longer( everything(), names_to = "Model", values_to = "Accuracy" ) ggplot(accuracy_data, aes(x = Model, y = Accuracy, fill = Model)) + geom_boxplot() + labs( title = "Accuracy distribution (1000 replications)", x = "Model", y = "Accuracy" ) + theme_minimal() + scale_fill_brewer(palette = "Paired") + theme( plot.title = element_text(hjust = 0.5, size = 18, face = "bold"), axis.title = element_text(size = 16), axis.text = element_text(size = 14), legend.title = element_text(size = 16), legend.text = element_text(size = 14) ) ## ----sequential-selection-function, eval=FALSE-------------------------------- # run_sequential_lag_selection <- function(Temp12_Train, d = 364) { # # Initialization # A <- sort(unique(Temp12_Train)) # lenA <- length(A) # lenX <- length(Temp12_Train) # A_pairs <- matrix(A, ncol = 2) # All unique state pairs # ct <- countsTab(X = Temp12_Train, d = 364) # Sequence counts table # # # Initialize storage # results <- list( # nuj1 = numeric(d), # nuj2 = numeric(d-1), # nuj3 = numeric(d-2), # selected_lags = numeric(3) # ) # # # Helper function for empirical distribution calculation # PI <- function(S, groupTab, x_S, lenX, d) { # if (length(S) > 0) { # filtr_S <- paste0("x", S) # groupTab <- groupTab %>% # dplyr::mutate(match = purrr::pmap_lgl(dplyr::pick(dplyr::all_of(filtr_S)), # ~ all(c(...) == x_S))) %>% # dplyr::filter(match) %>% # dplyr::select(-match) # } # PI <- matrix(groupTab$Nx_Sj/(lenX - d),ncol = 1) # PI # } # # # Sequential Selection Process # cat("=== Starting Sequential Lag Selection ===\n") # # # Step 1: Initial selection (S = ∅) # cat("\n[Step 1] Selecting first lag (S = ∅)...\n") # S <- NULL # Sc <- sort(setdiff(seq_len(d), S), decreasing = TRUE) # Complement of S in 1:d # # for (z in seq_along(Sc)) { # Runs across all available lags # j <- Sc[z] # # Frequency tables # b_Sja <- freqTab(S = S, j = j, A = A, countsTab = ct) # b_Sj <- b_Sja %>% # dplyr::group_by(dplyr::across(dplyr::all_of(paste0("x", j)))) %>% # dplyr::summarise(Nx_Sj = sum(Nxa_Sj), .groups = "drop") # # # Compute νj # PIs <- PI(S = S, groupTab = b_Sj, x_S = S, lenX = lenX, d = 364) # dTVs <- dTV_sample(S = S, j = j, lenA = lenA, base = b_Sja, # A_pairs = A_pairs, x_S = S) # results$nuj1[z] <- prod(PIs) * dTVs # } # results$selected_lags[1] <- Sc[which.max(results$nuj1)] # cat(sprintf("Selected: j = %d (ν = %.4f)\n", # results$selected_lags[1], max(results$nuj1))) # # # Step 2: Second selection (S = {1}) # cat(sprintf("\n[Step 2] Selecting second lag (S = {%d})...\n", # results$selected_lags[1])) # S <- results$selected_lags[1] # Sc <- sort(setdiff(seq_len(d), S), decreasing = TRUE) # # for (z in seq_along(Sc)) { # j <- Sc[z] # Sj <- sort(c(S, j), decreasing = TRUE) # # # Frequency tables # b_Sja <- freqTab(S = S, j = j, A = A, countsTab = ct) # b_Sj <- b_Sja %>% # dplyr::group_by(dplyr::across(dplyr::all_of(paste0("x", Sj)))) %>% # dplyr::summarise(Nx_Sj = sum(Nxa_Sj), .groups = "drop") # b_S <- b_Sja %>% # dplyr::group_by(dplyr::across(dplyr::all_of(paste0("x", S)))) %>% # dplyr::summarise(Nx_Sj = sum(Nxa_Sj), .groups = "drop") # # subx <- b_S[, -ncol(b_S)] # # # Compute ν_j # for (t in which(b_S$Nx_Sj > 0)) { # PIs <- PI(S = S, groupTab = b_Sj, x_S = subx[t, ], # lenX = lenX, d = d) # dTVs <- dTV_sample(S = S, j = j, lenA = lenA, base = b_Sja, # A_pairs = A_pairs, x_S = subx[t, ]) # PI_xS <- as.numeric(b_S[t, ncol(b_S)]/(lenX - d)) # results$nuj2[z] <- results$nuj2[z] + prod(PIs) * dTVs/PI_xS # } # } # results$selected_lags[2] <- Sc[which.max(results$nuj2)] # cat(sprintf("Selected: j = %d (ν = %.4f)\n", # results$selected_lags[2], max(results$nuj2))) # # # Step 3: Third selection (S = {1,364}) # cat(sprintf("\n[Step 3] Selecting third lag (S = {%d,%d})...\n", # results$selected_lags[1], results$selected_lags[2])) # S <- c(S, results$selected_lags[2]) # Sc <- sort(setdiff(seq_len(d), S), decreasing = TRUE) # # for (z in seq_along(Sc)) { # j <- Sc[z] # Sj <- sort(c(S, j), decreasing = TRUE) # dec_S <- rev(S) # S in decreasing order # # # Frequency tables # b_Sja <- freqTab(S = dec_S, j = j, A = A, countsTab = ct) # b_Sj <- b_Sja %>% # dplyr::group_by(dplyr::across(dplyr::all_of(paste0("x", Sj)))) %>% # dplyr::summarise(Nx_Sj = sum(Nxa_Sj), .groups = "drop") # b_S <- b_Sja %>% # dplyr::group_by(dplyr::across(dplyr::all_of(paste0("x", dec_S)))) %>% # dplyr::summarise(Nx_Sj = sum(Nxa_Sj), .groups = "drop") # # subx <- b_S[, -ncol(b_S)] # # # Compute ν_j # for (t in which(b_S$Nx_Sj > 0)) { # PIs <- PI(S = dec_S, groupTab = b_Sj, x_S = subx[t, ], # lenX = lenX, d = d) # dTVs <- dTV_sample(S = dec_S, j = j, lenA = lenA, base = b_Sja, # A_pairs = A_pairs, x_S = subx[t, ]) # PI_xS <- as.numeric(b_S[t, ncol(b_S)]/(lenX - d)) # results$nuj3[z] <- results$nuj3[z] + prod(PIs) * dTVs/PI_xS # } # } # results$selected_lags[3] <- Sc[which.max(results$nuj3)] # cat(sprintf("Selected: j = %d (ν = %.4f)\n", # results$selected_lags[3], max(results$nuj3))) # # # Final Results # cat("\n=== Final Selection Results ===\n") # print(data.frame(Step = 1:3, Selected_Lag = results$selected_lags, # nu = c(max(results$nuj1), max(results$nuj2), max(results$nuj3)))) # # return(results) # } ## ----sequential-selection-call, eval=FALSE------------------------------------ # results <- run_sequential_lag_selection(Temp12_Train) ## ----sequential-selection-load, echo=FALSE------------------------------------ results <- results_sequential cat("\n=== Final Selection Results ===\n") print(data.frame( Step = 1:3, Selected_Lag = results$selected_lags, nu = c(max(results$nuj1), max(results$nuj2), max(results$nuj3)) )) ## ----nu-plot, fig.width=11, fig.height=6, message=FALSE, warning=FALSE-------- par(mfrow = c(1, 3), mar = c(5, 6, 4, 2), oma = c(0, 0, 4, 0)) palette <- c("#E41A1C", "#377EB8", "#4DAF4A") with(results, { # Graph 1 Sc <- 364:1 plot(1:364, rev(nuj1), type = "p", pch = 19, cex = 0.8, col = "gray70", ylab = "", xlab = "Lag (-j)", cex.lab = 1.8, cex.axis = 1.3, ylim = c(0,0.13), main = "", panel.first = grid()) title(main = expression(paste("S = ", Ø)), cex.main = 1.5, font.main = 1) title(ylab = expression(widehat(nu)[n*","*j*","*S]/2), line = 3, cex.lab = 1.5) points(Sc[which.max(nuj1)], nuj1[which.max(nuj1)], pch = 21, bg = palette[1], cex = 1.5, lwd = 1) text(Sc[which.max(nuj1)], nuj1[which.max(nuj1)], labels = paste0(Sc[which.max(nuj1)]), pos = 3, col = palette[1], font = 2, cex = 1.4) # Graph 2 Sc <- 364:2 plot(2:364, rev(nuj2), type = "p", pch = 19, cex = 0.8, col = "gray70", ylab = "", xlab = "Lag (-j)", cex.lab = 1.8, cex.axis = 1.3, ylim = c(0,0.025), main = "", panel.first = grid()) title(main = "With S = {-1}", cex.main = 1.5, font.main = 1) title(ylab = expression(widehat(nu)[n*","*j*","*S]/2), line = 3, cex.lab = 1.5) points(Sc[which.max(nuj2)], nuj2[which.max(nuj2)], pch = 21, bg = palette[2], cex = 1.5, lwd = 1) text(Sc[which.max(nuj2)]-5, nuj2[which.max(nuj2)], labels = paste0(Sc[which.max(nuj2)]), pos = 3, col = palette[2], font = 2, cex = 1.4) # Graph 3 Sc <- 363:2 plot(2:363, rev(nuj3), type = "p", pch = 19, cex = 0.8, col = "gray70", ylab = "", xlab = "Lag (-j)", cex.lab = 1.8, cex.axis = 1.3, ylim = c(0,0.025), main = "", panel.first = grid()) title(main = "With S = {-364, -1}", cex.main = 1.5, font.main = 1) title(ylab = expression(widehat(nu)[n*","*j*","*S]/2), line = 3, cex.lab = 1.5) points(Sc[which.max(nuj3)], nuj3[which.max(nuj3)], pch = 21, bg = palette[3], cex = 1.5, lwd = 1) text(Sc[which.max(nuj3)], nuj3[which.max(nuj3)], labels = paste0(Sc[which.max(nuj3)]), pos = 3, col = palette[3], font = 2, cex = 1.4) mtext(expression(paste("Sequential lag selection based on ", widehat(nu)[n*","*j*","*S])), outer = TRUE, cex = 1.6, font = 2, line = 1.4) }) ## ----session-info------------------------------------------------------------- sessionInfo()