Nothing
# Confidence Intervals for Trace of Covariance Matrices
#
# This implements asymptotic confidence intervals for the trace (sum of eigenvalues)
# of sample covariance matrices based on the CLT for linear spectral statistics.
#
# DONE: ✔️ Initial implementation using simplified Bai-Silverstein variance 12/28/2024
#' Calculate Confidence Interval for Trace of Covariance Matrices
#'
#' @description
#' This function uses asymptotic results from random matrix theory to calculate
#' approximate, normal theory confidence intervals for the trace (sum of eigenvalues)
#' of one or more sample covariance matrices.
#'
#' The trace of a covariance matrix equals the sum of its eigenvalues, which
#' represents the total variance in the system. For large samples, the trace
#' follows an approximate normal distribution with variance that can be
#' calculated from the eigenvalue structure.
#'
#' @details
#' The confidence interval is based on the asymptotic normality of the trace:
#' \deqn{ trace(\widehat{\Sigma}) \pm z_{1 - \alpha/2} \times SE }
#' where \eqn{\widehat{\Sigma}} is the sample covariance matrix and
#' \eqn{SE} is the standard error.
#'
#' The variance of the trace is calculated using the formula from
#' Bai & Silverstein (2004):
#' \deqn{ Var(trace) = \frac{2}{n} \sum_{i=1}^{p} \lambda_i^2 = \frac{2}{n} trace(\Sigma^2) }
#' where \eqn{\lambda_i} are the eigenvalues of \eqn{\Sigma}.
#'
#' This is a simplified version of the general CLT for linear spectral statistics.
#' For i.i.d. components with finite fourth moments, the trace is asymptotically
#' normal with this variance.
#'
#' **Asymptotic regime:** The theory applies when both sample size \eqn{n} and
#' dimension \eqn{p} can grow, typically requiring \eqn{n >> p} for good
#' finite-sample performance. The approximation improves as the sample size
#' increases.
#'
#' **Comparison with bootstrap:** For small to moderate samples, bootstrap
#' confidence intervals (see `eigstatCI()`) may provide better coverage.
#' This asymptotic approach is faster but may be anticonservative (too narrow)
#' when \eqn{n} is small relative to \eqn{p}.
#'
#' @param cov A covariance matrix or a (named) list of covariance matrices,
#' all the same size
#' @param n Sample size, or vector of sample sizes, one for each covariance
#' matrix
#' @param conf Confidence level (default: 0.95)
#'
#' @return A data frame with one row for each covariance matrix. Columns:
#' \describe{
#' \item{trace}{The trace (sum of eigenvalues) of the covariance matrix}
#' \item{se}{Standard error of the trace}
#' \item{lower}{Lower confidence limit}
#' \item{upper}{Upper confidence limit}
#' }
#'
#' @author Michael Friendly
#'
#' @seealso
#' `boxM()`, `plot.boxM()`, `logdetCI()`, `eigstatCI()`
#'
#' @references
#' Bai, Z. D., & Silverstein, J. W. (2004).
#' CLT for linear spectral statistics of large-dimensional sample covariance matrices.
#' *Annals of Probability*, 32(1A), 553-605.
#' \doi{10.1214/aop/1078415845}
#'
#' Anderson, T. W. (2003).
#' *An Introduction to Multivariate Statistical Analysis* (3rd ed.).
#' Wiley-Interscience.
#'
#' @keywords manip
#'
#' @examples
#' # Iris data example
#' data(iris)
#' iris.mod <- lm(as.matrix(iris[,1:4]) ~ iris$Species)
#' iris.boxm <- boxM(iris.mod)
#'
#' # Get covariance matrices
#' cov <- c(iris.boxm$cov, list(pooled = iris.boxm$pooled))
#' n <- c(rep(50, 3), 150)
#'
#' # Calculate trace CIs
#' CI <- traceCI(cov, n = n, conf = 0.95)
#' CI
#'
#' # Compare with plot
#' plot(iris.boxm, which = "sum", gplabel = "Species",
#' main = "Sum of eigenvalues (trace)")
#' arrows(CI$lower, 1:4, CI$upper, 1:4,
#' lwd = 3, angle = 90, length = 0.1, code = 3, col = "red")
#'
#' # Single covariance matrix
#' S <- cov(iris[,1:4])
#' traceCI(S, n = 150)
#'
#' # Compare different confidence levels
#' traceCI(cov, n = n, conf = 0.90)
#' traceCI(cov, n = n, conf = 0.95)
#' traceCI(cov, n = n, conf = 0.99)
#'
#' @export
traceCI <- function(cov, n, conf = 0.95) {
# Input validation
if (missing(cov)) {
stop("Argument 'cov' is required")
}
if (missing(n)) {
stop("Argument 'n' is required")
}
if (conf <= 0 || conf >= 1) {
stop("Confidence level 'conf' must be between 0 and 1")
}
# Get dimension p and ensure all matrices are same size
p <- if (is.list(cov)) {
sapply(cov, nrow)
} else {
nrow(cov)
}
if (length(p) > 1) {
if (!all(p == p[1])) {
stop("All covariance matrices must be the same size")
} else {
p <- p[1]
}
}
# Check sample size
if (any(n <= p)) {
warning(glue::glue(
"Sample size n should be larger than dimension p = {p} ",
"for asymptotic theory to apply"))
}
# Calculate trace for each covariance matrix
trace_vals <- if (is.list(cov)) {
sapply(cov, function(S) sum(diag(S)))
} else {
sum(diag(cov))
}
# Calculate variance of trace
# Var(trace) = 2/n * sum(lambda_i^2) = 2/n * trace(Sigma^2)
trace_sq_vals <- if (is.list(cov)) {
sapply(cov, function(S) sum(diag(S %*% S)))
} else {
sum(diag(cov %*% cov))
}
# Standard error
var_trace <- 2 / n * trace_sq_vals
se <- sqrt(var_trace)
# Confidence interval
z <- qnorm((1 - conf) / 2, lower.tail = FALSE)
lower <- trace_vals - z * se
upper <- trace_vals + z * se
# Return as data frame
result <- data.frame(
trace = trace_vals,
se = se,
lower = lower,
upper = upper,
row.names = if (is.list(cov)) names(cov) else NULL
)
return(result)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.