Network Response#

In this tutorial we will cover how to do statistical significance testing for a ‘network response’. This is the average state/mode time course epoched around events of interest. We test is the response is significantly different from zero.

Get network response#

First we need to get the network response for each subject. This is the epoched state/mode time course averaged over trials, which would be a (subjects, states/modes, time) array. In this tutorial, we will simulate this.

import numpy as np

n_subjects = 20
n_time = 250
n_networks = 6

network_response = np.random.normal(size=(n_subjects, n_time, n_networks))

# Add non-zero network response for the first network for time points 30-80
network_response[:, 30:80, 0] += 1.5

# Add non-zero network response for the second network for time points 80-100
network_response[:, 80:100, 1] += 2

Statistical significance testing#

osl-dynamics has the analysis.statistics.evoked_response_max_stat_perm function for doing GLM permutation stats testing see if a value is significantly different from zero. This function uses the maximum test statistic to control for multiple comparisons across the time points and networks.

from osl_dynamics.analysis import statistics

pvalues = statistics.evoked_response_max_stat_perm(
    network_response,
    n_perm=1000,
    n_jobs=4,
)
print(pvalues.shape)
QUEUEING TASKS | Running permutations:   0%|          | 0/1000 [00:00<?, ?it/s]
QUEUEING TASKS | Running permutations:  84%|████████▍ | 842/1000 [00:00<00:00, 8418.28it/s]
QUEUEING TASKS | Running permutations: 100%|██████████| 1000/1000 [00:00<00:00, 9739.59it/s]

PROCESSING TASKS | Running permutations:   0%|          | 0/1000 [00:00<?, ?it/s]
PROCESSING TASKS | Running permutations:   2%|▎         | 25/1000 [00:00<00:03, 243.80it/s]
PROCESSING TASKS | Running permutations:   6%|▌         | 58/1000 [00:00<00:03, 293.44it/s]
PROCESSING TASKS | Running permutations:   9%|▉         | 90/1000 [00:00<00:03, 297.77it/s]
PROCESSING TASKS | Running permutations:  12%|█▏        | 120/1000 [00:00<00:02, 294.68it/s]
PROCESSING TASKS | Running permutations:  16%|█▌        | 155/1000 [00:00<00:02, 310.56it/s]
PROCESSING TASKS | Running permutations:  19%|█▉        | 189/1000 [00:00<00:02, 320.18it/s]
PROCESSING TASKS | Running permutations:  22%|██▏       | 222/1000 [00:00<00:02, 321.02it/s]
PROCESSING TASKS | Running permutations:  26%|██▌       | 256/1000 [00:00<00:02, 325.09it/s]
PROCESSING TASKS | Running permutations:  29%|██▉       | 291/1000 [00:00<00:02, 327.74it/s]
PROCESSING TASKS | Running permutations:  33%|███▎      | 329/1000 [00:01<00:01, 342.50it/s]
PROCESSING TASKS | Running permutations:  37%|███▋      | 368/1000 [00:01<00:01, 355.77it/s]
PROCESSING TASKS | Running permutations:  40%|████      | 404/1000 [00:01<00:01, 352.94it/s]
PROCESSING TASKS | Running permutations:  44%|████▍     | 440/1000 [00:01<00:01, 354.49it/s]
PROCESSING TASKS | Running permutations:  48%|████▊     | 478/1000 [00:01<00:01, 361.43it/s]
PROCESSING TASKS | Running permutations:  52%|█████▏    | 515/1000 [00:01<00:01, 354.46it/s]
PROCESSING TASKS | Running permutations:  56%|█████▌    | 556/1000 [00:01<00:01, 368.65it/s]
PROCESSING TASKS | Running permutations:  59%|█████▉    | 593/1000 [00:01<00:01, 364.58it/s]
PROCESSING TASKS | Running permutations:  63%|██████▎   | 630/1000 [00:01<00:01, 362.05it/s]
PROCESSING TASKS | Running permutations:  67%|██████▋   | 667/1000 [00:01<00:00, 358.45it/s]
PROCESSING TASKS | Running permutations:  71%|███████   | 710/1000 [00:02<00:00, 376.99it/s]
PROCESSING TASKS | Running permutations:  75%|███████▍  | 749/1000 [00:02<00:00, 376.12it/s]
PROCESSING TASKS | Running permutations:  79%|███████▉  | 790/1000 [00:02<00:00, 380.47it/s]
PROCESSING TASKS | Running permutations:  83%|████████▎ | 829/1000 [00:02<00:00, 367.15it/s]
PROCESSING TASKS | Running permutations:  87%|████████▋ | 866/1000 [00:02<00:00, 365.39it/s]
PROCESSING TASKS | Running permutations:  90%|█████████ | 905/1000 [00:02<00:00, 369.36it/s]
PROCESSING TASKS | Running permutations:  94%|█████████▍| 942/1000 [00:02<00:00, 353.54it/s]
PROCESSING TASKS | Running permutations:  98%|█████████▊| 980/1000 [00:02<00:00, 360.39it/s]
PROCESSING TASKS | Running permutations: 100%|██████████| 1000/1000 [00:02<00:00, 350.41it/s]

COLLECTING RESULTS | Running permutations:   0%|          | 0/1000 [00:00<?, ?it/s]
COLLECTING RESULTS | Running permutations: 100%|██████████| 1000/1000 [00:00<00:00, 532610.03it/s]
(250, 6)

Let’s plot the group average network response with the significant time points highlighted.

from osl_dynamics.utils import plotting

t = np.arange(n_time)
group_network_response = np.mean(network_response, axis=0)
fig, ax = plotting.plot_evoked_response(
    t,
    group_network_response,
    pvalues,
    x_label="Sample",
    y_label="Network Activation",
)
7 2 group network response

Note, this function also has a covariates argument that can be used to account for confounds.

Total running time of the script: (0 minutes 3.147 seconds)

Gallery generated by Sphinx-Gallery