Statistics

Permutation Testing

The example below uses a CLIP encoding model evaluated on PPA and FFA voxels. See the permutation testing guide for the full step-by-step method.

Example 1

Is encoding performance above chance?

python
import numpy as np
from laion_fmri.subject import load_subject

sub = load_subject("sub-03")

# Load betas for PPA and FFA voxels (check sub.get_available_rois() for exact names)
betas_ppa = sub.get_betas(session="ses-01", roi="PPA")  # (n_images, n_ppa)
betas_ffa = sub.get_betas(session="ses-01", roi="FFA")  # (n_images, n_ffa)
betas = np.concatenate([betas_ppa, betas_ffa], axis=1)  # (n_images, n_voxels)

# model_predictions: your encoding model's predicted responses
# shape (n_images, n_voxels), same image ordering as betas

def pearsonr_cols(A, B):
    # Vectorised Pearson r for every column pair; returns shape (n_voxels,)
    A = A - A.mean(0); B = B - B.mean(0)
    return (A * B).sum(0) / np.sqrt((A**2).sum(0) * (B**2).sum(0))

def mean_r(pred, resp):
    return np.nanmean(pearsonr_cols(pred, resp))

# Step 1: Observed test statistic
t_obs = mean_r(model_predictions, betas)

# Steps 2-3: Permute image indices in model predictions -> null distribution
#   This breaks the correspondence between which image the model is
#   predicting and which brain response it is compared against.
rng = np.random.default_rng(seed=0)
t_perm = np.array([
    mean_r(model_predictions[rng.permutation(len(betas))], betas)
    for _ in range(10000)
])

# Step 4: One-sided p-value
p = (1 + np.sum(t_perm >= t_obs)) / (1 + len(t_perm))
print(f"Observed mean r = {t_obs:.4f},  p = {p:.4f}")

Permutes image indices in the model predictions. This breaks the model's correspondence with any specific image's brain response, generating a one-sided null distribution.