Skip to contents

Why rMVPA?

Decoding stimulus categories from fMRI activation patterns requires coordinating data loading, model selection, cross-validation, and spatial iteration (searchlights or ROIs). rMVPA handles all of this so you can focus on your scientific question rather than pipeline plumbing.

This vignette walks you through three analyses on synthetic data:

  1. Searchlight classification – decode conditions at every voxel neighbourhood in the brain.
  2. Regional classification – decode within predefined ROIs.
  3. RSA (Representational Similarity Analysis) – test whether neural patterns match a predicted similarity structure.

Quick example: searchlight classification

A complete searchlight run is four short steps. Each builds one object the next step needs.

1. Load the package and generate a tiny synthetic dataset. gen_sample_dataset() returns both the imaging data (an mvpa_dataset) and the experimental design (an mvpa_design).

library(rMVPA)
library(neuroim2)

data <- gen_sample_dataset(D = c(6, 6, 6), nobs = 80, blocks = 4,
                           nlevels = 2, response_type = "categorical",
                           data_mode = "image")

2. Wrap the data in an mvpa_dataset and choose a cross-validation scheme. Run-blocked CV uses each scanning run as a held-out fold — the standard way to keep training and test trials temporally independent.

dset <- mvpa_dataset(data$dataset$train_data, mask = data$dataset$mask)
cval <- blocked_cross_validation(data$design$block_var)

3. Pick a classifier and bind it into a model specification. load_model("sda_notune") retrieves a pre-registered shrinkage discriminant model from the MVPAModels registry; mvpa_model() glues the dataset, design, classifier, and CV scheme together.

mod  <- load_model("sda_notune")
mspec <- mvpa_model(mod, dataset = dset, design = data$design,
                    crossval = cval,
                    tune_grid = data.frame(lambda = 0.01, diagonal = FALSE))

4. Run a 4 mm searchlight. Each voxel becomes the centre of a sphere; the model is fit and cross-validated locally; performance metrics are returned per centre as voxel-wise maps.

sl_result <- run_searchlight(mspec, radius = 4, method = "standard")
names(sl_result$results)
#> [1] "Accuracy" "AUC"

run_searchlight() returned a named list of performance maps (one per metric — accuracy and AUC by default for two-class problems). Each entry is a NeuroVol you can save with neuroim2::write_vol() or display with any volumetric viewer.

Regional classification

The same model spec runs over predefined ROIs instead of every voxel. The only new piece is a region mask: an integer-labelled NeuroVol where each non-zero value identifies one ROI.

1. Build a toy 3-region mask from the active voxels. Real analyses use an atlas or a parcellation; here we just split the mask randomly so the example is self-contained.

mask <- data$dataset$mask
set.seed(42)
region_mask <- NeuroVol(
  sample(1:3, sum(mask), replace = TRUE),
  space(mask),
  indices = which(mask > 0)
)

2. Run regional MVPA. run_regional() reuses the model spec from the searchlight example — same classifier, same CV scheme, just a different spatial unit.

reg_result <- run_regional(mspec, region_mask)
reg_result$performance_table
#> # A tibble: 3 × 3
#>   roinum Accuracy     AUC
#>    <int>    <dbl>   <dbl>
#> 1      1    0.512 -0.0387
#> 2      2    0.512  0.151 
#> 3      3    0.462 -0.166

Each row reports one ROI’s cross-validated metrics. A note on the values: rMVPA reports AUC as AUC − 0.5, so the chance level is 0, not 0.5, and slightly negative AUCs (e.g. -0.04) just mean the classifier did marginally worse than chance — typical for a synthetic null example like this one. Real datasets with signal will give clearly positive AUCs.

RSA in 30 seconds

RSA asks whether the pattern of neural similarities across conditions matches a model-predicted similarity structure.

# Create a synthetic dataset with 5 conditions
rsa_data <- gen_sample_dataset(D = c(6, 6, 6), nobs = 100, blocks = 5,
                               nlevels = 5, response_type = "categorical",
                               data_mode = "image")

# Hypothetical model: conditions are ordered, so nearby conditions are similar
ncond <- 5
model_rdm <- as.matrix(dist(1:ncond))

# Build the RSA design and model
# data= is a list of predictor RDMs; block_var is the run vector
rsa_des <- rsa_design(~ model_rdm,
                      data = list(model_rdm = model_rdm),
                      block_var = rsa_data$design$block_var)

dset_rsa <- mvpa_dataset(rsa_data$dataset$train_data, mask = rsa_data$dataset$mask)
rsa_mod  <- rsa_model(dataset = dset_rsa, design = rsa_des,
                      distmethod = "spearman", regtype = "pearson")

# Regional RSA
rsa_result <- run_regional(rsa_mod, region_mask = rsa_data$dataset$mask)
head(rsa_result$performance_table)
#> # A tibble: 1 × 2
#>   roinum model_rdm
#>    <int>     <dbl>
#> 1      1    0.0121

Where to go next

Pick the next vignette by what you want to do:

Build a real classification analysis

Test representational hypotheses

Cross-domain transfer (encoding ↔︎ retrieval, perception ↔︎ memory)

Run from the command line, not R

Plug in your own analysis