2020-06-10 14:35:27 +00:00
|
|
|
#' Longitudinal Sliced Inverse Regression
|
|
|
|
#'
|
|
|
|
#' @param X matrix of dim \eqn{n \times p t} with each row representing a
|
|
|
|
#' vectorized \eqn{p \times t} observation.
|
|
|
|
#' @param y vector of \eqn{n} elements as factors. (can be coersed to factors)
|
|
|
|
#' @param p,t,k,r dimensions.
|
|
|
|
#'
|
|
|
|
#' @returns a list with components
|
|
|
|
#' alpha: matrix of \eqn{t \times r}
|
|
|
|
#' beta: matrix of \eqn{p \times k}
|
|
|
|
#'
|
|
|
|
#' TODO: finish
|
|
|
|
#'
|
2021-10-29 16:16:40 +00:00
|
|
|
#' @export
|
2020-06-10 14:35:27 +00:00
|
|
|
LSIR <- function(X, y, p, t, k = 1L, r = 1L) {
|
|
|
|
# the code assumes:
|
|
|
|
# alpha: T x r, beta: p x k, X_i: p x T, for ith observation
|
2022-10-06 12:25:40 +00:00
|
|
|
|
2020-06-10 14:35:27 +00:00
|
|
|
# Check and transform parameters.
|
|
|
|
if (!is.matrix(X)) X <- as.matrix(X)
|
|
|
|
n <- nrow(X)
|
|
|
|
stopifnot(
|
|
|
|
ncol(X) == p * t,
|
|
|
|
n == length(y)
|
|
|
|
)
|
|
|
|
if (!is.factor(y)) y <- factor(y)
|
|
|
|
|
|
|
|
# Restructure X into a 3D tensor with axis (observations, predictors, time).
|
|
|
|
dim(X) <- c(n, p, t)
|
|
|
|
|
|
|
|
# Estimate predictor/time covariance matrices \hat{Sigma}_1, \hat{Sigma}_2.
|
|
|
|
sigma_p <- matrix(rowMeans(apply(X, 3, cov)), p, p)
|
|
|
|
sigma_t <- matrix(rowMeans(apply(X, 2, cov)), t, t)
|
|
|
|
|
|
|
|
# Normalize X as vec(Z) = Sigma^-1/2 (vec(X) - E(vec(X)))
|
|
|
|
dim(X) <- c(n, p * t)
|
|
|
|
sigma_p_isqrt <- matpow(sigma_p, -0.5)
|
|
|
|
sigma_t_isqrt <- matpow(sigma_t, -0.5)
|
|
|
|
Z <- scale(X, scale = FALSE) %*% kronecker(sigma_t_isqrt, sigma_p_isqrt)
|
|
|
|
# Both as 3D tensors.
|
|
|
|
dim(X) <- dim(Z) <- c(n, p, t)
|
|
|
|
|
|
|
|
# Estimate the conditional predictor/time covariance matrix Omega = cov(E(Z|Y)).
|
|
|
|
omega_p <- matrix(Reduce(`+`, lapply(levels(y), function(l) {
|
|
|
|
rowMeans(apply(Z[y == l, , ], 3, function(z) {
|
|
|
|
(nrow(z) / n) * tcrossprod(colMeans(z))
|
|
|
|
}))
|
|
|
|
})), p, p)
|
|
|
|
omega_t <- matrix(Reduce(`+`, lapply(levels(y), function(l) {
|
|
|
|
rowMeans(apply(Z[y == l, , ], 2, function(z) {
|
|
|
|
(nrow(z) / n) * tcrossprod(colMeans(z))
|
|
|
|
}))
|
|
|
|
})), t, t)
|
|
|
|
omega <- kronecker(omega_t, omega_p)
|
|
|
|
|
|
|
|
# Compute seperate SVD of estimated omega's and use that for an estimate of
|
|
|
|
# a central subspace basis.
|
|
|
|
svd_p <- La.svd(omega_p)
|
|
|
|
svd_t <- La.svd(omega_t)
|
|
|
|
beta <- sigma_p_isqrt %*% svd_p$u[, k]
|
|
|
|
alpha <- sigma_t_isqrt %*% svd_t$u[, r]
|
|
|
|
|
|
|
|
return(list(sigma_p = sigma_p, sigma_t = sigma_t,
|
|
|
|
sigma = kronecker(sigma_t, sigma_p),
|
|
|
|
alpha = alpha, beta = beta,
|
|
|
|
Delta = omega,
|
|
|
|
B = kronecker(alpha, beta)))
|
|
|
|
}
|