Martijn Wieling
University of Groningen
R
code) and resultsload("dat.rda")
dat = dat[order(dat$Subject, dat$TrialNr, dat$Time), ] # sort data per trial
dat$start.event <- dat$Time == min(dat$Time) # mark the start of every new trial
head(dat)
# uV Time Subject Word TrialNr Type AoArr start.event
# 721 8.94 505 GL102 Wald 2 incor 8 TRUE
# 722 15.56 515 GL102 Wald 2 incor 8 FALSE
# 723 21.31 525 GL102 Wald 2 incor 8 FALSE
# 724 13.32 535 GL102 Wald 2 incor 8 FALSE
# 725 19.11 545 GL102 Wald 2 incor 8 FALSE
# 726 17.96 555 GL102 Wald 2 incor 8 FALSE
dim(dat) # signal was downsampled to 100 Hz
# [1] 442160 8
mgcv
version 1.8.41, itsadug
version 2.4.1)library(mgcv)
library(itsadug)
# duration discrete=F: 3600 s.; 1/2/4/8/16 threads: 1000/560/300/200/250 s.
system.time(m0 <- bam(uV ~ s(Time, by = Type) + Type + s(Time, Subject, by = Type,
bs = "fs", m = 1) + s(Time, Word, by = Type, bs = "fs", m = 1), data = dat,
rho = rhoval, AR.start = dat$start.event, discrete = T, nthreads = 8))
# user system elapsed
# 1088 2948 289
rho
was used to determine rhoval
: 0.91summary(m0) # slides only show the relevant part of the summary
# Parametric coefficients:
# Estimate Std. Error t value Pr(>|t|)
# (Intercept) -0.561 0.521 -1.08 0.282
# Typeincor 0.803 0.670 1.20 0.231
#
# Approximate significance of smooth terms:
# edf Ref.df F p-value
# s(Time):Typecor 1.11 1.20 0.24 0.635
# s(Time):Typeincor 3.32 4.32 6.77 1.65e-05 ***
# s(Time,Subject):Typecor 58.99 603.00 0.90 <2e-16 ***
# s(Time,Subject):Typeincor 53.97 602.00 0.48 <2e-16 ***
# s(Time,Word):Typecor 68.31 864.00 0.29 <2e-16 ***
# s(Time,Word):Typeincor 65.86 863.00 0.26 <2e-16 ***
#
# Deviance explained = 5.2%
plot_smooth(m0, view = "Time", rug = F, plot_all = "Type", main = "")
plot_diff(m0, view = "Time", comp = list(Type = c("incor", "cor"))) # overly conservative
dat$IsIncorrect <- (dat$Type == "incor") * 1 # create binary predictor: 0 = cor, 1 = incor
m0b <- bam(uV ~ s(Time) + s(Time, by = IsIncorrect) + s(Time, Subject, bs = "fs",
m = 1) + s(Time, Subject, by = IsIncorrect, bs = "fs", m = 1) + s(Time, Word,
bs = "fs", m = 1) + s(Time, Word, by = IsIncorrect, bs = "fs", m = 1), data = dat,
rho = rhoval, AR.start = dat$start.event, discrete = T, nthreads = 8)
s(Time, by=IsIncorrect)
is equal to 0 whenever IsIncorrect
equals 0s(Time) + 0 = s(Time)
s(Time) + s(Time, by=IsIncorrect)
s(Time, by=IsIncorrect)
summary(m0b, re.test = FALSE) # summary without random effects (quicker to compute)
# Parametric coefficients:
# Estimate Std. Error t value Pr(>|t|)
# (Intercept) -0.573 0.468 -1.22 0.221
#
# Approximate significance of smooth terms:
# edf Ref.df F p-value
# s(Time) 1.64 2.05 0.6 0.535
# s(Time):IsIncorrect 4.08 5.00 3.9 0.002 **
s(Time):IsIncorrect
shows the significance of the combined intercept and non-linear difference between correct and incorrectdat$TypeO <- as.ordered(dat$Type) # creating an ordered factor ...
contrasts(dat$TypeO) <- "contr.treatment" # ... with contrast treatment: cor = 0, incor = 1
m0o <- bam(uV ~ s(Time) + s(Time, by = TypeO) + TypeO + s(Time, Subject, bs = "fs",
m = 1) + s(Time, Subject, by = TypeO, bs = "fs", m = 1) + s(Time, Word, bs = "fs",
m = 1) + s(Time, Word, by = TypeO, bs = "fs", m = 1), data = dat, rho = rhoval,
AR.start = dat$start.event, discrete = T, nthreads = 8)
s(Time, by=TypeO)
is equal to 0 whenever TypeO
equals cor
(reference level)s(Time, by=TypeO) + TypeO
s(Time, by=TypeO)
: centered non-linear difference TypeO
(must be included): intercept differencesummary(m0o, re.test = FALSE)
# Parametric coefficients:
# Estimate Std. Error t value Pr(>|t|)
# (Intercept) -0.573 0.468 -1.22 0.221
# TypeOincor 0.789 0.575 1.37 0.170
#
# Approximate significance of smooth terms:
# edf Ref.df F p-value
# s(Time) 1.64 2.05 0.60 0.535
# s(Time):TypeOincor 3.08 4.00 4.58 0.001 **
TypeOincor
represents the significance of the intercept difference between correct and incorrects(Time):TypeOincor
represents the significance of the non-linear difference between correct and incorrectplot(m0b, select = 2, shade = T, rug = F, main = "Binary difference", ylim = c(-3, 3))
plot(m0o, select = 2, shade = T, rug = F, main = "Ordered factor difference", ylim = c(-3, 3))
te
is used to model a non-linear interaction with predictors on a different scale)m1 <- bam(uV ~ te(Time, AoArr, by = Type) + Type + s(Time, Subject, bs = "fs", m = 1) + s(Time,
Subject, by = TypeO, bs = "fs", m = 1) + s(Time, Word, bs = "fs", m = 1) + s(Time, Word, by = TypeO,
bs = "fs", m = 1), data = dat, rho = rhoval, AR.start = dat$start.event, discrete = T, nthreads = 8)
summary(m1, re.test = FALSE)
# Parametric coefficients:
# Estimate Std. Error t value Pr(>|t|)
# (Intercept) -0.457 0.472 -0.97 0.333
# Typeincor 0.476 0.561 0.85 0.396
#
# Approximate significance of smooth terms:
# edf Ref.df F p-value
# te(Time,AoArr):Typecor 3.09 3.18 1.64 0.177
# te(Time,AoArr):Typeincor 5.88 6.96 4.59 4.14e-05 ***
#
# Deviance explained = 5%
plot_diff2(m1, view = c("Time", "AoArr"), comp = list(Type = c("incor", "cor")))
fadeRug(dat$Time, dat$AoArr) # hide points without data
f112300
and ShinyDem0
)m2 <- bam(uV ~ s(Time, by = Type) + s(AoArr, by = Type) + ti(Time, AoArr, by = Type) + Type +
s(Time, Subject, bs = "fs", m = 1) + s(Time, Subject, by = TypeO, bs = "fs", m = 1) + s(Time,
Word, bs = "fs", m = 1) + s(Time, Word, by = TypeO, bs = "fs", m = 1), data = dat, rho = rhoval,
AR.start = dat$start.event, discrete = T, nthreads = 8) # te(x,y) = s(x) + s(y) + ti(x,y)
summary(m2, re.test = FALSE)
# Parametric coefficients:
# Estimate Std. Error t value Pr(>|t|)
# (Intercept) -0.450 0.472 -0.95 0.341
# Typeincor 0.472 0.561 0.84 0.400
#
# Approximate significance of smooth terms:
# edf Ref.df F p-value
# s(Time):Typecor 1.02 1.04 0.04 0.878
# s(Time):Typeincor 3.31 4.30 6.56 2.32e-05 ***
# s(AoArr):Typecor 1.01 1.01 2.37 0.124
# s(AoArr):Typeincor 1.00 1.00 1.85 0.173
# ti(Time,AoArr):Typecor 1.04 1.08 2.19 0.128
# ti(Time,AoArr):Typeincor 2.10 2.96 0.39 0.718
m3 <- bam(uV ~ s(Time, by = Type) + s(AoArr, by = Type) + Type + s(Time, Subject, bs = "fs",
m = 1) + s(Time, Subject, by = TypeO, bs = "fs", m = 1) + s(Time, Word, bs = "fs", m = 1) +
s(Time, Word, by = TypeO, bs = "fs", m = 1), data = dat, rho = rhoval, AR.start = dat$start.event,
discrete = T, nthreads = 8) # ti-terms dropped
summary(m3, re.test = FALSE)
# Parametric coefficients:
# Estimate Std. Error t value Pr(>|t|)
# (Intercept) -0.448 0.472 -0.95 0.342
# Typeincor 0.474 0.561 0.84 0.399
#
# Approximate significance of smooth terms:
# edf Ref.df F p-value
# s(Time):Typecor 1.01 1.03 0.35 0.554
# s(Time):Typeincor 3.32 4.32 6.77 1.65e-05 ***
# s(AoArr):Typecor 1.06 1.07 2.28 0.134
# s(AoArr):Typeincor 1.01 1.01 1.80 0.179
fREML
select = T
, all smooths are considered random effects, and model comparison can be done using models fit with fREML
(default fitting method)
discrete = T
usable, and fREML
fitting is much faster than ML
m2.alt <- bam(uV ~ s(Time, by = Type) + s(AoArr, by = Type) + ti(Time, AoArr, by = Type) +
Type + s(Time, Subject, bs = "fs", m = 1) + s(Time, Subject, by = TypeO, bs = "fs",
m = 1) + s(Time, Word, bs = "fs", m = 1) + s(Time, Word, by = TypeO, bs = "fs",
m = 1), data = dat, rho = rhoval, AR.start = dat$start.event, select = T, discrete = T,
nthreads = 8)
m3.alt <- bam(uV ~ s(Time, by = Type) + s(AoArr, by = Type) + Type + s(Time, Subject,
bs = "fs", m = 1) + s(Time, Subject, by = TypeO, bs = "fs", m = 1) + s(Time,
Word, bs = "fs", m = 1) + s(Time, Word, by = TypeO, bs = "fs", m = 1), data = dat,
rho = rhoval, AR.start = dat$start.event, select = T, discrete = T, nthreads = 8)
compareML(m2.alt, m3.alt)
# m2.alt: uV ~ s(Time, by = Type) + s(AoArr, by = Type) + ti(Time, AoArr,
# by = Type) + Type + s(Time, Subject, bs = "fs", m = 1) +
# s(Time, Subject, by = TypeO, bs = "fs", m = 1) + s(Time,
# Word, bs = "fs", m = 1) + s(Time, Word, by = TypeO, bs = "fs",
# m = 1)
#
# m3.alt: uV ~ s(Time, by = Type) + s(AoArr, by = Type) + Type + s(Time,
# Subject, bs = "fs", m = 1) + s(Time, Subject, by = TypeO,
# bs = "fs", m = 1) + s(Time, Word, bs = "fs", m = 1) + s(Time,
# Word, by = TypeO, bs = "fs", m = 1)
#
# Chi-square test of fREML scores
# -----
# Model Score Edf Difference Df p.value Sig.
# 1 m3.alt 1492275 18
# 2 m2.alt 1492273 24 1.450 6.000 0.821
#
# AIC difference: 4.89, model m3.alt has lower AIC.
ti
-terms (simpler model m3.alt
is better)m4 <- bam(uV ~ s(Time) + s(Time, by = TypeO) + s(AoArr) + s(AoArr, by = TypeO) + TypeO + s(Time,
Subject, bs = "fs", m = 1) + s(Time, Subject, by = TypeO, bs = "fs", m = 1) + s(Time, Word,
bs = "fs", m = 1) + s(Time, Word, by = TypeO, bs = "fs", m = 1), data = dat, rho = rhoval,
AR.start = dat$start.event, discrete = T, nthreads = 8)
summary(m4, re.test = FALSE)
# Parametric coefficients:
# Estimate Std. Error t value Pr(>|t|)
# (Intercept) -0.411 0.475 -0.87 0.387
# TypeOincor 0.435 0.564 0.77 0.441
#
# Approximate significance of smooth terms:
# edf Ref.df F p-value
# s(Time) 1.64 2.05 0.60 0.535
# s(Time):TypeOincor 3.08 4.00 4.58 0.001 **
# s(AoArr) 1.04 1.04 2.33 0.131
# s(AoArr):TypeOincor 1.00 1.00 9.10 0.003 **
plot(m4, select = 2, shade = T, rug = F, ylim = c(-3, 3))
plot(m4, select = 4, shade = T, rug = F, ylim = c(-6, 6))
library(car)
qqp(resid(m4)) # quantile-quantile plot function from library car
hist(resid(m4))
bam
: family="scat"
system.time(m4.scat <- bam(uV ~ s(Time) + s(Time, by = TypeO) + s(AoArr) + s(AoArr, by = TypeO) +
TypeO + s(Time, Subject, bs = "fs", m = 1) + s(Time, Subject, by = TypeO, bs = "fs", m = 1) +
s(Time, Word, bs = "fs", m = 1) + s(Time, Word, by = TypeO, bs = "fs", m = 1), data = dat,
family = "scat", rho = rhoval, AR.start = dat$start.event, discrete = T, nthreads = 32))
# user system elapsed
# 55336 3512 1978
# For comparison, duration of the Gaussian model (8 CPU's is fastest)
system.time(m4 <- bam(uV ~ s(Time) + s(Time, by = TypeO) + s(AoArr) + s(AoArr, by = TypeO) +
TypeO + s(Time, Subject, bs = "fs", m = 1) + s(Time, Subject, by = TypeO, bs = "fs", m = 1) +
s(Time, Word, bs = "fs", m = 1) + s(Time, Word, by = TypeO, bs = "fs", m = 1), data = dat,
rho = rhoval, AR.start = dat$start.event, discrete = T, nthreads = 8))
# user system elapsed
# 1347 2395 152
summary(m4, re.test = FALSE)$s.table # significance of smooths
# edf Ref.df F p-value
# s(Time) 1.64 2.05 0.595 0.53482
# s(Time):TypeOincor 3.08 4.00 4.581 0.00107
# s(AoArr) 1.04 1.04 2.333 0.13057
# s(AoArr):TypeOincor 1.00 1.00 9.099 0.00253
summary(m4.scat, re.test = FALSE)$s.table # significance of smooths
# edf Ref.df F p-value
# s(Time) 2.35 3.03 1.259 0.28801
# s(Time):TypeOincor 3.12 4.04 4.364 0.00153
# s(AoArr) 1.10 1.11 0.502 0.54404
# s(AoArr):TypeOincor 1.01 1.02 8.432 0.00364
par(mfrow = c(1, 2))
qqp(resid(m4), main = "m4")
qqp(resid(m4.scat), main = "m4.scat")
m0
) is better for modeling individual factor levelste(Time,AoArr)
to model a non-linear interactionte(Time,AoArr)
using ti()
and two s()
'ste(x, y, Time, d = c(2,1))
Thank you for your attention!