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}:
17.5872 7.98078 8.95192 11.3478 … 13.6962 6.47239 11.3838
1.98739 11.2074 2.4076 3.24325 11.1043 11.9759 13.3204
20.2716 7.2268 17.7165 19.0147 6.43297 14.3635 15.0468
7.78103 8.71343 9.4522 6.64546 8.01423 1.27141 16.071
4.5458 17.8417 5.58468 6.13369 5.79027 3.45208 17.4985Overlap-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.