56 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			R
		
	
	
	
	
	
			
		
		
	
	
			56 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			R
		
	
	
	
	
	
#' A simple higher order (multi-way) canonical correlation analysis.
 | 
						|
#'
 | 
						|
#' @param X multi-dimensional array
 | 
						|
#' @param Y multi-dimensional array with the same nr. of dimensions and equal
 | 
						|
#'  sample axis to `X`.
 | 
						|
#' @param sample.axis integer indicationg which axis enumerates observations
 | 
						|
#'
 | 
						|
#' @export
 | 
						|
HOCCA <- function(X, Y, sample.axis = length(dim(X)), centerX = TRUE, centerY = TRUE) {
 | 
						|
 | 
						|
    # ensure sample axis is the last axis
 | 
						|
    if (!missing(sample.axis)) {
 | 
						|
        modes <- seq_along(dim(X))[-sample.axis]
 | 
						|
        X <- aperm(X, c(modes, sample.axis))
 | 
						|
        Y <- aperm(Y, c(modes, sample.axis))
 | 
						|
    }
 | 
						|
    modes <- seq_len(length(dim(X)) - 1L)
 | 
						|
    dimX <- head(dim(X), -1L)
 | 
						|
    dimF <- head(dim(F), -1L)
 | 
						|
    sample.size <- tail(dim(X), 1L)
 | 
						|
 | 
						|
    # center `X` and `Y`
 | 
						|
    if (centerX) {
 | 
						|
        X <- X - as.vector(rowMeans(X, dims = length(dim(X)) - 1L))
 | 
						|
    }
 | 
						|
    if (centerY) {
 | 
						|
        Y <- Y - as.vector(rowMeans(Y, dims = length(dim(Y)) - 1L))
 | 
						|
    }
 | 
						|
 | 
						|
    # estimate marginal covariance matrices
 | 
						|
    CovXX <- Map(function(mode) mcrossprod(X, mode = mode) / prod(dim(X)[-mode]), modes)
 | 
						|
    CovYY <- Map(function(mode) mcrossprod(Y, mode = mode) / prod(dim(Y)[-mode]), modes)
 | 
						|
    # and the "covariance tensor"
 | 
						|
    CovXY <- array(tcrossprod(mat(X, modes), mat(Y, modes)) / sample.size, c(dimX, dimF))
 | 
						|
 | 
						|
    # Compute standardized X and Y correlation tensor
 | 
						|
    SCovXY <- mlm(CovXY, Map(matpow, c(CovXX, CovYY), -1 / 2))
 | 
						|
 | 
						|
    # mode-wise canonical correlation directions
 | 
						|
    hosvd <- HOSVD(SCovXY, nu = rep(pmin(dimX, dimF), 2L))
 | 
						|
    dirsX <- hosvd$Us[modes]
 | 
						|
    dirsY <- hosvd$Us[modes + length(modes)]
 | 
						|
 | 
						|
    list(dirsX = dirsX, dirsY = dirsY)
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
# c(dirsX, dirsY) %<-% HOCCA(X, F)
 | 
						|
# B.hocca <- Reduce(kronecker, rev(Map(tcrossprod, dirsX, dirsY)))
 | 
						|
# dist.subspace(B.true, B.hocca, normalize = TRUE)
 | 
						|
# dist.subspace(B.true, Reduce(kronecker, rev(dirsX)), normalize = TRUE)
 | 
						|
 | 
						|
# cca <- cancor(mat(X, 4), mat(F, 4))
 | 
						|
# B.cca <- tcrossprod(cca$xcoef[, prod(dim(X)[-4])], cca$xcoef[, prod(dim(F)[-4])])
 | 
						|
# dist.subspace(B.true, cca$xcoef[, prod(dim(X)[-4])], normalize = TRUE)
 |