---
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.)