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×120198 Matrix{Float64}:
6.21684 7.63839 16.9123 2.23046 … 14.606 5.00478 6.45514
9.13038 6.58745 12.43 5.85597 3.64583 18.3988 13.6772
7.50148 0.66175 16.4338 18.3745 8.45273 6.63517 9.94464
1.8097 13.7348 18.5884 2.46048 19.0057 7.17104 8.5815
16.6189 13.9638 1.75852 0.87182 15.8026 12.5732 16.4046Overlap-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.