| Title: | Interactive Tabular Matrix Problems via Pseudoinverse Estimation |
|---|---|
| Description: | Provides an interactive wrapper for the 'tmpinv()' function from the 'rtmpinv' package with options extending its functionality to pre- and post-estimation processing and streamlined incorporation of prior cell information. The Tabular Matrix Problems via Pseudoinverse Estimation (TMPinv) is a two-stage estimation method that reformulates structured table-based systems - such as allocation problems, transaction matrices, and input-output tables - as structured least-squares problems. Based on the Convex Least Squares Programming (CLSP) framework, TMPinv solves systems with row and column constraints, block structure, and optionally reduced dimensionality by (1) constructing a canonical constraint form and applying a pseudoinverse-based projection, followed by (2) a convex-programming refinement stage to improve fit, coherence, and regularization (e.g., via Lasso, Ridge, or Elastic Net). |
| Authors: | Ilya Bolotov [aut, cre] (ORCID: <https://orcid.org/0000-0003-1148-7144>) |
| Maintainer: | Ilya Bolotov <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 2.0.0 |
| Built: | 2026-06-07 23:03:09 UTC |
| Source: | https://github.com/econcz/rtmpinvi |
Solve an interactive tabular matrix estimation problem via Convex Least Squares Programming (CLSP).
tmpinvi( ival = NULL, ibounds = NULL, preestimation = NULL, postestimation = NULL, update = FALSE, ... )tmpinvi( ival = NULL, ibounds = NULL, preestimation = NULL, postestimation = NULL, update = FALSE, ... )
ival |
NULL, numeric matrix, or data.frame.
Prior information on known cell values. If supplied and not entirely
missing, |
ibounds |
NULL, |
preestimation |
NULL or function.
A function executed prior to model estimation. If supplied,
it is called as |
postestimation |
NULL or function.
A function executed after model estimation. For a full model,
it is called as |
update |
logical scalar, default = |
... |
Additional arguments passed to |
An object of class "tmpinvi" with components:
result: a fitted object of class "tmpinv".
data: the processed matrix (either the fitted solution
x or the updated ival, depending on update).
RNGkind("L'Ecuyer-CMRG") set.seed(123456789) iso2 <- c("CN", "DE", "JP", "NL", "US") T <- 10L year <- (as.integer(format(Sys.Date(), "%Y")) - T) + seq_len(T) m <- length(iso2) df <- expand.grid(year = year, iso2 = iso2, KEEP.OUT.ATTRS = FALSE) df <- df[order(df$year, df$iso2), ] ex_cols <- paste0("EX_", iso2) df[ex_cols] <- NA_real_ df$EX <- NA_real_ df$IM <- NA_real_ X_true <- vector("list", length(year)) names(X_true) <- as.character(year) for (t in seq_along(year)) { scale <- 1000 * (1.05^(t - 1L)) X <- matrix(runif(m * m, 0, scale), m, m) diag(X) <- 0 X_true[[t]] <- X rows <- ((t - 1L) * m + 1L):((t - 1L) * m + m) df$EX[rows] <- rowSums(X) df$IM[rows] <- colSums(X) miss <- matrix(runif(m * m) > 0.5, m, m) X[miss] <- NA_real_ df[rows, ex_cols] <- X } cv <- qnorm(0.975) for (nm in ex_cols) { fit <- lm(df[[nm]] ~ year * iso2, data = df, na.action = na.exclude) pr <- predict(fit, df, se.fit = TRUE) ub <- pr$fit + cv * pr$se.fit ub[ub < 0] <- NA_real_ df[[paste0("_", nm, "_lb")]] <- 0 df[[paste0("_", nm, "_ub")]] <- ub } make_bounds <- function(lb, ub) Map(function(a, b) c(a, b), lb, ub) df_out <- df for (step in 1:2) { for (y in year) { idx <- df_out$year == y d <- df_out[idx, ] ival <- as.matrix(d[ex_cols]) lb <- as.vector(t(as.matrix(d[paste0("_EX_", iso2, "_lb")]))) ub <- as.vector(t(as.matrix(d[paste0("_EX_", iso2, "_ub")]))) fit <- tmpinvi( ival = ival, ibounds = make_bounds(lb, ub), b_row = d$EX, b_col = d$IM, alpha = 1.0, update = TRUE ) df_out[idx, ex_cols] <- fit$data } } drop_cols <- grep("^_EX_.*_(lb|ub)$", names(df_out), value = TRUE) df_out[drop_cols] <- NULL df_outRNGkind("L'Ecuyer-CMRG") set.seed(123456789) iso2 <- c("CN", "DE", "JP", "NL", "US") T <- 10L year <- (as.integer(format(Sys.Date(), "%Y")) - T) + seq_len(T) m <- length(iso2) df <- expand.grid(year = year, iso2 = iso2, KEEP.OUT.ATTRS = FALSE) df <- df[order(df$year, df$iso2), ] ex_cols <- paste0("EX_", iso2) df[ex_cols] <- NA_real_ df$EX <- NA_real_ df$IM <- NA_real_ X_true <- vector("list", length(year)) names(X_true) <- as.character(year) for (t in seq_along(year)) { scale <- 1000 * (1.05^(t - 1L)) X <- matrix(runif(m * m, 0, scale), m, m) diag(X) <- 0 X_true[[t]] <- X rows <- ((t - 1L) * m + 1L):((t - 1L) * m + m) df$EX[rows] <- rowSums(X) df$IM[rows] <- colSums(X) miss <- matrix(runif(m * m) > 0.5, m, m) X[miss] <- NA_real_ df[rows, ex_cols] <- X } cv <- qnorm(0.975) for (nm in ex_cols) { fit <- lm(df[[nm]] ~ year * iso2, data = df, na.action = na.exclude) pr <- predict(fit, df, se.fit = TRUE) ub <- pr$fit + cv * pr$se.fit ub[ub < 0] <- NA_real_ df[[paste0("_", nm, "_lb")]] <- 0 df[[paste0("_", nm, "_ub")]] <- ub } make_bounds <- function(lb, ub) Map(function(a, b) c(a, b), lb, ub) df_out <- df for (step in 1:2) { for (y in year) { idx <- df_out$year == y d <- df_out[idx, ] ival <- as.matrix(d[ex_cols]) lb <- as.vector(t(as.matrix(d[paste0("_EX_", iso2, "_lb")]))) ub <- as.vector(t(as.matrix(d[paste0("_EX_", iso2, "_ub")]))) fit <- tmpinvi( ival = ival, ibounds = make_bounds(lb, ub), b_row = d$EX, b_col = d$IM, alpha = 1.0, update = TRUE ) df_out[idx, ex_cols] <- fit$data } } drop_cols <- grep("^_EX_.*_(lb|ub)$", names(df_out), value = TRUE) df_out[drop_cols] <- NULL df_out