This functionality is not extensively tested. While it returns reasonable results, we haven't written any unit-tests, nor tested the type-1 error probability yet
0. Setup
If you want to do LMM + cluster permutations, you at least need these packages (more for the simulation below)
using UnfoldMixedModels
using MixedModelsPermutations, ClusterDepth
using UnfoldStats
1. Simulate data
This section can be skipped, if one already has (real) data that they want to analyse.
Click to expand the simulation details
using UnfoldSim
using StatsModels
using Random
srate = 25
design = MultiSubjectDesign(;
n_subjects = 30,
n_items = 40,
items_between = Dict(:stimtype => ["car", "face"]),
)
#both_within = Dict(:condition=>["scrambled","intact"]))
contrasts = Dict(:stimtype => DummyCoding())
p1 = MixedModelComponent(;
basis = UnfoldSim.p100(; sfreq = srate),
formula = @formula(dv ~ 1 + (1 | subject) + (1 | item)),
β = [5.0],
σs = Dict(:subject => [0.0], :item => [0.0]),
contrasts = contrasts,
);
n1 = MixedModelComponent(;
basis = UnfoldSim.n170(; sfreq = srate),
formula = @formula(dv ~ 1 + stimtype + (1 + stimtype | subject) + (1 | item)),
β = [1.0, 4], # n170-basis is negative
σs = Dict(:subject => [2.0, 0.25], :item => [0.25]),
contrasts = contrasts,
);
p3 = MixedModelComponent(;
basis = UnfoldSim.p300(; sfreq = srate),
formula = @formula(dv ~ 1 + (1 | subject) + (1 + stimtype | item)),
β = [4.0],
σs = Dict(:subject => [1.0], :item => [0.5, 2]),
contrasts = contrasts,
);
data_e, events = UnfoldSim.simulate(
design,
[p1, n1, p3],
UniformOnset(srate * 2, 10),
PinkNoise(; noiselevel = 1);
return_epoched = true,
)
times = range(-0.1, 0.5, length = size(data_e, 1))
data_e = reshape(data_e, 1, size(data_e, 1), :)
┌ Warning: No random generator defined, used the default (`Random.MersenneTwister(1)`) with a fixed seed. This will always return the same results and the user is strongly encouraged to provide their own random generator!
└ @ UnfoldSim ~/.julia/packages/UnfoldSim/JzrqI/src/simulation.jl:17
2. Fit mass-univariate LMMs
We have some typical experimental data with subject and item effects. Item refer to stimuli here, based on our stimtype
condition these are either different cars
or faces
.
m = fit(
UnfoldModel,
[
Any => (
@formula(0 ~ 1 + stimtype + (1 + stimtype | item) + (1 + stimtype | subject)),
times,
),
],
events,
data_e,
);
Progress: 17%|██████▉ | ETA: 0:00:10
channel: 1
time: 2
Progress: 100%|█████████████████████████████████████████| Time: 0:00:02
channel: 1
time: 12
3. Cluster permutation test
If we would run a statistical test on each time-point separately, we would greatly inflate the type-1 error, reaching significance on any each sample much higher than the assumed α=0.05. One solution are cluster permutation test, where we instead test for clustersizes of connected significant clusters. In "classical" two-stage testing, such a permutation test is straight forward. But for LMMs we have to think of something more clever, as it is not directly clear how to permute if both subject and item effects exist (you gonna break the relation between the two). We did that in MixedModelsPermutations
and can apply this strategy to EEG data as well.`
select the fixed-effects coefficient to test (stimtype
)
coefficient = 2;
call the permutation test
This interface is very likely to change in the future
pvalue(
MersenneTwister(1),
m,
data_e,
coefficient;
n_permutations = 20,
clusterforming_threshold = 1.8,
)
1×12 Matrix{Float64}:
1.0 1.0 1.0 0.0666667 0.0666667 1.0 1.0 1.0 1.0 1.0 1.0 1.0
This page was generated using Literate.jl.