using UnfoldDecode
using UnfoldSim
using UnfoldMakie
using CairoMakie
using UnfoldOverlap-corrected decoding
We will try to introduce as many fancy features as possible Please read the "tutorial" first
Simulation
multi-event
dat, evt = UnfoldSim.predef_eeg()
evt.event = rand(["eventA", "eventB"], size(evt, 1)) # add random events
dat = repeat(dat', 5)
dat .= dat .+ 20 .* rand(size(dat)...)5×120199 Matrix{Float64}:
9.01374 3.764 4.54548 15.7452 … 5.83032 3.0957 9.00664
17.7199 16.565 14.6415 1.46751 19.5718 11.3176 10.2678
2.18348 10.3004 11.5502 12.9094 5.30589 0.124008 16.7909
17.3435 5.80782 14.3009 20.0696 15.5848 14.1926 1.14269
11.2792 0.684888 0.639159 12.9794 12.9816 11.1436 6.8912Overlap-model Definition
We have two basis functions now, with two different timewindows. Let's see if it works!
des = [
"eventA" => (@formula(0 ~ 1 + condition + continuous), firbasis((-0.1, 1.0), 100)),
"eventB" => (@formula(0 ~ 1 + continuous), firbasis((-0.3, 0.5), 100)),
]2-element Vector{Pair{String, Tuple{StatsModels.FormulaTerm{StatsModels.ConstantTerm{Int64}}, Unfold.FIRBasis}}}:
"eventA" => (0 ~ 1 + condition + continuous, �[0m�[22m╭──────────────────────────────────────────────────────────────────────────────╮�[22m�[0m111×111 SparseArrays.SparseMatrixCSC with 111 stored entries:
�[22m│�[22m �[1m�[34m::BasisFunction�[22m�[39m �[22m│�[22m⎡⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎤
�[22m│�[22m �[1mname: �[22m�[38;2;144;202;249m�[39m �[22m│�[22m⎢⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
�[22m│�[22m �[1mkerneltype: �[22m�[38;2;144;202;249mUnfold.FIRBasis�[39m �[22m│�[22m⎢⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
�[22m│�[22m �[1mwidth: �[22m�[38;2;144;202;249m111�[39m �[22m│�[22m⎢⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
�[22m│�[22m �[1mheight: �[22m�[38;2;144;202;249m111�[39m �[22m│�[22m⎢⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
�[22m│�[22m �[1mcolnames: �[22m�[38;2;144;202;249m[-0.1, -0.09 ... 1.0]�[39m �[22m│�[22m⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⎥
�[22m│�[22m �[1mtimes: �[22m�[38;2;144;202;249m[-0.1, -0.09 ... 1.0]�[39m �[22m│�[22m⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⎥
�[22m│�[22m �[1mcollabel: �[22m�[38;2;144;202;249mtime�[39m �[22m│�[22m⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⎥
�[22m│�[22m �[1mshift_onset: �[22m�[38;2;144;202;249m-10�[39m �[22m│�[22m⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⎥
�[22m│�[22m �[22m│�[22m⎣⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⎦
�[0m�[22m╰──────────────────────────────────────────────────────────────────────────────╯�[22m�[0m�[0m
)
"eventB" => (0 ~ 1 + continuous, �[0m�[22m╭──────────────────────────────────────────────────────────────────────────────╮�[22m�[0m81×81 SparseArrays.SparseMatrixCSC with 81 stored entries:
�[22m│�[22m �[1m�[34m::BasisFunction�[22m�[39m �[22m│�[22m⎡⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎤
�[22m│�[22m �[1mname: �[22m�[38;2;144;202;249m�[39m �[22m│�[22m⎢⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
�[22m│�[22m �[1mkerneltype: �[22m�[38;2;144;202;249mUnfold.FIRBasis�[39m �[22m│�[22m⎢⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
�[22m│�[22m �[1mwidth: �[22m�[38;2;144;202;249m81�[39m �[22m│�[22m⎢⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
�[22m│�[22m �[1mheight: �[22m�[38;2;144;202;249m81�[39m �[22m│�[22m⎢⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⎥
�[22m│�[22m �[1mcolnames: �[22m�[38;2;144;202;249m[-0.3, -0.29 ... 0.5]�[39m �[22m│�[22m⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⠀⠀⎥
�[22m│�[22m �[1mtimes: �[22m�[38;2;144;202;249m[-0.3, -0.29 ... 0.5]�[39m �[22m│�[22m⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⠀⠀⎥
�[22m│�[22m �[1mcollabel: �[22m�[38;2;144;202;249mtime�[39m �[22m│�[22m⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⠀⠀⎥
�[22m│�[22m �[1mshift_onset: �[22m�[38;2;144;202;249m-30�[39m �[22m│�[22m⎢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⠀⠀⎥
�[22m│�[22m �[22m│�[22m⎣⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⢄⎦
�[0m�[22m╰──────────────────────────────────────────────────────────────────────────────╯�[22m�[0m�[0m
)To show that it is possible, we explicitly specify the solver
customsolver = (x, y) -> Unfold.solver_default(x, y)
uf = Unfold.fit(UnfoldModel, des, evt, dat[1, :]; solver = customsolver);
plot_erp(coeftable(uf); mapping = (; col = :eventname))
Fitting the Overlap-corrected LDA model
using MLJ, MultivariateStats, MLJMultivariateStatsInterface
LDA = @load LDA pkg = MultivariateStatsMLJMultivariateStatsInterface.LDAyou could use other parameters, check out ?LDA
ldaModel = LDA(
method = :whiten,
cov_w = SimpleCovariance(),
cov_b = SimpleCovariance(),
regcoef = 1e-3,
)
uf_lda = UnfoldDecode.fit(
UnfoldDecodingModel,
des,
evt,
dat,
ldaModel,
"eventA" => :condition;
nfolds = 2,# only 2 folds to speed up computation
unfold_fit_options = (; solver = customsolver), #customer solver for fun
eventcolumn = :event, # actually the default, but maybe your event dataframe has a different name?
multithreading = false,
) # who needs speed anyway :shrug:
plot_erp(coeftable(uf_lda))
Voila, the model classified the correct period at the correct event
This page was generated using Literate.jl.