Hi everyone,
I am running a single-participant, single-condition source analysis in MNE-Python, and I want to use a non-parametric spatiotemporal cluster permutation test to find significant cortical activation within a post-stimulus ROI (0.1 to 0.5 seconds), I want to do this test between the source estimate epochs (see the code below) and that to apply the within subject anaylsis at the source level not the channel level.
Because I only have a single experimental condition, I am confused about the most mathematically sound way to test my active ROI against a baseline or a state where there is no stimulus activity. I want to avoid direct comparison with the pre-stimulus baseline (-0.2 to 0 s) because the noise covariance matrix was optimized on that exact window, which may introduces statistical circularity. Instead, I am looking at a late post-stimulus window (e.g., 2.2 to 2.7 seconds) where I expect no stimulus-driven activity to remain.
note: the stimulus is every 5 seconds approximately.
I am considering a few different approaches and want to know which one is statistically and scientifically valid:
-
Approach A (Subtraction): Subtract the late window from the active window at the channel level (epochs(active) - epochs(late)) and feed its source estimate difference array “X” into
mne.stats.spatio_temporal_cluster_1samp_test. -
Approach B (Mean Subtraction): Take the average activity over time for the late window subtract it from the active window feed its source estimate difference array “X” into
mne.stats.spatio_temporal_cluster_1samp_test. -
Approach C (Test Against Zero, shown in the code below): Ignore the late window entirely, take the estimated source epochs, and feed them directly into
mne.stats.spatio_temporal_cluster_1samp_testto evaluate whether the active ROI significantly deviates from 0.
I would pick Approach C but I am wondering from the scientific statistical perspective whihc one is best or maybe some other approach can be suggested.
fwd_general = make_forward_solution(
epochs.info,
trans=str(trans),
src=str(SRC),
bem=str(BEM),
eeg=True,
mindist=5.0,
n_jobs=None,
)
epochs_bl = epochs.copy().apply_baseline((-0.2, 0))
cov_matrix = compute_covariance(
epochs_bl,
tmin = -0.2,
tmax = 0,
method=["empirical", "shrunk", "diagonal_fixed"],
)
inv = make_inverse_operator(
epochs_bl.average().info,
fwd_general,
cov_matrix,
loose="auto"
)
stc_epochs_dspm = apply_inverse_epochs(epochs=epochs_bl,
inverse_operator=inv,
lambda2=LAMBDA2,
method="dSPM",
pick_ori="normal")
src_ = read_source_spaces(SRC)
adjacency = spatial_src_adjacency(src_)
# time window for the "active" task (expected time of activity)
tmin_active = 0.1
tmax_active = 0.5
n_epochs = len(stc_epochs_dspm)
diff_data = []
for stc in stc_epochs_dspm:
stc_act = stc.copy().crop(tmin=tmin_active, tmax=tmax_active)
act = stc_act.data
diff = act # - base_mean_over_time
diff_transposed = diff.T
diff_data.append(diff_transposed)
X = np.array(diff_data)
print("Running cluster permutation test ...")
T_obs, clusters, cluster_p_values, H0 = spatio_temporal_cluster_1samp_test(
X,
adjacency=adjacency,
n_permutations=1000, # max_perms = 2 ** (n_samples - (tail == 0)) - 1
threshold=None,
tail=0,
n_jobs=-1
)