Importing and visualising EEG data
Below we import and reshape EEG data from the eegkit package.
library(neurogam)
library(ggplot2)
library(eegkit)
library(dplyr)
# retrieving some EEG data
data(eegdata)
head(eegdata)
#> subject group condition trial channel time voltage
#> 1 co2a0000364 a S1 0 FP1 0 -8.921
#> 2 co2a0000364 a S1 0 FP1 1 -8.433
#> 3 co2a0000364 a S1 0 FP1 2 -2.574
#> 4 co2a0000364 a S1 0 FP1 3 5.239
#> 5 co2a0000364 a S1 0 FP1 4 11.587
#> 6 co2a0000364 a S1 0 FP1 5 14.028
# plotting the average ERP per group and channel
eegdata |>
summarise(voltage = mean(voltage), .by = c(group, channel, time) ) |>
ggplot(aes(x = time, y = voltage, colour = group) ) +
geom_line() +
facet_wrap(~channel) +
theme_bw()
# reshape the data
eeg_data <- eegdata |>
# keeping only one channel
dplyr::filter(channel == "PZ") |>
# converting timesteps to seconds
mutate(time = (time + 1) / 256) |>
# rounding numeric variables
mutate(across(where(is.numeric), ~ round(.x, 4) ) ) |>
# removing NAs
na.omit()
# show a few rows
head(eeg_data)
#> subject group condition trial channel time voltage
#> 1 co2a0000364 a S1 0 PZ 0.0039 -2.797
#> 2 co2a0000364 a S1 0 PZ 0.0078 -4.262
#> 3 co2a0000364 a S1 0 PZ 0.0117 -4.262
#> 4 co2a0000364 a S1 0 PZ 0.0156 -2.797
#> 5 co2a0000364 a S1 0 PZ 0.0195 -0.844
#> 6 co2a0000364 a S1 0 PZ 0.0234 0.132
Fitting the model
We fit the model (a BGAMM) on one channel (PZ) to test for group difference at every timestep.
# fitting the BGAMM to identify clusters (around 30 min on 4 parallel apple M4 cores)
results <- testing_through_time(
# EEG data
data = eeg_data,
# participant column
participant_id = "subject",
# EEG column
outcome_id = "voltage",
# name of predictor in data
predictor_id = "group",
# basis dimension
kvalue = 40,
# we recommend fitting the GAMM on summary statistics (mean and SD)
multilevel = "summary",
# threshold on posterior odds
threshold = 10,
# number of MCMCs
chains = 4,
# number of parallel cores
cores = 4
)
Visualising the results
# displaying the identified clusters
print(results)
#>
#> ==== Time-resolved GAMM results ===============================
#>
#> Clusters found:
#>
#> sign id onset offset duration
#> positive 1 0.266 0.438 0.172
#>
#> =================================================================
# plotting the data, model's predictions, and clusters
plot(results)
Computing clusters at the participant-level
Below we fit a new model, specifying predictor_id = NA (because group varies across participants) and by_ppt = TRUE to test whether EEG amplitude (voltage) differs from 0 and return clusters at the participant level.
# fitting the BGAMM to identify clusters (around 30 min on 4 parallel apple M4 cores)
results <- testing_through_time(
# EEG data
data = eeg_data,
# participant column
participant_id = "subject",
# EEG column
outcome_id = "voltage",
# here we use no predictor (because group varies across participants)
predictor_id = NA,
# basis dimension (for both the group and participant levels)
kvalue = 40,
# we recommend fitting the GAMM with summary statistics (mean and SD)
multilevel = "summary",
# return clusters at both the group and participant levels
by_ppt = TRUE,
# threshold on posterior odds
threshold = 10,
# number of MCMCs
chains = 4,
# number of parallel cores
cores = 4
)
Visualising the results
# displaying the identified clusters
print(results)
#>
#> ==== Time-resolved GAMM results ===============================
#>
#> Clusters found:
#>
#> participant sign id onset offset duration
#> co2a0000364 positive 1 0.336 0.398 0.062
#> co2a0000364 negative 1 0.004 0.312 0.308
#> co2a0000364 negative 2 0.441 0.449 0.008
#> co2a0000364 negative 3 0.531 1.000 0.469
#> co2a0000365 negative 1 0.148 0.219 0.071
#> co2a0000365 negative 2 0.328 1.000 0.672
#> co2a0000368 negative 1 0.004 0.090 0.086
#> co2a0000368 negative 2 0.137 1.000 0.863
#> co2a0000369 positive 1 0.191 0.394 0.203
#> co2a0000369 negative 1 0.027 0.102 0.075
#> co2a0000369 negative 2 0.551 1.000 0.449
#> co2a0000370 positive 1 0.055 0.148 0.093
#> co2a0000370 positive 2 0.215 0.473 0.258
#> co2a0000370 positive 3 0.574 0.660 0.086
#> co2a0000370 positive 4 0.781 0.887 0.106
#> co2a0000371 negative 1 0.090 1.000 0.910
#> co2a0000372 positive 1 0.004 0.020 0.016
#> co2a0000372 positive 2 0.066 0.148 0.082
#> co2a0000372 positive 3 0.297 1.000 0.703
#> co2a0000372 negative 1 0.180 0.223 0.043
#> co2a0000375 positive 1 0.004 0.449 0.445
#> co2a0000375 positive 2 0.859 0.965 0.106
#> co2a0000377 positive 1 0.004 0.027 0.023
#> co2a0000377 positive 2 0.113 0.144 0.031
#> co2a0000377 positive 3 0.219 0.258 0.039
#> co2a0000377 positive 4 0.348 0.473 0.125
#> co2a0000377 negative 1 0.766 1.000 0.234
#> co2a0000378 positive 1 0.219 0.516 0.297
#> co2a0000378 negative 1 0.004 0.203 0.199
#> co2a0000378 negative 2 0.586 0.629 0.043
#> co2a0000378 negative 3 0.789 0.789 0.000
#> co2a0000378 negative 4 0.859 1.000 0.141
#> co2c0000337 positive 1 0.086 0.113 0.027
#> co2c0000337 positive 2 0.305 0.500 0.195
#> co2c0000337 negative 1 0.781 0.840 0.059
#> co2c0000337 negative 2 0.852 0.859 0.007
#> co2c0000338 negative 1 0.125 0.219 0.094
#> co2c0000338 negative 2 0.641 1.000 0.359
#> co2c0000339 negative 1 0.004 0.207 0.203
#> co2c0000339 negative 2 0.426 1.000 0.574
#> co2c0000340 positive 1 0.043 0.051 0.008
#> co2c0000340 negative 1 0.098 1.000 0.902
#> co2c0000341 positive 1 0.227 0.676 0.449
#> co2c0000341 negative 1 0.004 0.094 0.090
#> co2c0000341 negative 2 0.152 0.184 0.032
#> co2c0000341 negative 3 0.820 0.906 0.086
#> co2c0000342 positive 1 0.004 0.156 0.152
#> co2c0000342 positive 2 0.180 1.000 0.820
#> co2c0000344 positive 1 0.246 0.246 0.000
#> co2c0000344 positive 2 0.309 0.352 0.043
#> co2c0000344 negative 1 0.144 0.215 0.071
#> co2c0000344 negative 2 0.445 0.606 0.161
#> co2c0000344 negative 3 0.656 1.000 0.344
#> co2c0000345 positive 1 0.004 0.027 0.023
#> co2c0000345 positive 2 0.043 0.086 0.043
#> co2c0000345 positive 3 0.281 0.406 0.125
#> co2c0000345 positive 4 0.633 0.676 0.043
#> co2c0000345 negative 1 0.156 0.199 0.043
#> co2c0000345 negative 2 0.492 0.527 0.035
#> co2c0000345 negative 3 0.773 0.797 0.024
#> co2c0000346 positive 1 0.004 0.152 0.148
#> co2c0000346 positive 2 0.188 0.465 0.277
#> co2c0000346 negative 1 0.551 0.602 0.051
#> co2c0000347 positive 1 0.004 0.137 0.133
#> co2c0000347 positive 2 0.215 0.449 0.234
#>
#> =================================================================
# plotting the data, model's predictions, and clusters
plot(results)
Posterior predictive checks
We recommend visually assessing the predictions of the model against the observed data (for each participant). We provide a lightweight ppc() method, but you can conduct various PPCs with brms::pp_check(results$model, ...) (for all available PPCs, see https://mc-stan.org/bayesplot/reference/PPC-overview.html).
# posterior predictive checks (PPCs) at the group level
ppc(object = results, ppc_type = "group")
# posterior predictive checks (PPCs) at the participant level
ppc(object = results, ppc_type = "participant")