72 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			R
		
	
	
	
	
	
			
		
		
	
	
			72 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			R
		
	
	
	
	
	
#' 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)
 | 
						|
#'
 | 
						|
#' TODO: finish
 | 
						|
#'
 | 
						|
#' @export
 | 
						|
LSIR <- function(X, y,
 | 
						|
    reduction.dims = rep(1L, length(dim(X)) - 1L),
 | 
						|
    sample.axis = 1L,
 | 
						|
    nr.slices = 10L,    # default slices, ignored if y is a factor or integer
 | 
						|
    eps = sqrt(.Machine$double.eps),
 | 
						|
    slice.method = c("cut", "ecdf")   # ignored if y is a factor or integer
 | 
						|
) {
 | 
						|
    # In case of `y` not descrete, group `y` into slices
 | 
						|
    if (!(is.factor(y) || is.integer(y))) {
 | 
						|
        slice.method <- match.arg(slice.method)
 | 
						|
        if (slice.method == "ecdf") {
 | 
						|
            y <- cut(ecdf(y)(y), nr.slices)
 | 
						|
        } else {
 | 
						|
            y <- cut(y, nr.slices)
 | 
						|
            # ensure there are no empty slices
 | 
						|
            if (any(table(y) == 0)) {
 | 
						|
                y <- as.factor(as.integer(y))
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if (!is.factor(y)) {
 | 
						|
        y <- factor(y)
 | 
						|
    }
 | 
						|
 | 
						|
    stopifnot(dim(X)[sample.axis] == length(y))
 | 
						|
 | 
						|
    # rearrange `X` such that the first axis enumerates observations
 | 
						|
    axis.perm <- c(sample.axis, seq_along(dim(X))[-sample.axis])
 | 
						|
    X <- aperm(X, axis.perm)
 | 
						|
 | 
						|
    modes <- seq_along(dim(X))[-1L]
 | 
						|
    n <- dim(X)[1L]
 | 
						|
 | 
						|
    Sigmas <- lapply(seq_along(modes), function(i) {
 | 
						|
        matrix(rowMeans(apply(X, modes[-i], cov)), dim(X)[modes[i]])
 | 
						|
    })
 | 
						|
    # Omega_i = Sigma_i^{-1 / 2}
 | 
						|
    isqrt_Sigmas <- Map(matpow, Sigmas, -1 / 2)
 | 
						|
 | 
						|
    # Normalize observations
 | 
						|
    Z <- mlm(X - rep(colMeans(X), each = dim(X)[1L]), isqrt_Sigmas, modes = modes)
 | 
						|
    
 | 
						|
    # Estimate conditional covariances Omega = Cov(E[Z | Y])
 | 
						|
    slice.args <- c(
 | 
						|
        list(Z), rep(alist(, )[1], length(dim(X))), list(drop = FALSE)
 | 
						|
    )
 | 
						|
    Omegas <- lapply(seq_along(modes), function(i) {
 | 
						|
        matrix(Reduce(`+`, lapply(levels(y), function(l) {
 | 
						|
            slice.args[[2]] <- y == l
 | 
						|
            rowMeans(apply(do.call(`[`, slice.args), modes[-i], function(z) {
 | 
						|
                (nrow(z) / n) * tcrossprod(colMeans(z))
 | 
						|
            }))
 | 
						|
        })), dim(X)[modes[i]])
 | 
						|
    })
 | 
						|
 | 
						|
    # Compute central subspace basis estimate
 | 
						|
    betas <- mapply(function(isqrt_sigma, omega, reduction_dim) {
 | 
						|
        isqrt_sigma %*% La.svd(omega, reduction_dim, 0L)$u
 | 
						|
    }, isqrt_Sigmas, Omegas, reduction.dims, SIMPLIFY = FALSE)
 | 
						|
 | 
						|
    list(betas = betas, Sigmas = Sigmas, Omegas = Omegas)
 | 
						|
}
 |