| Title: | Value-Price Analysis with Bayesian and Panel Data Methods |
|---|---|
| Description: | Provides tools for analyzing the relationship between direct prices (based on labor values) and prices of production using Bayesian generalized linear models, panel data methods, partial least squares regression, canonical correlation analysis, and panel vector autoregression. Includes functions for model comparison, out-of-sample validation, and structural break detection. Here, methods use raw accounting data with explicit temporal structure, following Gomez Julian (2023) <doi:10.17605/OSF.IO/7J8KF> and standard econometric techniques for panel data analysis. |
| Authors: | Jose Mauricio Gomez Julian [aut, cre]
|
| Maintainer: | Jose Mauricio Gomez Julian <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.0 |
| Built: | 2026-10-10 14:58:24 UTC |
| Source: | https://github.com/IsadoreNabi/valueprhr |
Aggregates panel data to time series by computing means across sectors.
aggregate_to_timeseries(panel_data, vars = c("log_direct", "log_production"))aggregate_to_timeseries(panel_data, vars = c("log_direct", "log_production"))
panel_data |
Data frame with panel data. |
vars |
Character vector of variables to aggregate. Default c("log_direct", "log_production"). |
Data frame with one row per year containing aggregated values.
set.seed(123) panel <- data.frame( year = rep(2000:2005, 3), sector = rep(c("A", "B", "C"), each = 6), log_direct = rnorm(18, mean = 5), log_production = rnorm(18, mean = 5) ) ts_agg <- aggregate_to_timeseries(panel) head(ts_agg)set.seed(123) panel <- data.frame( year = rep(2000:2005, 3), sector = rep(c("A", "B", "C"), each = 6), log_direct = rnorm(18, mean = 5), log_production = rnorm(18, mean = 5) ) ts_agg <- aggregate_to_timeseries(panel) head(ts_agg)
Functions for fitting Bayesian GLMs sector by sector.
Estimates the mode of a numeric vector using kernel density estimation. Falls back to median if density estimation fails.
calculate_mode(x)calculate_mode(x)
x |
A numeric vector. |
A single numeric value representing the estimated mode.
set.seed(123) x <- rnorm(100, mean = 5, sd = 1) calculate_mode(x)set.seed(123) x <- rnorm(100, mean = 5, sd = 1) calculate_mode(x)
Functions for sparse CCA and panel vector autoregression.
Checks for package availability and provides informative error message.
check_package(pkg, reason = "this functionality")check_package(pkg, reason = "this functionality")
pkg |
Character string with package name. |
reason |
Character string explaining why the package is needed. |
TRUE invisibly if package is available, otherwise stops with error.
check_package("stats", "basic statistics")check_package("stats", "basic statistics")
Generates a comprehensive comparison table of all fitted models.
compare_models( twoway_result = NULL, mundlak_result = NULL, bayes_result = NULL, pls_result = NULL )compare_models( twoway_result = NULL, mundlak_result = NULL, bayes_result = NULL, pls_result = NULL )
twoway_result |
Result from fit_twoway_fe (or NULL). |
mundlak_result |
Result from fit_mundlak_cre (or NULL). |
bayes_result |
Result from fit_bayesian_hierarchical (or NULL). |
pls_result |
Result from fit_pls_multivariate (or NULL). |
A data frame with model comparison metrics.
if (requireNamespace("plm", quietly = TRUE)) { set.seed(123) panel <- data.frame( year = rep(2000:2019, 5), sector = rep(LETTERS[1:5], each = 20), log_direct = rnorm(100, 5, 0.5), log_production = rnorm(100, 5, 0.5) ) panel$log_production <- panel$log_direct * 0.95 + rnorm(100, 0, 0.1) twoway <- fit_twoway_fe(panel) mundlak <- fit_mundlak_cre(panel) comparison <- compare_models( twoway_result = twoway, mundlak_result = mundlak ) print(comparison) }if (requireNamespace("plm", quietly = TRUE)) { set.seed(123) panel <- data.frame( year = rep(2000:2019, 5), sector = rep(LETTERS[1:5], each = 20), log_direct = rnorm(100, 5, 0.5), log_production = rnorm(100, 5, 0.5) ) panel$log_production <- panel$log_direct * 0.95 + rnorm(100, 0, 0.1) twoway <- fit_twoway_fe(panel) mundlak <- fit_mundlak_cre(panel) comparison <- compare_models( twoway_result = twoway, mundlak_result = mundlak ) print(comparison) }
Compares out-of-sample metrics to in-sample metrics.
compute_oos_degradation(insample_metrics, cv_results)compute_oos_degradation(insample_metrics, cv_results)
insample_metrics |
Named list with in-sample metrics. |
cv_results |
Data frame from rolling_window_cv. |
Data frame with degradation percentages.
insample <- list(rmse_fe = 0.05, rmse_m = 0.04) cv_res <- data.frame( rmse_fe_all = c(0.06, 0.055, 0.058), rmse_m_all = c(0.045, 0.042, 0.044) ) degradation <- compute_oos_degradation(insample, cv_res) print(degradation)insample <- list(rmse_fe = 0.05, rmse_m = 0.04) cv_res <- data.frame( rmse_fe_all = c(0.06, 0.055, 0.058), rmse_m_all = c(0.045, 0.042, 0.044) ) degradation <- compute_oos_degradation(insample, cv_res) print(degradation)
Calculates the coefficient of determination (R-squared) for predictions.
compute_r2(actual, predicted)compute_r2(actual, predicted)
actual |
Numeric vector of actual values. |
predicted |
Numeric vector of predicted values. |
A single numeric R-squared value, or NA if not computable.
actual <- c(1, 2, 3, 4, 5) predicted <- c(1.1, 1.9, 3.1, 4.0, 4.9) compute_r2(actual, predicted)actual <- c(1, 2, 3, 4, 5) predicted <- c(1.1, 1.9, 3.1, 4.0, 4.9) compute_r2(actual, predicted)
Adds sector-level means and within-deviations for Mundlak/CRE estimation.
create_mundlak_data(panel_data, x_var = "log_direct")create_mundlak_data(panel_data, x_var = "log_direct")
panel_data |
Data frame with panel data. |
x_var |
Character string. Name of the explanatory variable. Default "log_direct". |
Panel data with additional columns:
Sector-level mean of x_var
Within-sector deviation (x - sector mean)
set.seed(123) panel <- data.frame( year = rep(2000:2002, 3), sector = rep(c("A", "B", "C"), each = 3), log_direct = rnorm(9, mean = 5), log_production = rnorm(9, mean = 5) ) panel_mundlak <- create_mundlak_data(panel) head(panel_mundlak)set.seed(123) panel <- data.frame( year = rep(2000:2002, 3), sector = rep(c("A", "B", "C"), each = 3), log_direct = rnorm(9, mean = 5), log_production = rnorm(9, mean = 5) ) panel_mundlak <- create_mundlak_data(panel) head(panel_mundlak)
Functions for preparing and transforming price data for analysis.
Computes various error metrics comparing predictions to actual values.
evaluate_insample(predicted, actual)evaluate_insample(predicted, actual)
predicted |
Numeric vector of predicted values (log scale). |
actual |
Numeric vector of actual values (log scale). |
A list containing:
MAE in log scale
RMSE in log scale
MAE in original scale (after exp transformation)
RMSE in original scale
MAE as percentage of range
set.seed(123) actual <- log(runif(50, 100, 200)) predicted <- actual + rnorm(50, 0, 0.1) evaluate_insample(predicted, actual)set.seed(123) actual <- log(runif(50, 100, 200)) predicted <- actual + rnorm(50, 0, 0.1) evaluate_insample(predicted, actual)
Exports analysis results to CSV files.
export_results_csv( comparison_table = NULL, cv_results = NULL, sector_summary = NULL, output_dir = tempdir(), prefix = "valueprhr" )export_results_csv( comparison_table = NULL, cv_results = NULL, sector_summary = NULL, output_dir = tempdir(), prefix = "valueprhr" )
comparison_table |
Data frame from compare_models. |
cv_results |
Data frame from rolling_window_cv. |
sector_summary |
Data frame from fit_bayesian_glm_sectors. |
output_dir |
Directory for output files. Default tempdir(). |
prefix |
Filename prefix. Default "valueprhr". |
Character vector of created file paths.
comparison <- data.frame( model = c("Model A", "Model B"), R2 = c(0.95, 0.92) ) files <- export_results_csv(comparison_table = comparison) print(files)comparison <- data.frame( model = c("Model A", "Model B"), R2 = c(0.95, 0.92) ) files <- export_results_csv(comparison_table = comparison) print(files)
Extracts the variables with highest absolute loadings for each CCA component.
extract_cca_loadings( cca_result, n_top = 5L, which_matrix = c("both", "X", "Y") )extract_cca_loadings( cca_result, n_top = 5L, which_matrix = c("both", "X", "Y") )
cca_result |
Result from run_sparse_cca. |
n_top |
Number of top variables to show. Default 5. |
which_matrix |
Character. "X", "Y", or "both". Default "both". |
Data frame with top loadings.
set.seed(123) n <- 50 p <- 20 X <- matrix(rnorm(n * p), n, p) Y <- X %*% matrix(rnorm(p * 5), p, 5) + matrix(rnorm(n * 5, 0, 0.5), n, 5) colnames(X) <- paste0("X", 1:p) colnames(Y) <- paste0("Y", 1:5) cca_res <- run_sparse_cca(X, Y, n_components = 2) top_loads <- extract_cca_loadings(cca_res) print(top_loads)set.seed(123) n <- 50 p <- 20 X <- matrix(rnorm(n * p), n, p) Y <- X %*% matrix(rnorm(p * 5), p, 5) + matrix(rnorm(n * 5, 0, 0.5), n, 5) colnames(X) <- paste0("X", 1:p) colnames(Y) <- paste0("Y", 1:5) cca_res <- run_sparse_cca(X, Y, n_components = 2) top_loads <- extract_cca_loadings(cca_res) print(top_loads)
Extracts variable importance scores from a fitted PLS model.
extract_pls_importance(pls_result, ncomp = NULL)extract_pls_importance(pls_result, ncomp = NULL)
pls_result |
Result from fit_pls_multivariate. |
ncomp |
Number of components to use. Default uses optimal. |
Data frame with variable names and importance scores.
if (requireNamespace("pls", quietly = TRUE)) { set.seed(123) n <- 50 p <- 10 X <- matrix(rnorm(n * p), n, p) colnames(X) <- paste0("X", 1:p) Y <- X[, 1:3] %*% diag(c(1, 0.5, 0.3)) + matrix(rnorm(n * 3, 0, 0.5), n, 3) colnames(Y) <- paste0("Y", 1:3) result <- fit_pls_multivariate(X, Y, max_components = 5) importance <- extract_pls_importance(result) print(head(importance)) }if (requireNamespace("pls", quietly = TRUE)) { set.seed(123) n <- 50 p <- 10 X <- matrix(rnorm(n * p), n, p) colnames(X) <- paste0("X", 1:p) Y <- X[, 1:3] %*% diag(c(1, 0.5, 0.3)) + matrix(rnorm(n * 3, 0, 0.5), n, 3) colnames(Y) <- paste0("Y", 1:3) result <- fit_pls_multivariate(X, Y, max_components = 5) importance <- extract_pls_importance(result) print(head(importance)) }
Extracts intercepts and slopes from all sector models.
extract_sector_coefficients(sector_results)extract_sector_coefficients(sector_results)
sector_results |
List of sector results from fit_bayesian_glm_sectors. |
Data frame with sector names, intercepts, and slopes.
if (requireNamespace("rstanarm", quietly = TRUE)) { set.seed(123) years <- 2000:2010 direct <- data.frame( Year = years, A = 100 + cumsum(rnorm(11)), B = 120 + cumsum(rnorm(11)) ) production <- data.frame( Year = years, A = 102 + cumsum(rnorm(11)), B = 118 + cumsum(rnorm(11)) ) results <- fit_bayesian_glm_sectors(direct, production, chains = 2, iter = 1000) coefs <- extract_sector_coefficients(results$results) print(coefs) }if (requireNamespace("rstanarm", quietly = TRUE)) { set.seed(123) years <- 2000:2010 direct <- data.frame( Year = years, A = 100 + cumsum(rnorm(11)), B = 120 + cumsum(rnorm(11)) ) production <- data.frame( Year = years, A = 102 + cumsum(rnorm(11)), B = 118 + cumsum(rnorm(11)) ) results <- fit_bayesian_glm_sectors(direct, production, chains = 2, iter = 1000) coefs <- extract_sector_coefficients(results$results) print(coefs) }
Fits a VAR model on time-aggregated (mean across sectors) data.
fit_aggregated_var(panel_data, max_lags = 6L, difference = TRUE)fit_aggregated_var(panel_data, max_lags = 6L, difference = TRUE)
panel_data |
Data frame in panel format. |
max_lags |
Maximum lag order. Default 6. |
difference |
Logical. Apply first differencing. Default TRUE. |
A list containing:
The fitted vars::VAR model
Lag selected by information criteria
Impulse response functions (if computed)
Forecast error variance decomposition (if computed)
if (requireNamespace("vars", quietly = TRUE)) { set.seed(123) panel <- data.frame( year = rep(2000:2019, 5), sector = rep(LETTERS[1:5], each = 20), log_direct = rnorm(100, 5, 0.5), log_production = rnorm(100, 5, 0.5) ) result <- fit_aggregated_var(panel) print(result$selected_lag) }if (requireNamespace("vars", quietly = TRUE)) { set.seed(123) panel <- data.frame( year = rep(2000:2019, 5), sector = rep(LETTERS[1:5], each = 20), log_direct = rnorm(100, 5, 0.5), log_production = rnorm(100, 5, 0.5) ) result <- fit_aggregated_var(panel) print(result$selected_lag) }
Fits separate Bayesian generalized linear models for each sector, regressing production prices on direct prices.
fit_bayesian_glm_sectors( direct_prices, production_prices, chains = 4L, iter = 4000L, seed = 12345L, verbose = TRUE )fit_bayesian_glm_sectors( direct_prices, production_prices, chains = 4L, iter = 4000L, seed = 12345L, verbose = TRUE )
direct_prices |
Data frame with direct prices. First column must be 'Year', remaining columns are sector values. |
production_prices |
Data frame with prices of production. Must have same structure as direct_prices. |
chains |
Number of MCMC chains. Default 4. |
iter |
Number of iterations per chain. Default 4000. |
seed |
Random seed for reproducibility. Default 12345. |
verbose |
Logical. Print progress messages. Default TRUE. |
This function requires the 'rstanarm' and 'loo' packages to be installed. Each sector model uses a Gaussian family with identity link and weakly informative priors.
A list with two elements:
List of results for each sector
Data frame with summary statistics for all sectors
if (requireNamespace("rstanarm", quietly = TRUE)) { set.seed(123) years <- 2000:2010 direct <- data.frame( Year = years, Agriculture = 100 + cumsum(rnorm(11, 2, 1)), Manufacturing = 120 + cumsum(rnorm(11, 2, 1)) ) production <- data.frame( Year = years, Agriculture = 102 + cumsum(rnorm(11, 2, 1)), Manufacturing = 118 + cumsum(rnorm(11, 2, 1)) ) results <- fit_bayesian_glm_sectors( direct, production, chains = 2, iter = 1000 ) print(results$summary_table) }if (requireNamespace("rstanarm", quietly = TRUE)) { set.seed(123) years <- 2000:2010 direct <- data.frame( Year = years, Agriculture = 100 + cumsum(rnorm(11, 2, 1)), Manufacturing = 120 + cumsum(rnorm(11, 2, 1)) ) production <- data.frame( Year = years, Agriculture = 102 + cumsum(rnorm(11, 2, 1)), Manufacturing = 118 + cumsum(rnorm(11, 2, 1)) ) results <- fit_bayesian_glm_sectors( direct, production, chains = 2, iter = 1000 ) print(results$summary_table) }
Fits a Bayesian mixed effects model with random slopes by sector.
fit_bayesian_hierarchical( panel_data, include_time = TRUE, chains = 4L, iter = 4000L, seed = 12345L )fit_bayesian_hierarchical( panel_data, include_time = TRUE, chains = 4L, iter = 4000L, seed = 12345L )
panel_data |
Data frame in panel format. |
include_time |
Logical. Include time trend. Default TRUE. |
chains |
Number of MCMC chains. Default 4. |
iter |
Number of iterations. Default 4000. |
seed |
Random seed. Default 12345. |
A list containing:
The fitted rstanarm model object
Bayesian R-squared (mean)
Model summary for fixed effects
In-sample evaluation metrics
## Not run: if (requireNamespace("rstanarm", quietly = TRUE)) { set.seed(123) panel <- data.frame( year = rep(2000:2009, 5), sector = rep(LETTERS[1:5], each = 10), time = rep(1:10, 5), log_direct = rnorm(50, 5, 0.5), log_production = rnorm(50, 5, 0.5) ) panel$log_production <- panel$log_direct * 0.95 + rnorm(50, 0, 0.1) result <- fit_bayesian_hierarchical(panel, chains = 2, iter = 1000) print(result$r2_bayes) } ## End(Not run)## Not run: if (requireNamespace("rstanarm", quietly = TRUE)) { set.seed(123) panel <- data.frame( year = rep(2000:2009, 5), sector = rep(LETTERS[1:5], each = 10), time = rep(1:10, 5), log_direct = rnorm(50, 5, 0.5), log_production = rnorm(50, 5, 0.5) ) panel$log_production <- panel$log_direct * 0.95 + rnorm(50, 0, 0.1) result <- fit_bayesian_hierarchical(panel, chains = 2, iter = 1000) print(result$r2_bayes) } ## End(Not run)
Fits a Mundlak (CRE) model that decomposes effects into within and between components, allowing for correlation between unit effects and regressors.
fit_mundlak_cre(panel_data, include_time_fe = TRUE, robust_se = TRUE)fit_mundlak_cre(panel_data, include_time_fe = TRUE, robust_se = TRUE)
panel_data |
Data frame in panel format. |
include_time_fe |
Logical. Include time fixed effects. Default TRUE. |
robust_se |
Logical. Compute robust standard errors. Default TRUE. |
The Mundlak transformation adds sector-level means of the regressors to a random effects model, allowing consistent estimation even when the random effects are correlated with the regressors.
A list containing:
The fitted plm model object
Model summary
Panel data with Mundlak transformations
Robust coefficient tests
Random effects variance components
In-sample evaluation metrics
if (requireNamespace("plm", quietly = TRUE)) { set.seed(123) panel <- data.frame( year = rep(2000:2009, 5), sector = rep(LETTERS[1:5], each = 10), log_direct = rnorm(50, 5, 0.5), log_production = rnorm(50, 5, 0.5) ) panel$log_production <- panel$log_direct * 0.95 + rnorm(50, 0, 0.1) result <- fit_mundlak_cre(panel) print(result$variance_components) }if (requireNamespace("plm", quietly = TRUE)) { set.seed(123) panel <- data.frame( year = rep(2000:2009, 5), sector = rep(LETTERS[1:5], each = 10), log_direct = rnorm(50, 5, 0.5), log_production = rnorm(50, 5, 0.5) ) panel$log_production <- panel$log_direct * 0.95 + rnorm(50, 0, 0.1) result <- fit_mundlak_cre(panel) print(result$variance_components) }
Fits a panel vector autoregression model with first-difference transformation.
fit_panel_var(panel_data, max_lags = 2L, verbose = TRUE)fit_panel_var(panel_data, max_lags = 2L, verbose = TRUE)
panel_data |
Data frame in panel format. |
max_lags |
Maximum lag order to consider. Default 2. |
verbose |
Logical. Print progress. Default TRUE. |
A list containing:
The fitted panelvar model
Selected lag order
BIC for each lag order tested
if (requireNamespace("panelvar", quietly = TRUE)) { set.seed(123) panel <- data.frame( year = rep(2000:2019, 5), sector = rep(LETTERS[1:5], each = 20), log_direct = rnorm(100, 5, 0.5), log_production = rnorm(100, 5, 0.5) ) result <- fit_panel_var(panel) print(result$best_lag) }if (requireNamespace("panelvar", quietly = TRUE)) { set.seed(123) panel <- data.frame( year = rep(2000:2019, 5), sector = rep(LETTERS[1:5], each = 20), log_direct = rnorm(100, 5, 0.5), log_production = rnorm(100, 5, 0.5) ) result <- fit_panel_var(panel) print(result$best_lag) }
Fits a partial least squares regression model with automatic selection of the optimal number of components via cross-validation.
fit_pls_multivariate( X_matrix, Y_matrix, max_components = NULL, cv_segments = 10L, scale = TRUE, center = TRUE )fit_pls_multivariate( X_matrix, Y_matrix, max_components = NULL, cv_segments = 10L, scale = TRUE, center = TRUE )
X_matrix |
Numeric matrix of predictor variables (direct prices). |
Y_matrix |
Numeric matrix of response variables (production prices). |
max_components |
Maximum number of components to consider. Default NULL uses min(ncol(X), nrow(X)-1, ncol(Y), 25). |
cv_segments |
Number of cross-validation segments. Default 10. |
scale |
Logical. Scale variables before fitting. Default TRUE. |
center |
Logical. Center variables before fitting. Default TRUE. |
This function uses the pls package for PLS regression. Component selection is based on minimizing cross-validated RMSE. The function handles log-transformed data and reports metrics in both log and original scales.
A list containing:
The fitted pls model object
Optimal number of components by CV-RMSE
Data frame with CV metrics by number of components
CV metrics at optimal component number
In-sample metrics at optimal component number
if (requireNamespace("pls", quietly = TRUE)) { set.seed(123) n <- 50 p <- 10 X <- matrix(rnorm(n * p), n, p) colnames(X) <- paste0("X", 1:p) Y <- X[, 1:3] %*% diag(c(1, 0.5, 0.3)) + matrix(rnorm(n * 3, 0, 0.5), n, 3) colnames(Y) <- paste0("Y", 1:3) result <- fit_pls_multivariate(X, Y, max_components = 8) print(result$optimal_ncomp) print(result$cv_table) }if (requireNamespace("pls", quietly = TRUE)) { set.seed(123) n <- 50 p <- 10 X <- matrix(rnorm(n * p), n, p) colnames(X) <- paste0("X", 1:p) Y <- X[, 1:3] %*% diag(c(1, 0.5, 0.3)) + matrix(rnorm(n * 3, 0, 0.5), n, 3) colnames(Y) <- paste0("Y", 1:3) result <- fit_pls_multivariate(X, Y, max_components = 8) print(result$optimal_ncomp) print(result$cv_table) }
Fits a two-way fixed effects model with sector and time effects, regressing log production prices on log direct prices.
fit_twoway_fe( panel_data, robust_se = TRUE, cluster_type = c("group", "time", "twoway") )fit_twoway_fe( panel_data, robust_se = TRUE, cluster_type = c("group", "time", "twoway") )
panel_data |
Data frame in panel format with columns: year, sector, log_direct, log_production. |
robust_se |
Logical. Compute robust standard errors. Default TRUE. |
cluster_type |
Character. Type of cluster for robust SE. One of "group", "time", or "twoway". Default "group". |
This function requires the 'plm' package. The model specification is: log_production ~ log_direct with two-way (sector and time) fixed effects.
A list containing:
The fitted plm model object
Model summary
Within R-squared
Coefficient test with robust SE (if robust_se=TRUE)
In-sample evaluation metrics
if (requireNamespace("plm", quietly = TRUE)) { set.seed(123) panel <- data.frame( year = rep(2000:2009, 5), sector = rep(LETTERS[1:5], each = 10), log_direct = rnorm(50, 5, 0.5), log_production = rnorm(50, 5, 0.5) ) panel$log_production <- panel$log_direct * 0.95 + rnorm(50, 0, 0.1) result <- fit_twoway_fe(panel) print(result$r2_within) }if (requireNamespace("plm", quietly = TRUE)) { set.seed(123) panel <- data.frame( year = rep(2000:2009, 5), sector = rep(LETTERS[1:5], each = 10), log_direct = rnorm(50, 5, 0.5), log_production = rnorm(50, 5, 0.5) ) panel$log_production <- panel$log_direct * 0.95 + rnorm(50, 0, 0.1) result <- fit_twoway_fe(panel) print(result$r2_within) }
Creates a formatted summary of structural break test results.
format_break_results(break_results, alpha = 0.05)format_break_results(break_results, alpha = 0.05)
break_results |
Result from test_structural_breaks. |
alpha |
Significance level for interpretation. Default 0.05. |
A data frame with formatted test summaries.
if (requireNamespace("strucchange", quietly = TRUE)) { set.seed(123) years <- 1980:2020 panel <- data.frame( year = rep(years, 5), sector = rep(LETTERS[1:5], each = length(years)), log_direct = rnorm(length(years) * 5, 5, 0.5), log_production = rnorm(length(years) * 5, 5, 0.5) ) break_tests <- test_structural_breaks(panel) summary_df <- format_break_results(break_tests) print(summary_df) }if (requireNamespace("strucchange", quietly = TRUE)) { set.seed(123) years <- 1980:2020 panel <- data.frame( year = rep(years, 5), sector = rep(LETTERS[1:5], each = length(years)), log_direct = rnorm(length(years) * 5, 5, 0.5), log_production = rnorm(length(years) * 5, 5, 0.5) ) break_tests <- test_structural_breaks(panel) summary_df <- format_break_results(break_tests) print(summary_df) }
Creates a complete summary of all analysis results including models, validation, and structural break tests.
generate_analysis_summary( comparison_table, cv_summary = NULL, break_results = NULL, cca_results = NULL, granger_results = NULL )generate_analysis_summary( comparison_table, cv_summary = NULL, break_results = NULL, cca_results = NULL, granger_results = NULL )
comparison_table |
Data frame from compare_models. |
cv_summary |
Data frame from summarize_cv_results (or NULL). |
break_results |
Result from test_structural_breaks (or NULL). |
cca_results |
Result from run_sparse_cca (or NULL). |
granger_results |
Data frame from panel_granger_test (or NULL). |
A list with formatted summary components.
comparison <- data.frame( model = c("Model A", "Model B"), R2 = c(0.95, 0.92), RMSE_log = c(0.05, 0.06) ) summary_list <- generate_analysis_summary(comparison) print(summary_list$best_model)comparison <- data.frame( model = c("Model A", "Model B"), R2 = c(0.95, 0.92), RMSE_log = c(0.05, 0.06) ) summary_list <- generate_analysis_summary(comparison) print(summary_list$best_model)
Attempts to extract R-squared using loo_R2, falling back to bayes_R2.
get_r2_values(fit, verbose = FALSE)get_r2_values(fit, verbose = FALSE)
fit |
A fitted rstanarm model object. |
verbose |
Logical. Print messages about extraction method. Default FALSE. |
A named numeric vector with mean, median, and mode R-squared values.
if (requireNamespace("rstanarm", quietly = TRUE)) { data(mtcars) fit <- rstanarm::stan_glm(mpg ~ wt, data = mtcars, chains = 2, iter = 1000, refresh = 0) get_r2_values(fit) }if (requireNamespace("rstanarm", quietly = TRUE)) { data(mtcars) fit <- rstanarm::stan_glm(mpg ~ wt, data = mtcars, chains = 2, iter = 1000, refresh = 0) get_r2_values(fit) }
Provides textual interpretation of structural break tests.
interpret_break_tests(break_results, alpha = 0.05)interpret_break_tests(break_results, alpha = 0.05)
break_results |
Result from test_structural_breaks. |
alpha |
Significance level. Default 0.05. |
Character string with interpretation.
if (requireNamespace("strucchange", quietly = TRUE)) { set.seed(123) years <- 1980:2020 panel <- data.frame( year = rep(years, 5), sector = rep(LETTERS[1:5], each = length(years)), log_direct = rnorm(length(years) * 5, 5, 0.5), log_production = rnorm(length(years) * 5, 5, 0.5) ) break_tests <- test_structural_breaks(panel) interpretation <- interpret_break_tests(break_tests) cat(interpretation) }if (requireNamespace("strucchange", quietly = TRUE)) { set.seed(123) years <- 1980:2020 panel <- data.frame( year = rep(years, 5), sector = rep(LETTERS[1:5], each = length(years)), log_direct = rnorm(length(years) * 5, 5, 0.5), log_production = rnorm(length(years) * 5, 5, 0.5) ) break_tests <- test_structural_breaks(panel) interpretation <- interpret_break_tests(break_tests) cat(interpretation) }
Performs LOSO CV, leaving out each sector in turn as the test set.
leave_one_sector_out(panel_data, verbose = TRUE)leave_one_sector_out(panel_data, verbose = TRUE)
panel_data |
Data frame in panel format. |
verbose |
Logical. Print progress. Default TRUE. |
A data frame with RMSE and MAE for each held-out sector.
if (requireNamespace("plm", quietly = TRUE)) { set.seed(123) panel <- data.frame( year = rep(2000:2019, 5), sector = rep(LETTERS[1:5], each = 20), log_direct = rnorm(100, 5, 0.5), log_production = rnorm(100, 5, 0.5) ) panel$log_production <- panel$log_direct * 0.95 + rnorm(100, 0, 0.1) loso_results <- leave_one_sector_out(panel) print(loso_results) }if (requireNamespace("plm", quietly = TRUE)) { set.seed(123) panel <- data.frame( year = rep(2000:2019, 5), sector = rep(LETTERS[1:5], each = 20), log_direct = rnorm(100, 5, 0.5), log_production = rnorm(100, 5, 0.5) ) panel$log_production <- panel$log_direct * 0.95 + rnorm(100, 0, 0.1) loso_results <- leave_one_sector_out(panel) print(loso_results) }
Performs panel Granger causality tests between direct and production prices.
panel_granger_test(panel_data, lags = c(1L, 2L))panel_granger_test(panel_data, lags = c(1L, 2L))
panel_data |
Data frame in panel format. |
lags |
Integer vector of lag orders to test. Default c(1, 2). |
Tests both directions: direct -> production and production -> direct.
A data frame with test results for each direction and lag.
if (requireNamespace("plm", quietly = TRUE)) { set.seed(123) panel <- data.frame( year = rep(2000:2019, 5), sector = rep(LETTERS[1:5], each = 20), log_direct = rnorm(100, 5, 0.5), log_production = rnorm(100, 5, 0.5) ) granger_results <- panel_granger_test(panel) print(granger_results) }if (requireNamespace("plm", quietly = TRUE)) { set.seed(123) panel <- data.frame( year = rep(2000:2019, 5), sector = rep(LETTERS[1:5], each = 20), log_direct = rnorm(100, 5, 0.5), log_production = rnorm(100, 5, 0.5) ) granger_results <- panel_granger_test(panel) print(granger_results) }
Functions for fitting two-way fixed effects and Mundlak CRE models.
Functions for multivariate PLS regression with cross-validation.
Generate predictions from a fitted PLS model.
predict_pls(pls_result, newdata = NULL, ncomp = NULL)predict_pls(pls_result, newdata = NULL, ncomp = NULL)
pls_result |
Result from fit_pls_multivariate. |
newdata |
Optional new data matrix for prediction. |
ncomp |
Number of components to use. Default uses optimal. |
Matrix of predictions.
if (requireNamespace("pls", quietly = TRUE)) { set.seed(123) n <- 50 p <- 10 X <- matrix(rnorm(n * p), n, p) colnames(X) <- paste0("X", 1:p) Y <- X[, 1:3] %*% diag(c(1, 0.5, 0.3)) + matrix(rnorm(n * 3, 0, 0.5), n, 3) colnames(Y) <- paste0("Y", 1:3) result <- fit_pls_multivariate(X, Y, max_components = 5) preds <- predict_pls(result) dim(preds) }if (requireNamespace("pls", quietly = TRUE)) { set.seed(123) n <- 50 p <- 10 X <- matrix(rnorm(n * p), n, p) colnames(X) <- paste0("X", 1:p) Y <- X[, 1:3] %*% diag(c(1, 0.5, 0.3)) + matrix(rnorm(n * 3, 0, 0.5), n, 3) colnames(Y) <- paste0("Y", 1:3) result <- fit_pls_multivariate(X, Y, max_components = 5) preds <- predict_pls(result) dim(preds) }
Extracts numeric columns from price data frames and applies log transform.
prepare_log_matrices( direct_prices, production_prices, exclude_cols = c("Year") )prepare_log_matrices( direct_prices, production_prices, exclude_cols = c("Year") )
direct_prices |
Data frame with direct prices. |
production_prices |
Data frame with prices of production. |
exclude_cols |
Character vector of columns to exclude. Default c("Year"). |
A list containing:
Log-transformed matrix of direct prices
Log-transformed matrix of production prices
Logical vector indicating complete cases
Subset of X_log with complete cases
Subset of Y_log with complete cases
set.seed(123) direct <- data.frame( Year = 2000:2005, A = runif(6, 100, 200), B = runif(6, 100, 200) ) production <- data.frame( Year = 2000:2005, A = runif(6, 100, 200), B = runif(6, 100, 200) ) matrices <- prepare_log_matrices(direct, production) str(matrices)set.seed(123) direct <- data.frame( Year = 2000:2005, A = runif(6, 100, 200), B = runif(6, 100, 200) ) production <- data.frame( Year = 2000:2005, A = runif(6, 100, 200), B = runif(6, 100, 200) ) matrices <- prepare_log_matrices(direct, production) str(matrices)
Converts wide-format price matrices (with Year as first column and sectors as subsequent columns) into long-format panel data suitable for panel regression analysis.
prepare_panel_data(direct_prices, production_prices, log_transform = TRUE)prepare_panel_data(direct_prices, production_prices, log_transform = TRUE)
direct_prices |
Data frame with direct prices (labor value-based). First column must be 'Year', remaining columns are sector values. |
production_prices |
Data frame with prices of production. Must have same structure as direct_prices. |
log_transform |
Logical. Apply natural log transformation. Default TRUE. |
A data frame in panel (long) format with columns:
Year of observation
Sector identifier
Numeric sector identifier
Time index (year minus minimum year plus 1)
Direct price value
Price of production value
Log of direct price (if log_transform = TRUE)
Log of production price (if log_transform = TRUE)
set.seed(123) years <- 2000:2010 sectors <- c("Agriculture", "Manufacturing", "Services") direct <- data.frame( Year = years, Agriculture = 100 + cumsum(rnorm(11)), Manufacturing = 120 + cumsum(rnorm(11)), Services = 90 + cumsum(rnorm(11)) ) production <- data.frame( Year = years, Agriculture = 102 + cumsum(rnorm(11)), Manufacturing = 118 + cumsum(rnorm(11)), Services = 92 + cumsum(rnorm(11)) ) panel <- prepare_panel_data(direct, production) head(panel)set.seed(123) years <- 2000:2010 sectors <- c("Agriculture", "Manufacturing", "Services") direct <- data.frame( Year = years, Agriculture = 100 + cumsum(rnorm(11)), Manufacturing = 120 + cumsum(rnorm(11)), Services = 90 + cumsum(rnorm(11)) ) production <- data.frame( Year = years, Agriculture = 102 + cumsum(rnorm(11)), Manufacturing = 118 + cumsum(rnorm(11)), Services = 92 + cumsum(rnorm(11)) ) panel <- prepare_panel_data(direct, production) head(panel)
Prints a formatted summary of analysis results to console.
print_analysis_summary(summary_list, verbose = TRUE)print_analysis_summary(summary_list, verbose = TRUE)
summary_list |
Result from generate_analysis_summary. |
verbose |
Logical. Print detailed output. Default TRUE. |
Invisible NULL.
comparison <- data.frame( model = c("Two-Way FE", "Mundlak CRE"), R2 = c(0.95, 0.92), RMSE_log = c(0.05, 0.06) ) summary_list <- generate_analysis_summary(comparison) print_analysis_summary(summary_list)comparison <- data.frame( model = c("Two-Way FE", "Mundlak CRE"), R2 = c(0.95, 0.92), RMSE_log = c(0.05, 0.06) ) summary_list <- generate_analysis_summary(comparison) print_analysis_summary(summary_list)
Computes mean, standard deviation, median, MAD, trimmed mean, and bootstrap confidence intervals for a numeric vector.
robust_summary(x, bootstrap_reps = 200L, trim_proportion = 0.1)robust_summary(x, bootstrap_reps = 200L, trim_proportion = 0.1)
x |
Numeric vector. |
bootstrap_reps |
Number of bootstrap replications for CI. Default 200. |
trim_proportion |
Proportion to trim for trimmed mean. Default 0.10. |
A list containing:
Arithmetic mean
Standard deviation
Median
Median Absolute Deviation (scaled)
Trimmed mean
Vector of length 2 with 95 percent bootstrap CI bounds
set.seed(123) x <- rnorm(50) robust_summary(x)set.seed(123) x <- rnorm(50) robust_summary(x)
Performs time-series cross-validation using rolling windows, comparing fixed effects and Mundlak models.
rolling_window_cv( panel_data, window_sizes = c(20L, 30L), step_size = 2L, test_horizon = 3L, verbose = TRUE )rolling_window_cv( panel_data, window_sizes = c(20L, 30L), step_size = 2L, test_horizon = 3L, verbose = TRUE )
panel_data |
Data frame in panel format. |
window_sizes |
Integer vector of training window sizes. Default c(20, 30). |
step_size |
Integer step between windows. Default 2. |
test_horizon |
Integer number of periods to forecast. Default 3. |
verbose |
Logical. Print progress. Default TRUE. |
For each rolling window, the function fits both a fixed effects model (by sector) and a Mundlak CRE model, then evaluates predictions on the test period. Results are separated by whether test sectors were seen during training (common) or not (new).
A data frame with validation results for each window, including:
Training window size
Start year of training window
End year of training window
RMSE for FE model on all test observations
RMSE for Mundlak model on all test observations
Number of test obs from sectors in training
Number of test obs from new sectors
if (requireNamespace("plm", quietly = TRUE)) { set.seed(123) panel <- data.frame( year = rep(2000:2029, 5), sector = rep(LETTERS[1:5], each = 30), log_direct = rnorm(150, 5, 0.5), log_production = rnorm(150, 5, 0.5) ) panel$log_production <- panel$log_direct * 0.95 + rnorm(150, 0, 0.1) cv_results <- rolling_window_cv(panel, window_sizes = c(15, 20)) print(head(cv_results)) }if (requireNamespace("plm", quietly = TRUE)) { set.seed(123) panel <- data.frame( year = rep(2000:2029, 5), sector = rep(LETTERS[1:5], each = 30), log_direct = rnorm(150, 5, 0.5), log_production = rnorm(150, 5, 0.5) ) panel$log_production <- panel$log_direct * 0.95 + rnorm(150, 0, 0.1) cv_results <- rolling_window_cv(panel, window_sizes = c(15, 20)) print(head(cv_results)) }
Convenience function to run both sparse CCA and panel/aggregated VAR.
run_cca_var_analysis( direct_prices, production_prices, panel_data, cca_components = 3L, verbose = TRUE )run_cca_var_analysis( direct_prices, production_prices, panel_data, cca_components = 3L, verbose = TRUE )
direct_prices |
Data frame with direct prices. |
production_prices |
Data frame with production prices. |
panel_data |
Data frame in panel format. |
cca_components |
Number of CCA components. Default 3. |
verbose |
Logical. Print progress. Default TRUE. |
A list with cca, pvar, agg_var, and granger results.
set.seed(123) years <- 2000:2019 sectors <- LETTERS[1:5] direct <- data.frame(Year = years) production <- data.frame(Year = years) for (s in sectors) { direct[[s]] <- 100 + cumsum(rnorm(20, 2, 1)) production[[s]] <- 102 + cumsum(rnorm(20, 2, 1)) } panel <- prepare_panel_data(direct, production) matrices <- prepare_log_matrices(direct, production) result <- run_cca_var_analysis( direct, production, panel, cca_components = 2 )set.seed(123) years <- 2000:2019 sectors <- LETTERS[1:5] direct <- data.frame(Year = years) production <- data.frame(Year = years) for (s in sectors) { direct[[s]] <- 100 + cumsum(rnorm(20, 2, 1)) production[[s]] <- 102 + cumsum(rnorm(20, 2, 1)) } panel <- prepare_panel_data(direct, production) matrices <- prepare_log_matrices(direct, production) result <- run_cca_var_analysis( direct, production, panel, cca_components = 2 )
Convenience function to run the full analysis pipeline.
run_full_analysis( direct_prices, production_prices, run_bayesian = FALSE, run_cv = TRUE, run_breaks = TRUE, verbose = TRUE )run_full_analysis( direct_prices, production_prices, run_bayesian = FALSE, run_cv = TRUE, run_breaks = TRUE, verbose = TRUE )
direct_prices |
Data frame with direct prices. |
production_prices |
Data frame with production prices. |
run_bayesian |
Logical. Run Bayesian models. Default FALSE. |
run_cv |
Logical. Run cross-validation. Default TRUE. |
run_breaks |
Logical. Run structural break tests. Default TRUE. |
verbose |
Logical. Print progress. Default TRUE. |
A list with all analysis results.
set.seed(123) years <- 2000:2019 sectors <- LETTERS[1:5] direct <- data.frame(Year = years) production <- data.frame(Year = years) for (s in sectors) { direct[[s]] <- 100 + cumsum(rnorm(20, 2, 1)) production[[s]] <- 102 + cumsum(rnorm(20, 2, 1)) } if (requireNamespace("plm", quietly = TRUE)) { results <- run_full_analysis( direct, production, run_bayesian = FALSE, run_cv = FALSE ) print(results$comparison) }set.seed(123) years <- 2000:2019 sectors <- LETTERS[1:5] direct <- data.frame(Year = years) production <- data.frame(Year = years) for (s in sectors) { direct[[s]] <- 100 + cumsum(rnorm(20, 2, 1)) production[[s]] <- 102 + cumsum(rnorm(20, 2, 1)) } if (requireNamespace("plm", quietly = TRUE)) { results <- run_full_analysis( direct, production, run_bayesian = FALSE, run_cv = FALSE ) print(results$comparison) }
Performs canonical correlation analysis on PCA-reduced price matrices, with optional sparsity penalties.
run_sparse_cca( X_matrix, Y_matrix, n_components = 3L, variance_threshold = 0.9, min_pcs = 8L, max_pcs = 12L )run_sparse_cca( X_matrix, Y_matrix, n_components = 3L, variance_threshold = 0.9, min_pcs = 8L, max_pcs = 12L )
X_matrix |
Numeric matrix of direct prices. |
Y_matrix |
Numeric matrix of production prices. |
n_components |
Number of canonical components to extract. Default 3. |
variance_threshold |
Cumulative variance threshold for PCA. Default 0.90. |
min_pcs |
Minimum number of PCs to retain. Default 8. |
max_pcs |
Maximum number of PCs to retain. Default 12. |
The function first reduces dimensionality using PCA, then applies CCA. Falls back to base R cancor if specialized packages unavailable.
A list containing:
Method used for CCA
Canonical correlations
X loadings in PC space
Y loadings in PC space
X loadings projected to original variables
Y loadings projected to original variables
Number of PCs used for X
Number of PCs used for Y
set.seed(123) n <- 50 p <- 20 X <- matrix(rnorm(n * p), n, p) Y <- X %*% matrix(rnorm(p * 5), p, 5) + matrix(rnorm(n * 5, 0, 0.5), n, 5) colnames(X) <- paste0("X", 1:p) colnames(Y) <- paste0("Y", 1:5) result <- run_sparse_cca(X, Y, n_components = 2) print(result$correlations)set.seed(123) n <- 50 p <- 20 X <- matrix(rnorm(n * p), n, p) Y <- X %*% matrix(rnorm(p * 5), p, 5) + matrix(rnorm(n * 5, 0, 0.5), n, 5) colnames(X) <- paste0("X", 1:p) colnames(Y) <- paste0("Y", 1:5) result <- run_sparse_cca(X, Y, n_components = 2) print(result$correlations)
Calculates Mean Absolute Error handling non-finite values.
safe_mae(actual, predicted)safe_mae(actual, predicted)
actual |
Numeric vector of actual values. |
predicted |
Numeric vector of predicted values. |
A single numeric value for MAE, or NA if calculation not possible.
actual <- c(1, 2, 3, 4, 5) predicted <- c(1.1, 2.2, 2.9, 4.1, 5.2) safe_mae(actual, predicted)actual <- c(1, 2, 3, 4, 5) predicted <- c(1.1, 2.2, 2.9, 4.1, 5.2) safe_mae(actual, predicted)
Calculates percentage while handling division by zero and non-finite values.
safe_pct(numerator, denominator)safe_pct(numerator, denominator)
numerator |
Numeric vector for the numerator. |
denominator |
Numeric vector for the denominator. |
Numeric vector of percentages, with NA for invalid calculations.
safe_pct(c(10, 20, 30), c(100, 0, 200))safe_pct(c(10, 20, 30), c(100, 0, 200))
Calculates Root Mean Squared Error handling non-finite values.
safe_rmse(actual, predicted)safe_rmse(actual, predicted)
actual |
Numeric vector of actual values. |
predicted |
Numeric vector of predicted values. |
A single numeric value for RMSE, or NA if calculation not possible.
actual <- c(1, 2, 3, 4, 5) predicted <- c(1.1, 2.2, 2.9, 4.1, 5.2) safe_rmse(actual, predicted)actual <- c(1, 2, 3, 4, 5) predicted <- c(1.1, 2.2, 2.9, 4.1, 5.2) safe_rmse(actual, predicted)
Functions for testing structural breaks in the price relationship.
Computes summary statistics from rolling window cross-validation.
summarize_cv_results(cv_results, bootstrap_reps = 300L)summarize_cv_results(cv_results, bootstrap_reps = 300L)
cv_results |
Data frame from rolling_window_cv. |
bootstrap_reps |
Number of bootstrap replications. Default 300. |
A data frame with summary statistics by model and partition.
if (requireNamespace("plm", quietly = TRUE)) { set.seed(123) panel <- data.frame( year = rep(2000:2029, 5), sector = rep(LETTERS[1:5], each = 30), log_direct = rnorm(150, 5, 0.5), log_production = rnorm(150, 5, 0.5) ) panel$log_production <- panel$log_direct * 0.95 + rnorm(150, 0, 0.1) cv_results <- rolling_window_cv(panel, window_sizes = c(15, 20)) summary_stats <- summarize_cv_results(cv_results) print(summary_stats) }if (requireNamespace("plm", quietly = TRUE)) { set.seed(123) panel <- data.frame( year = rep(2000:2029, 5), sector = rep(LETTERS[1:5], each = 30), log_direct = rnorm(150, 5, 0.5), log_production = rnorm(150, 5, 0.5) ) panel$log_production <- panel$log_direct * 0.95 + rnorm(150, 0, 0.1) cv_results <- rolling_window_cv(panel, window_sizes = c(15, 20)) summary_stats <- summarize_cv_results(cv_results) print(summary_stats) }
Functions for comparing models and generating summary tables.
Performs Wald test on the sector-mean coefficient to test whether fixed effects would be preferred over random effects.
test_mundlak_specification(mundlak_result)test_mundlak_specification(mundlak_result)
mundlak_result |
Result from fit_mundlak_cre. |
Under the null hypothesis that the sector means coefficient equals zero, random effects would be appropriate. Rejection suggests fixed effects should be used.
A list with test statistic, degrees of freedom, and p-value.
if (requireNamespace("plm", quietly = TRUE)) { set.seed(123) panel <- data.frame( year = rep(2000:2009, 5), sector = rep(LETTERS[1:5], each = 10), log_direct = rnorm(50, 5, 0.5), log_production = rnorm(50, 5, 0.5) ) panel$log_production <- panel$log_direct * 0.95 + rnorm(50, 0, 0.1) mundlak_fit <- fit_mundlak_cre(panel) test_result <- test_mundlak_specification(mundlak_fit) print(test_result) }if (requireNamespace("plm", quietly = TRUE)) { set.seed(123) panel <- data.frame( year = rep(2000:2009, 5), sector = rep(LETTERS[1:5], each = 10), log_direct = rnorm(50, 5, 0.5), log_production = rnorm(50, 5, 0.5) ) panel$log_production <- panel$log_direct * 0.95 + rnorm(50, 0, 0.1) mundlak_fit <- fit_mundlak_cre(panel) test_result <- test_mundlak_specification(mundlak_fit) print(test_result) }
Performs multiple structural break tests on the aggregated time series relationship between direct and production prices.
test_structural_breaks(panel_data, chow_years = NULL, min_segment = 10L)test_structural_breaks(panel_data, chow_years = NULL, min_segment = 10L)
panel_data |
Data frame in panel format. |
chow_years |
Integer vector of candidate break years for Chow test. Default NULL uses 1986, 1997, 2001, 2008 if present. |
min_segment |
Integer minimum observations per segment. Default 10. |
This function aggregates panel data to a single time series by taking means across sectors, then applies various structural break tests from the strucchange package.
A list containing:
Chow test results for candidate years
CUSUM test results
MOSUM test results
supremum F test results
Estimated breakpoint dates
The aggregated time series used
if (requireNamespace("strucchange", quietly = TRUE)) { set.seed(123) years <- 1980:2020 panel <- data.frame( year = rep(years, 5), sector = rep(LETTERS[1:5], each = length(years)), log_direct = rnorm(length(years) * 5, 5, 0.5), log_production = rnorm(length(years) * 5, 5, 0.5) ) break_tests <- test_structural_breaks(panel) print(break_tests$cusum) }if (requireNamespace("strucchange", quietly = TRUE)) { set.seed(123) years <- 1980:2020 panel <- data.frame( year = rep(years, 5), sector = rep(LETTERS[1:5], each = length(years)), log_direct = rnorm(length(years) * 5, 5, 0.5), log_production = rnorm(length(years) * 5, 5, 0.5) ) break_tests <- test_structural_breaks(panel) print(break_tests$cusum) }
Internal utility functions used across the package.
Checks that panel data has required columns and valid structure.
validate_panel_data(panel_data, require_log = TRUE)validate_panel_data(panel_data, require_log = TRUE)
panel_data |
Data frame to validate. |
require_log |
Logical. Check for log-transformed columns. Default TRUE. |
TRUE invisibly if valid, otherwise stops with informative error.
set.seed(123) panel <- data.frame( year = rep(2000:2002, 3), sector = rep(c("A", "B", "C"), each = 3), log_direct = rnorm(9), log_production = rnorm(9) ) validate_panel_data(panel)set.seed(123) panel <- data.frame( year = rep(2000:2002, 3), sector = rep(c("A", "B", "C"), each = 3), log_direct = rnorm(9), log_production = rnorm(9) ) validate_panel_data(panel)
Functions for rolling window and leave-one-sector-out validation.