--- title: "glh" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{glh} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, warning = F, message = F, comment = "#>" ) ``` ```{r setup, include = F, echo = F} library(semnova) ``` # ๐Ÿ“˜ General Linear Hypothesis for Multigroup Models This derivation provides the foundation for constructing linear hypothesis tests across multiple groups in a multivariate setting using matrix vectorization. It is designed for use in models where each group has its own set of regression coefficients. --- ## ๐Ÿ”ข Model Setup We assume: - \( n_{ ext{groups}} \): number of groups - \( q \): number of repeated measures (outcomes) - \( p + 1 \): number of predictors including intercept - \( \mathbf{B}_g \in \mathbb{R}^{(p + 1) \times q} \): coefficient matrix for group \(g\) These matrices are stacked in a 3D array: \[ \mathbf{B}_{\text{array}}[(p + 1), q, n_{\text{groups}}] \] --- ## ๐ŸŽฏ Hypothesis of Interest We aim to test: \[ \mathbf{H}_0: \mathbf{G} \cdot (\mathbf{L} \cdot \mathbf{B}_g \cdot \mathbf{M}) = \mathbf{K} \] Where: | Symbol | Dimensions | Description | |----------------|----------------------------|-------------| | \( \mathbf{L} \) | \( h \times (p + 1) \) | Predictor contrast matrix | | \( \mathbf{M} \) | \( q \times r \) | Within-subject contrast matrix | | \( \mathbf{G} \) | \( d \times n_{\text{groups}} \) | Group contrast matrix | | \( \mathbf{K} \) | \( d \times h \times r \) | Target matrix (often 0) | --- ## ๐Ÿง  Vectorization Strategy ### Step 1: Single Group Transformation For each group \(g\): \[ \text{vec}(\mathbf{L} \cdot \mathbf{B}_g \cdot \mathbf{M}) = (\mathbf{M}^\top \otimes \mathbf{L}) \cdot \text{vec}(\mathbf{B}_g) \] This maps: \[ \text{vec}(\mathbf{B}_g) \in \mathbb{R}^{(p + 1) \cdot q} \quad \rightarrow \quad \text{vec}(\mathbf{L} \cdot \mathbf{B}_g \cdot \mathbf{M}) \in \mathbb{R}^{h \cdot r} \] --- ### Step 2: All Groups Transformation Stack all transformed groups: \[ \text{vec} \begin{bmatrix} \mathbf{L} \mathbf{B}_1 \mathbf{M} \\ \mathbf{L} \mathbf{B}_2 \mathbf{M} \\ \vdots \\ \mathbf{L} \mathbf{B}_{n_{\text{groups}}} \mathbf{M} \end{bmatrix} = \left( \mathbf{I}_{n_{\text{groups}}} \otimes (\mathbf{M}^\top \otimes \mathbf{L}) \right) \cdot \text{vec}(\mathbf{B}) \] Where: \[ \mathbf{B} = \begin{bmatrix} \mathbf{B}_1 \\ \vdots \\ \mathbf{B}_{n_{\text{groups}}} \end{bmatrix} \quad \Rightarrow \quad \text{vec}(\mathbf{B}) \in \mathbb{R}^{n_{\text{groups}} \cdot (p + 1) \cdot q} \] --- ### Step 3: Apply Group-Level Contrast The group contrast \( \mathbf{G} \in \mathbb{R}^{d \times n_{\text{groups}}} \) is applied as: \[ \mathbf{R} = (\mathbf{G} \otimes \mathbf{I}_{h \cdot r}) \cdot (\mathbf{I}_{n_{\text{groups}}} \otimes (\mathbf{M}^\top \otimes \mathbf{L})) \] Thus, the full hypothesis becomes: \[ \boxed{ \mathbf{H}_0: \mathbf{R} \cdot \text{vec}(\mathbf{B}) = \mathbf{k} } \] Where \( \mathbf{k} = \text{vec}(\mathbf{K}) \), often a zero vector. --- ## โœ… Dimensions Summary | Matrix | Dimensions | |----------------------|-------------| | \( \mathbf{B}_g \) | \( (p + 1) \times q \) | | \( \mathbf{L} \) | \( h \times (p + 1) \) | | \( \mathbf{M} \) | \( q \times r \) | | \( \mathbf{G} \) | \( d \times n_{\text{groups}} \) | | \( \text{vec}(\mathbf{B}) \) | \( n_{\text{groups}} \cdot (p + 1) \cdot q \times 1 \) | | \( \mathbf{R} \) | \( d \cdot h \cdot r \times n_{\text{groups}} \cdot (p + 1) \cdot q \) | | \( \mathbf{k} \) | \( d \cdot h \cdot r \times 1 \) | --- ## ๐Ÿ›  Code Implementation ```r construct_contrast_matrix <- function(B_array, G, L, M) { p1 <- dim(B_array)[1] # predictors (incl. intercept) q <- dim(B_array)[2] # repeated measures n_groups <- dim(B_array)[3] # number of groups h <- nrow(L) # predictor contrasts r <- ncol(M) # within-subject contrasts d <- nrow(G) # group contrasts vec_B <- as.vector(B_array) # vectorized coefficient matrix Rg <- kronecker(t(M), L) # (h * r) x (p1 * q) R_within <- kronecker(diag(n_groups), Rg) # (n_groups * h * r) x (n_groups * p1 * q) R <- kronecker(G, diag(h * r)) %*% R_within # (d * h * r) x (n_groups * p1 * q) return(list(R = R, vec_B = vec_B)) } ``` --- ## ๐Ÿงช Final Use To test: \[ \mathbf{H}_0: \mathbf{R} \cdot \text{vec}(\mathbf{B}) = \mathbf{k} \] Compute the residual: \[ \text{residual} = \mathbf{R} \cdot \text{vec}(\mathbf{B}) - \mathbf{k} \] This is used for: - **Wald tests** - **F-tests** - **Multivariate test statistics** (Wilks' Lambda, etc.)