Experimental treatment with edaravone in a mouse model of spinocerebellar ataxia 1

Analysis of motor deficit on rotarod

Author

Martina Sucha, Simona Benediktova, Filip Tichanek, Jan Jedlicka, Stepan Kapl, Dana Jelinkova, Zdenka Purkartova, Jan Tuma, Jitka Kuncova, Jan Cendelin

This page shows R code for the study Sucha et al. (2023, International Journal of Molecular Science).

Citation:

Sucha M, Benediktova S, Tichanek F, Jedlicka J, Kapl S, Jelinkova D, Purkartova Z, Tuma J, Kuncova J, Cendelin J. Experimental Treatment with Edaravone in a Mouse Model of Spinocerebellar Ataxia 1. International Journal of Molecular Sciences. 2023; 24(13):10689. https://doi.org/10.3390/ijms241310689

GitHub page: https://github.com/filip-tichanek/edaravonSCA1

1 Upload of packages

rm(list = ls())

suppressWarnings(suppressMessages( {
library(brms)
library(beeswarm)
library(vioplot)
library(glmmTMB)
library(car)
library(cowplot)
library(ggplot2)
library(tidyverse)
library(bayesplot)
library(gtsummary)
library(vegan)
library(knitr)  
library(ggplot2)  
  } ) )

2 Data upload and wrangling

load("source_data/myEnvironment.RData")

## defining new variables
rotarod$group <- interaction(rotarod$treatment, rotarod$genotype)
rotarod$group <- factor(rotarod$group,levels=c('ctrl.wt','eda.wt','ctrl.sca','eda.sca'))
rotarod$sex_num <- ifelse(rotarod$sex == "f", -0.5, 0.5)

rotarod$group_sex <- interaction(rotarod$treatment, rotarod$genotype, rotarod$sex)
rotarod$group_sex <- factor(rotarod$group_sex, levels=c('ctrl.wt.f','ctrl.wt.m',
                                                  'eda.wt.f','eda.wt.m',
                                                  'ctrl.sca.f','ctrl.sca.m',
                                                  'eda.sca.f','eda.sca.m'))

## subject as factor
rotarod$id <- as.factor(rotarod$id)


## order of all roatrod tests
rotarod$order <- (rotarod$day-1) * 4 + rotarod$session
rotarod$order2 <- ifelse(rotarod$pre_post == 'pre', rotarod$order, rotarod$order+12)

## data summary
summary(rotarod)
       id       treatment  genotype  sex          day       session    
 7      :  24   ctrl:960   sca:960   f:936   Min.   :1   Min.   :1.00  
 9      :  24   eda :960   wt :960   m:984   1st Qu.:1   1st Qu.:1.75  
 11     :  24                                Median :2   Median :2.50  
 12     :  24                                Mean   :2   Mean   :2.50  
 13     :  24                                3rd Qu.:3   3rd Qu.:3.25  
 14     :  24                                Max.   :3   Max.   :4.00  
 (Other):1776                                                          
  rot_latency     pre_post        group        sex_num             group_sex  
 Min.   :  2.30   post:960   ctrl.wt :480   Min.   :-0.5000   ctrl.wt.m :264  
 1st Qu.: 94.97   pre :960   eda.wt  :480   1st Qu.:-0.5000   eda.wt.f  :240  
 Median :126.90              ctrl.sca:480   Median : 0.5000   eda.wt.m  :240  
 Mean   :127.79              eda.sca :480   Mean   : 0.0125   ctrl.sca.f:240  
 3rd Qu.:157.60                             3rd Qu.: 0.5000   ctrl.sca.m:240  
 Max.   :299.20                             Max.   : 0.5000   eda.sca.f :240  
                                                              (Other)   :456  
     order           order2     
 Min.   : 1.00   Min.   : 1.00  
 1st Qu.: 3.75   1st Qu.: 6.75  
 Median : 6.50   Median :12.50  
 Mean   : 6.50   Mean   :12.50  
 3rd Qu.: 9.25   3rd Qu.:18.25  
 Max.   :12.00   Max.   :24.00  
                                

Sub-setting pre-treatment and post-treatment rotarod data and data aggregation.

We will create 3 aggregated datasets, each with different pre-treatment rotarod latency (preTreat RotLat) variable. The reason is that our previous observations suggested that the genotype-related difference is less pronounced for the first 1-2 rotarod session(s) and do not predict later rotarod well. Models will be fitted using all three datasets and the model with the best predictive accuracy (as estimated via leave-one-out cross-validation - LOO-CV) will be used

## subseting post-treatment dataset
rot_post <- subset(rotarod, rotarod$pre_post == 'post')

## pre-treatment rotarod
rot_pre3 <- subset(rotarod, rotarod$pre_post == 'pre'& rotarod$day >2)
rot_pre23 <- subset(rotarod,rotarod$pre_post == 'pre'& rotarod$day >1)
rot_pre <- subset(rotarod, rotarod$pre_post == 'pre')

## aggregated data sets. Each has different definition of pre-treatment rotarod:

### mean from all pre-treatment rotarod runs
rot_pre_agg <- rot_pre %>% 
  group_by(id) %>% 
  summarise(mean_lat = mean(rot_latency))

### mean from 2nd and 3rd day 
rot_pre_agg_23 <- rot_pre23 %>% 
  group_by(id) %>% 
  summarise(mean_lat = mean(rot_latency))

### mean from 3rd rotarod day only
rot_pre_agg_3 <- rot_pre3 %>% 
  group_by(id) %>% 
  summarise(mean_lat = mean(rot_latency))

## joining new variable to post-treatment rotarod data
rot_post_co <- rot_post %>% 
  left_join(rot_pre_agg, by ='id') %>% 
  left_join(rot_pre_agg_23, by ='id') %>%
  left_join(rot_pre_agg_3, by ='id')
 
## centering the variables 'day' and 'session'
rot_post_co$day_cen <- rot_post_co$day-2
rot_post_co$session_cen <- rot_post_co$session -2.5

summary(rot_post_co)
       id      treatment  genotype  sex          day       session    
 7      : 12   ctrl:480   sca:480   f:468   Min.   :1   Min.   :1.00  
 9      : 12   eda :480   wt :480   m:492   1st Qu.:1   1st Qu.:1.75  
 11     : 12                                Median :2   Median :2.50  
 12     : 12                                Mean   :2   Mean   :2.50  
 13     : 12                                3rd Qu.:3   3rd Qu.:3.25  
 14     : 12                                Max.   :3   Max.   :4.00  
 (Other):888                                                          
  rot_latency     pre_post        group        sex_num             group_sex  
 Min.   : 16.10   post:960   ctrl.wt :240   Min.   :-0.5000   ctrl.wt.m :132  
 1st Qu.: 93.75   pre :  0   eda.wt  :240   1st Qu.:-0.5000   eda.wt.f  :120  
 Median :125.75              ctrl.sca:240   Median : 0.5000   eda.wt.m  :120  
 Mean   :126.67              eda.sca :240   Mean   : 0.0125   ctrl.sca.f:120  
 3rd Qu.:155.03                             3rd Qu.: 0.5000   ctrl.sca.m:120  
 Max.   :291.20                             Max.   : 0.5000   eda.sca.f :120  
                                                              (Other)   :228  
     order           order2        mean_lat.x       mean_lat.y    
 Min.   : 1.00   Min.   :13.00   Min.   : 55.98   Min.   : 55.67  
 1st Qu.: 3.75   1st Qu.:15.75   1st Qu.:108.61   1st Qu.:117.49  
 Median : 6.50   Median :18.50   Median :127.36   Median :136.45  
 Mean   : 6.50   Mean   :18.50   Mean   :128.90   Mean   :140.28  
 3rd Qu.: 9.25   3rd Qu.:21.25   3rd Qu.:147.82   3rd Qu.:166.12  
 Max.   :12.00   Max.   :24.00   Max.   :195.66   Max.   :218.11  
                                                                  
    mean_lat        day_cen    session_cen   
 Min.   : 60.2   Min.   :-1   Min.   :-1.50  
 1st Qu.:121.4   1st Qu.:-1   1st Qu.:-0.75  
 Median :141.0   Median : 0   Median : 0.00  
 Mean   :146.2   Mean   : 0   Mean   : 0.00  
 3rd Qu.:173.2   3rd Qu.: 1   3rd Qu.: 0.75  
 Max.   :255.6   Max.   : 1   Max.   : 1.50  
                                             

New variables mean_lat.x, mean_lat.y, mean_lat indicate pre-treatment rotarod latency (preTreat RotLat) used as covariate in models to adjuste for baseline performance

    1. mean_lat.x: average latency from all pre-treatment measurements
    1. mean_lat.y: latency averaged from the days 2 and 3
    1. mean_lat latency averaged from the 3rd day

3 Data exploration

Figure showing individual trajectories or rotarod (all 24 sessions, blue vertical line shows transition from pre-treatment to post-treatment)

rotarod %>% ggplot(aes(x=order2, y=rot_latency, by=id, col=sex)) + 
  geom_line(alpha=0.8) + 
  geom_vline(xintercept = 12.5, 
                color = "blue", linewidth=0.8, linetype= 'dashed') +
  facet_wrap(~group) 

Sex does not exhibit consistent effect, or only minor specifically in WT group. We will ignore the sex throughout the analysis

Figure showing data distribution per group

par(mfrow=c(2,2))
hist(rotarod[which(rotarod$group == 'ctrl.wt'),c('rot_latency')], 20, main="WT_0", xlim=c(0,300))
hist(rotarod[which(rotarod$group == 'eda.wt'),c('rot_latency')], 20, main="WT_E", xlim=c(0,300))
hist(rotarod[which(rotarod$group == 'ctrl.sca'),c('rot_latency')], 20,
     main="SCA_0", xlim=c(0,300))
hist(rotarod[which(rotarod$group == 'eda.sca'),c('rot_latency')], 20, main="SCA_E", xlim=c(0,300))

Distributions seem more or less symmetric. I do not see marks of heteroscedasticity (width of distribution seems similar across groups, similar magnitude of changes in low- and high-performing individuals on the previous plot of individual trajectories).

4 Modelling

As rotarod latency in non-negative, and right tail-distribution is expected, gamma likelihood may be the first choice. On the other hand, the values of latency is restricted as the rotarod increases the speed; the latency is thus strongly restricted, resulting in normal-like distribution.

Also data exploration suggest that Gaussian likelihood distribution may be reasonable choice here. We will fit both and look on posterior predictive check (PPC) to choose between them.

Firstly, we will select likelihood used, with models including pre-treatment roator latency averaged over all pre-treatment rotarod measurements (mean_lat.x).

4.1 Prior specification

First, we look at data summary statistics and estimate from previous publication Tichanek et al.

## changing reference group
rot_post_co$group<-relevel(rot_post_co$group,ref='ctrl.sca')

## wrangling data from Tichanek et al.
young_scirep <- young_scirep %>% mutate(
  rotarod_latency = mean(grepl('rotarod', young_scirep)))

young_scirep$rot_lat <- rowMeans(young_scirep[
  ,which(grepl("rotarod", colnames(young_scirep)))])

## prior for genotype effect, using Gaussian likelihood
mprio_norm <- glmmTMB(rot_lat~genotype, data = young_scirep)
summary(mprio_norm)
 Family: gaussian  ( identity )
Formula:          rot_lat ~ genotype
Data: young_scirep

     AIC      BIC   logLik deviance df.resid 
   569.5    575.6   -281.8    563.5       52 


Dispersion estimate for gaussian family (sigma^2): 1.65e+03 

Conditional model:
            Estimate Std. Error z value Pr(>|z|)    
(Intercept)  134.771      7.416  18.174   <2e-16 ***
genotypew     24.259     10.999   2.206   0.0274 *  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
prios(mprio_norm)
 Estimate           
 2.701332 32.337246 
## prior for genotype effect with Gamma likelihood
mprio_norm <- glmmTMB(rot_lat~genotype, data = young_scirep,family=Gamma(link="log"))
summary(mprio_norm)
 Family: Gamma  ( log )
Formula:          rot_lat ~ genotype
Data: young_scirep

     AIC      BIC   logLik deviance df.resid 
   567.2    573.2   -280.6    561.2       52 


Dispersion estimate for Gamma family (sigma^2): 0.079 

Conditional model:
            Estimate Std. Error z value Pr(>|z|)    
(Intercept)  4.90358    0.05133   95.53   <2e-16 ***
genotypew    0.16552    0.07613    2.17   0.0297 *  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
prios(mprio_norm)
  Estimate            
0.01629459 0.22383596 
## summary statistics
mean(rot_post_co$rot_latency)
[1] 126.674
mean(rot_post_co[rot_post_co$genotype == 'sca', c('rot_latency')])
[1] 109.2742
sd(rot_post_co$rot_latency) *c(5, 2, 1.2)
[1] 229.65135  91.86054  55.11632
sd(rot_post_co[rot_post_co$genotype == 'sca', c('rot_latency')])*c(5, 2, 1.2)
[1] 191.03904  76.41562  45.84937
mean(log(rot_post_co$rot_latency))
[1] 4.765482
mean(log(rot_post_co[rot_post_co$genotype == 'sca', c('rot_latency')]))
[1] 4.621306
sd(log(rot_post_co$rot_latency))*c(5)
[1] 2.07183

4.2 Setting priors, preTreat RotLat: all days

## priors for Gaussian model
prior01 <- c(set_prior("student_t(3, 127, 229)", class = "b", coef = "Intercept"),
             set_prior("normal(0,92)", class = "b", coef = "groupctrl.wt"),
             set_prior("normal(0,92)", class = "b", coef = "groupeda.wt"),
             set_prior("normal(0,46)"  , class = "b", coef = "groupeda.sca"),
             set_prior("normal(10,20)", class = "b", coef = "day_cen"),
             set_prior("normal(0,20)", class = "b", coef = "session_cen"),
             set_prior("normal(0,2)", class = "b", coef = "session_cen:day_cen"),
             set_prior("normal(0.5,2)", class = "b", coef = "mean_lat.x"))

## prior for Gamma (log-linked) model
prior02 <- c(set_prior("student_t(3, 4.8, 2.1)", class = "b", coef = "Intercept"),
             set_prior("normal(0,2)", class = "b", coef = "groupctrl.wt"),
             set_prior("normal(0,2)", class = "b", coef = "groupeda.wt"),
             set_prior("normal(0,1.2)", class = "b", coef = "groupeda.sca"),
             set_prior("normal(0.2,0.5)", class = "b", coef = "day_cen"),
             set_prior("normal(0,0.5)", class = "b", coef = "session_cen"),
             set_prior("normal(0,0.2)", class = "b", coef = "session_cen:day_cen"),
             set_prior("normal(0.5,1)", class = "b", coef = "mean_lat.x"))

4.3 Fitting and diagnsotics, preTreat RotLat: all days

## fitting gaussian model
model1 <- run_model(
          brm(rot_latency ~ 0 + Intercept + mean_lat.x + session_cen + 
                day_cen + session_cen:day_cen + group + (1|id),
              family=gaussian(),
              data = rot_post_co, 
              prior= prior01,
              save_pars = save_pars(all = TRUE),
              iter=8000, warmup=2000,chains=2,cores=1,seed=17,
              control = list(adapt_delta = 0.99, max_treedepth = 15)),
              'output/brm/model1', reuse = TRUE)

### fitting gamma model
model2 <- run_model(
          brm(rot_latency ~ 0 + Intercept + mean_lat.x + session_cen + 
                day_cen + session_cen:day_cen + group + (1|id),
              family=Gamma(link = 'log'),
              data = rot_post_co, 
              prior= prior02,
              save_pars = save_pars(all = TRUE),
              iter=8000, warmup=2000,chains=2,cores=1,seed=17,
              control = list(adapt_delta = 0.99, max_treedepth = 15)),
              'output/brm/model2', reuse = TRUE)

## models summary 
summary(model1)
 Family: gaussian 
  Links: mu = identity; sigma = identity 
Formula: rot_latency ~ 0 + Intercept + mean_lat.x + session_cen + day_cen + session_cen:day_cen + group + (1 | id) 
   Data: rot_post_co (Number of observations: 960) 
  Draws: 2 chains, each with iter = 8000; warmup = 2000; thin = 1;
         total post-warmup draws = 12000

Group-Level Effects: 
~id (Number of levels: 80) 
              Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sd(Intercept)    24.22      2.29    20.09    29.10 1.00     2140     4087

Population-Level Effects: 
                    Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept              39.03     14.23    10.97    66.87 1.00     1272     2805
mean_lat.x              0.56      0.11     0.35     0.77 1.00     1358     2896
session_cen             5.90      0.89     4.15     7.63 1.00    12064     9673
day_cen                 8.99      1.23     6.56    11.37 1.00    10391     8646
groupctrl.wt           29.56      8.21    13.30    46.05 1.00     1211     2165
groupeda.wt            27.82      8.16    11.59    43.94 1.00     1536     3203
groupeda.sca            3.29      7.95   -12.34    18.69 1.00     1313     2785
session_cen:day_cen    -0.26      0.96    -2.13     1.63 1.00    11634     9794

Family Specific Parameters: 
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sigma    30.88      0.73    29.48    32.33 1.00    10860     9755

Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
summary(model2)
 Family: gamma 
  Links: mu = log; shape = identity 
Formula: rot_latency ~ 0 + Intercept + mean_lat.x + session_cen + day_cen + session_cen:day_cen + group + (1 | id) 
   Data: rot_post_co (Number of observations: 960) 
  Draws: 2 chains, each with iter = 8000; warmup = 2000; thin = 1;
         total post-warmup draws = 12000

Group-Level Effects: 
~id (Number of levels: 80) 
              Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sd(Intercept)     0.20      0.02     0.17     0.24 1.00     3088     5140

Population-Level Effects: 
                    Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept               4.11      0.12     3.88     4.35 1.00     3155     4839
mean_lat.x              0.00      0.00     0.00     0.01 1.00     3220     4962
session_cen             0.05      0.01     0.03     0.06 1.00    17402     8648
day_cen                 0.07      0.01     0.05     0.09 1.00    16963     8730
groupctrl.wt            0.26      0.07     0.12     0.40 1.00     2524     4237
groupeda.wt             0.25      0.07     0.11     0.38 1.00     2755     4614
groupeda.sca            0.05      0.07    -0.08     0.19 1.00     2617     4652
session_cen:day_cen    -0.01      0.01    -0.02     0.01 1.00    16026     8456

Family Specific Parameters: 
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
shape    12.82      0.61    11.66    14.04 1.00    14064     8030

Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).

Convergence is OK; both models lead to the same conclusions and similar estimates

4.4 PPC, preTreat RotLat: all days

pla<-pp_check(model1,type='dens_overlay',ndraws = 50)
plb<-pp_check(model2,type='dens_overlay',ndraws = 50) 
plot_grid(pla, plb, labels=c("A", "B"), ncol = 1, nrow = 2)

pla<-pp_check(model1,type='dens_overlay_grouped',ndraws = 50,group='group') 
plb<-pp_check(model2,type='dens_overlay_grouped',ndraws = 50,group='group') 
plot_grid(pla, plb, labels=c("A", "B"), ncol = 1, nrow = 2)

pla<-pp_check(model1,type='scatter_avg') 
Using all posterior draws for ppc type 'scatter_avg' by default.
plb<-pp_check(model2,type='scatter_avg') 
Using all posterior draws for ppc type 'scatter_avg' by default.
plot_grid(pla, plb, labels=c("A", "B"), ncol = 1, nrow = 2)

pla<-pp_check(model1,type='ecdf_overlay_grouped',ndraws = 50,group='group') 
plb<-pp_check(model2,type='ecdf_overlay_grouped',ndraws = 50,group='group') 
plot_grid(pla, plb, labels=c("A", "B"), ncol = 1, nrow = 2)

pla<-pp_check(model1,type="stat_2d", stat = c("max", "min"),ndraws=200)
plb<-pp_check(model2,type="stat_2d", stat = c("max", "min"),ndraws=200)
plot_grid(pla, plb, labels=c("A", "B"), ncol = 1, nrow = 2)

pla<-pp_check(model1,type="stat_2d", stat = c("mean", "sd"),ndraws=200)
plb<-pp_check(model2,type="stat_2d", stat = c("mean", "sd"),ndraws=200)
plot_grid(pla, plb, labels=c("A", "B"), ncol = 1, nrow = 2)

### Are there too influential observations?
par(mfrow=c(1,2))
plot(loo(model1));loo(model1)

Computed from 12000 by 960 log-likelihood matrix

         Estimate   SE
elpd_loo  -4694.3 26.9
p_loo        73.1  4.1
looic      9388.6 53.8
------
Monte Carlo SE of elpd_loo is 0.1.

Pareto k diagnostic values:
                         Count Pct.    Min. n_eff
(-Inf, 0.5]   (good)     959   99.9%   2736      
 (0.5, 0.7]   (ok)         1    0.1%   561       
   (0.7, 1]   (bad)        0    0.0%   <NA>      
   (1, Inf)   (very bad)   0    0.0%   <NA>      

All Pareto k estimates are ok (k < 0.7).
See help('pareto-k-diagnostic') for details.
plot(loo(model2));loo(model2)


Computed from 12000 by 960 log-likelihood matrix

         Estimate   SE
elpd_loo  -4759.1 28.9
p_loo        62.9  3.4
looic      9518.1 57.7
------
Monte Carlo SE of elpd_loo is 0.1.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Posterior predictive checks (PPC) shows that Gaussian model fits data clearly better than Gamma model. All models are OK, no pareto value > 0.7, indicating no overly influential observation

Lets to fit two other Gaussian models with different deficnition of pre-treatment rotarod latency

4.5 Setting prior for other models

## preTreat RotLat: 3rd day only
prior03 <- c(set_prior("student_t(3, 127, 229)", class = "b", coef = "Intercept"),
             set_prior("normal(0,92)", class = "b", coef = "groupctrl.wt"),
             set_prior("normal(0,92)", class = "b", coef = "groupeda.wt"),
             set_prior("normal(0,46)"  , class = "b", coef = "groupeda.sca"),
             set_prior("normal(10,20)", class = "b", coef = "day_cen"),
             set_prior("normal(0,20)", class = "b", coef = "session_cen"),
             set_prior("normal(0,2)", class = "b", coef = "session_cen:day_cen"),
             set_prior("normal(0.5,2)", class = "b", coef = "mean_lat"))

## preTreat RotLat: 2nd and 3rd day
prior04 <- c(set_prior("student_t(3, 127, 229)", class = "b", coef = "Intercept"),
             set_prior("normal(0,92)", class = "b", coef = "groupctrl.wt"),
             set_prior("normal(0,92)", class = "b", coef = "groupeda.wt"),
             set_prior("normal(0,46)"  , class = "b", coef = "groupeda.sca"),
             set_prior("normal(10,20)", class = "b", coef = "day_cen"),
             set_prior("normal(0,20)", class = "b", coef = "session_cen"),
             set_prior("normal(0,2)", class = "b", coef = "session_cen:day_cen"),
             set_prior("normal(0.5,2)", class = "b", coef = "mean_lat.y"))

4.6 Fitting and diagnsotics, preTreat RotLat: 3rd (+2nd) days

## preTreat RotLat: 3rd day only
model3 <- run_model(
          brm(rot_latency ~ 0 + Intercept + mean_lat + session_cen + 
              day_cen + session_cen:day_cen + group + (1|id),
              family=gaussian(),
              data = rot_post_co, 
              prior= prior03,
              save_pars = save_pars(all = TRUE),
              iter=8000, warmup=2000,chains=2,cores=1,seed=17,
              control = list(adapt_delta = 0.99)),
              'output/brm/model3', reuse = TRUE)

## preTreat RotLat: 2nd + 3rd day
model4 <- run_model(
          brm(rot_latency ~ 0 + Intercept + mean_lat.y + session_cen + 
              day_cen + session_cen:day_cen + group + (1|id),
              family=gaussian(),
              data = rot_post_co, 
              prior= prior04,
              save_pars = save_pars(all = TRUE),
              iter=8000, warmup=2000,chains=2,cores=1,seed=17,
              control = list(adapt_delta = 0.99)),
              'output/brm/model4', reuse = TRUE)

## models summary
summary(model3)
 Family: gaussian 
  Links: mu = identity; sigma = identity 
Formula: rot_latency ~ 0 + Intercept + mean_lat + session_cen + day_cen + session_cen:day_cen + group + (1 | id) 
   Data: rot_post_co (Number of observations: 960) 
  Draws: 2 chains, each with iter = 8000; warmup = 2000; thin = 1;
         total post-warmup draws = 12000

Group-Level Effects: 
~id (Number of levels: 80) 
              Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sd(Intercept)    25.41      2.35    21.25    30.35 1.00     2368     4856

Population-Level Effects: 
                    Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept              57.53     12.68    32.65    82.28 1.00     1533     2830
mean_lat                0.38      0.08     0.21     0.54 1.00     1635     3175
session_cen             5.89      0.90     4.12     7.66 1.00    12401     8102
day_cen                 8.97      1.22     6.56    11.37 1.00    14924     9215
groupctrl.wt           26.77      8.58    10.17    43.81 1.00     1583     3191
groupeda.wt            27.79      8.89    10.47    45.04 1.00     1713     3408
groupeda.sca            2.87      8.39   -13.56    19.45 1.00     1604     3085
session_cen:day_cen    -0.27      0.94    -2.14     1.56 1.00    12862     9054

Family Specific Parameters: 
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sigma    30.89      0.73    29.50    32.35 1.00    11835     9004

Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
summary(model4)
 Family: gaussian 
  Links: mu = identity; sigma = identity 
Formula: rot_latency ~ 0 + Intercept + mean_lat.y + session_cen + day_cen + session_cen:day_cen + group + (1 | id) 
   Data: rot_post_co (Number of observations: 960) 
  Draws: 2 chains, each with iter = 8000; warmup = 2000; thin = 1;
         total post-warmup draws = 12000

Group-Level Effects: 
~id (Number of levels: 80) 
              Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sd(Intercept)    24.55      2.31    20.48    29.48 1.00     2335     4617

Population-Level Effects: 
                    Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept              47.30     13.27    21.52    73.68 1.00     1657     2816
mean_lat.y              0.47      0.09     0.29     0.65 1.00     1464     3143
session_cen             5.89      0.90     4.13     7.64 1.00    13934     8304
day_cen                 8.96      1.23     6.53    11.38 1.00    12177     8586
groupctrl.wt           25.76      8.42     9.39    42.52 1.00     1587     3152
groupeda.wt            25.71      8.75     8.25    42.69 1.00     1504     2833
groupeda.sca            1.51      8.23   -15.36    17.35 1.00     1433     2399
session_cen:day_cen    -0.26      0.97    -2.18     1.64 1.00    13103     8714

Family Specific Parameters: 
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sigma    30.91      0.73    29.52    32.39 1.00    10656     8660

Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).

All models converged well (Rhat values = 1), ESSs are sufficient

4.7 PPC, preTreat RotLat: 3rd (+2nd) days

pla<-pp_check(model3,type='dens_overlay',ndraws = 50)
plb<-pp_check(model4,type='dens_overlay',ndraws = 50) 
plot_grid(pla, plb, labels=c("A", "B"), ncol = 1, nrow = 2)

pla<-pp_check(model3,type='dens_overlay_grouped',ndraws = 50,group='group') 
plb<-pp_check(model4,type='dens_overlay_grouped',ndraws = 50,group='group') 
plot_grid(pla, plb, labels=c("A", "B"), ncol = 1, nrow = 2)

pla<-pp_check(model3,type='scatter_avg') 
Using all posterior draws for ppc type 'scatter_avg' by default.
plb<-pp_check(model4,type='scatter_avg') 
Using all posterior draws for ppc type 'scatter_avg' by default.
plot_grid(pla, plb, labels=c("A", "B"), ncol = 1, nrow = 2)

pla<-pp_check(model3,type="stat_2d", stat = c("max", "min"),ndraws=200)
plb<-pp_check(model4,type="stat_2d", stat = c("max", "min"),ndraws=200)
plot_grid(pla, plb, labels=c("A", "B"), ncol = 1, nrow = 2)

pla<-pp_check(model3,type="stat_2d", stat = c("mean", "sd"),ndraws=200)
plb<-pp_check(model4,type="stat_2d", stat = c("mean", "sd"),ndraws=200)
plot_grid(pla, plb, labels=c("A", "B"), ncol = 1, nrow = 2)

### Are there too influential observations?
par(mfrow=c(1,2))
plot(loo(model3));loo(model3)

Computed from 12000 by 960 log-likelihood matrix

         Estimate   SE
elpd_loo  -4694.8 26.8
p_loo        74.0  4.1
looic      9389.6 53.6
------
Monte Carlo SE of elpd_loo is 0.1.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.
plot(loo(model4));loo(model4)


Computed from 12000 by 960 log-likelihood matrix

         Estimate   SE
elpd_loo  -4694.7 26.8
p_loo        73.5  4.1
looic      9389.5 53.6
------
Monte Carlo SE of elpd_loo is 0.1.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.

Everything seems fine.

4.8 Models comparison

Next, we will compare all three Gaussian models using LOO-CV

model1 <- add_criterion(model1, criterion = "loo")
model3 <- add_criterion(model3, criterion = "loo")
model4 <- add_criterion(model4, criterion = "loo")

loo_compare(model1, model3, model4)
       elpd_diff se_diff
model1  0.0       0.0   
model4 -0.5       0.6   
model3 -0.5       1.1   

Using baseline rotarod latency, averaged from all pre-treatment rotarod sessions, is comparable to using covariate from specifically 3rd or 2nd + 3rd day.

The model we currently have is, however, relatively simple. Likely the most importantly, it does not allow modelling the situation when group differ in day-to-day gain (implying motor learning).

Thus, let to create another model, which looks like model1 but also include interaction between group and effect of time

4.9 Model including group : day interaction

## fitting model
model5 <- run_model(
          brm(rot_latency ~ 0 + Intercept + mean_lat.x + session_cen + 
              day_cen + session_cen:day_cen + group + day_cen:group + (1|id),
              family=gaussian(),
              data = rot_post_co, 
              prior= prior01,
              save_pars = save_pars(all = TRUE),
              iter=8000, warmup=2000,chains=2,cores=1,seed=17,
              control = list(adapt_delta = 0.99, max_treedepth = 15)),
              'output/brm/model5', reuse = TRUE)

## model summary
summary(model5)
 Family: gaussian 
  Links: mu = identity; sigma = identity 
Formula: rot_latency ~ 0 + Intercept + mean_lat.x + session_cen + day_cen + session_cen:day_cen + group + day_cen:group + (1 | id) 
   Data: rot_post_co (Number of observations: 960) 
  Draws: 2 chains, each with iter = 8000; warmup = 2000; thin = 1;
         total post-warmup draws = 12000

Group-Level Effects: 
~id (Number of levels: 80) 
              Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sd(Intercept)    24.24      2.30    20.01    29.09 1.00     2994     4963

Population-Level Effects: 
                     Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS
Intercept               39.08     13.91    11.61    66.22 1.00     1919
mean_lat.x               0.56      0.11     0.36     0.77 1.00     1954
session_cen              5.90      0.90     4.16     7.63 1.00    13428
day_cen                  3.66      2.40    -1.02     8.35 1.00     4552
groupctrl.wt            29.77      8.20    13.69    45.72 1.00     1876
groupeda.wt             27.86      8.40    11.12    44.26 1.00     1603
groupeda.sca             3.42      8.10   -12.55    19.03 1.00     1815
session_cen:day_cen     -0.27      0.95    -2.17     1.59 1.00    15380
day_cen:groupctrl.wt    13.32      3.40     6.60    19.90 1.00     5779
day_cen:groupeda.wt      4.96      3.42    -1.73    11.68 1.00     5807
day_cen:groupeda.sca     3.01      3.38    -3.59     9.48 1.00     6298
                     Tail_ESS
Intercept                3810
mean_lat.x               3990
session_cen              9003
day_cen                  6931
groupctrl.wt             3583
groupeda.wt              3157
groupeda.sca             3156
session_cen:day_cen      8538
day_cen:groupctrl.wt     7919
day_cen:groupeda.wt      7749
day_cen:groupeda.sca     8316

Family Specific Parameters: 
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sigma    30.65      0.74    29.26    32.15 1.00    11851     8434

Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
## prior summary
prior_summary(model5)
                  prior class                 coef group resp dpar nlpar lb ub
                 (flat)     b                                                 
          normal(10,20)     b              day_cen                            
                 (flat)     b day_cen:groupctrl.wt                            
                 (flat)     b day_cen:groupeda.sca                            
                 (flat)     b  day_cen:groupeda.wt                            
           normal(0,92)     b         groupctrl.wt                            
           normal(0,46)     b         groupeda.sca                            
           normal(0,92)     b          groupeda.wt                            
 student_t(3, 127, 229)     b            Intercept                            
          normal(0.5,2)     b           mean_lat.x                            
           normal(0,20)     b          session_cen                            
            normal(0,2)     b  session_cen:day_cen                            
  student_t(3, 0, 45.3)    sd                                             0   
  student_t(3, 0, 45.3)    sd                         id                  0   
  student_t(3, 0, 45.3)    sd            Intercept    id                  0   
  student_t(3, 0, 45.3) sigma                                             0   
       source
      default
         user
 (vectorized)
 (vectorized)
 (vectorized)
         user
         user
         user
         user
         user
         user
         user
      default
 (vectorized)
 (vectorized)
      default
## PPC
pp_check(model5,type='dens_overlay',ndraws = 50)

pp_check(model5,type='dens_overlay_grouped',ndraws = 50,group='group') 

pp_check(model5,type='scatter_avg') 
Using all posterior draws for ppc type 'scatter_avg' by default.

pp_check(model5,type="stat_2d", stat = c("max", "min"),ndraws=200)

pp_check(model5,type="stat_2d", stat = c("mean", "sd"),ndraws=200)

## Are there too influential observations?

plot(loo(model5));loo(model5)


Computed from 12000 by 960 log-likelihood matrix

         Estimate   SE
elpd_loo  -4688.7 26.3
p_loo        76.3  4.1
looic      9377.3 52.6
------
Monte Carlo SE of elpd_loo is 0.1.

All Pareto k estimates are good (k < 0.5).
See help('pareto-k-diagnostic') for details.
## comparing with original model via LOO-CV
model5 <- add_criterion(model5, criterion = "loo")
loo_compare(model1, model5) 
       elpd_diff se_diff
model5  0.0       0.0   
model1 -5.6       4.8   

Models comparison indicate that more complex model, allowing group-specific change in rotarod performance over day, has better predictive accuracy. The last complex model (Gaussian distribution, ignoring sex, including day : group interaction) thus will be used as the final model.

The model coverged well, ESSs are sufficient, PPC seems fine.

4.10 Posterior draws extraction

post_fix<-as.data.frame(model5, variable = c("b_Intercept","b_groupctrl.wt",
                                                       "b_groupeda.wt","b_groupeda.sca"))
names(post_fix)[1]<-"sca_ctrl"

post_fix$wt_ctrl<-post_fix$sca_ctrl+post_fix$b_groupctrl.wt
post_fix$wt_eda<-post_fix$sca_ctrl+post_fix$b_groupeda.wt
post_fix$sca_eda<-post_fix$sca_ctrl+post_fix$b_groupeda.sca
post_fix$wt_contrast<-post_fix$wt_eda-post_fix$wt_ctrl
summary(post_fix)
    sca_ctrl      b_groupctrl.wt    b_groupeda.wt    b_groupeda.sca   
 Min.   :-16.00   Min.   : 0.5698   Min.   :-5.929   Min.   :-28.281  
 1st Qu.: 29.81   1st Qu.:24.2420   1st Qu.:22.191   1st Qu.: -2.051  
 Median : 39.13   Median :29.8007   Median :27.892   Median :  3.351  
 Mean   : 39.08   Mean   :29.7691   Mean   :27.858   Mean   :  3.416  
 3rd Qu.: 48.53   3rd Qu.:35.2160   3rd Qu.:33.536   3rd Qu.:  9.024  
 Max.   : 91.93   Max.   :66.4481   Max.   :62.362   Max.   : 33.938  
    wt_ctrl           wt_eda           sca_eda        wt_contrast     
 Min.   :  9.15   Min.   :  2.729   Min.   :-14.06   Min.   :-40.123  
 1st Qu.: 58.85   1st Qu.: 56.104   1st Qu.: 32.93   1st Qu.: -7.248  
 Median : 69.06   Median : 67.066   Median : 42.76   Median : -1.859  
 Mean   : 68.85   Mean   : 66.939   Mean   : 42.50   Mean   : -1.911  
 3rd Qu.: 78.94   3rd Qu.: 77.698   3rd Qu.: 52.27   3rd Qu.:  3.473  
 Max.   :126.46   Max.   :124.232   Max.   :103.39   Max.   : 30.281  
groupquant<-sapply(post_fix[,c(5,6,1,7)],function(p) quantile(p, probs = c(0.025,0.975,0.5)))
groupquant <- groupquant

5 Data visualisation

rot_post_co$group <- factor(rot_post_co$group,levels = c('ctrl.wt','eda.wt','ctrl.sca','eda.sca') )

m= matrix(c(1,2), nrow = 1, ncol=2, byrow = TRUE)
layout(mat = m, heights = c(1),
       widths = c(0.65, 0.4))

par(mar=c(2,3,0,0))
par(mgp=c(2,0.6,0))
range<-c(0, 180);scal<-range[2]-range[1]
xrange<-c(0.5,4.5);xscal=xrange[2]-xrange[1]
plot(NULL,xlim=c(xrange[1],xrange[2]),ylim=c(range[1],range[2]),xlab="",
     ylab="Rotarod latency (s)",las=1, axes=FALSE,cex.lab=1.2)

rect(xrange[1],range[2],xrange[2],range[1],col="grey92",border=NA)
x<-range[1]
repeat{
  lines(c(xrange[1],xrange[2]),c(x,x),col="white",lwd=0.7)
  x=x+30;if(x>range[2]){break}}

x<-0.5
repeat{
  lines(c(x,x),c(range[1],range[2]),col="white",lwd=0.7)
  x=x+0.5;if(x>4.5){break}}

  
subdat <- subset(rotarod, pre_post == 'pre' & day == 1) 
preD1 <- tapply(subdat$rot_latency, list(subdat$group, subdat$session), mean)
subdat <- subset(rotarod, pre_post == 'pre' & day == 2) 
preD2 <- tapply(subdat$rot_latency, list(subdat$group, subdat$session), mean)
subdat <- subset(rotarod, pre_post == 'pre' & day == 3) 
preD3 <- tapply(subdat$rot_latency, list(subdat$group, subdat$session), mean)


subdat <- subset(rotarod, pre_post == 'post' & day == 1) 
postD1 <- tapply(subdat$rot_latency, list(subdat$group, subdat$session), mean)
subdat <- subset(rotarod, pre_post == 'post' & day == 2) 
postD2 <- tapply(subdat$rot_latency, list(subdat$group, subdat$session), mean)
subdat <- subset(rotarod, pre_post == 'post' & day == 3) 
postD3 <- tapply(subdat$rot_latency, list(subdat$group, subdat$session), mean)

xl <- c(0.85, 0.95, 1.05, 1.15)

for (x in 1:4){
lines(preD1[x,]~c(xl),col=cola[x], lwd = 1.6, type = 'o', pch= 16)
lines(preD2[x,]~c(xl+0.5),col= cola[x], lwd = 1.6, type = 'o', pch= 16)
lines(preD3[x,]~c(xl+1),col= cola[x], lwd = 1.6,, type = 'o', pch= 16)
lines(postD1[x,]~c(xl+2),col= cola[x], lwd = 1.6, type = 'o', pch= 16)
lines(postD2[x,]~c(xl+2.5),col= cola[x], lwd = 1.6, type = 'o', pch= 16)
lines(postD3[x,]~c(xl+3),col= cola[x], lwd = 1.6, type = 'o', pch= 16)
}

tckk=-0.02

axis(2,las=2,cex.axis=1.1,at=seq(range[1],range[2],by=30),pos=xrange[1],tck=tckk)

axis(side=1,las=1,cex.axis=1.1,at=c(1,1.5,2,3,3.5,4),
     labels=c(rep("",6)),pos=range[1],tck=tckk)
lines(c(0.5,4.5), c(0,0))
text(c(1, 1.5, 2, 3, 3.5, 4) ,c(rep(range[1]-0.05*scal)),
     c('D1', 'D2', 'D3', 'D1', 'D2', 'D3'), xpd= TRUE)

text(c(1.5, 3.5),c(range[1]-0.117*scal, range[1]-0.117*scal),
     c('PRE', 'POST'), font = 2, xpd = TRUE)
lines(c(1,2),c(range[1]-0.085*scal, range[1]-0.085*scal), xpd = TRUE)
lines(c(3,4),c(range[1]-0.085*scal, range[1]-0.085*scal), xpd = TRUE)

x = 1  
y = 58;yde <- 10
lines(c(1.2,1.6),c(y,y), col = cola[x], pch = 16, lwd = 1.6)
text(2.05, y, 'WT 0', col = cola[x])
points(1.4, y, pch = 16, col = cola[x]); x = x+1; y = y-yde

lines(c(1.2,1.6),c(y,y), col = cola[x], pch = 16, lwd = 1.6)
text(2.05, y, 'WT edv', col = cola[x])
points(1.4, y, pch = 16, col = cola[x]); x = x+1; y = y-yde

lines(c(1.2,1.6),c(y,y), col = cola[x], pch = 16, lwd = 1.6)
text(2.05, y, 'SCA1 0', col = cola[x])
points(1.4, y, pch = 16, col = cola[x]); x = x+1; y = y-yde

lines(c(1.2,1.6),c(y,y), col = cola[x], pch = 16, lwd = 1.6)
text(2.05, y, 'SCA1 edv', col = cola[x])
points(1.4, y, pch = 16, col = cola[x]); x = x+1; y = y-yde

## probability distributions 
par(mar=c(2,0,0,0))
dif<-data.frame(post_fix$wt_contrast,post_fix$b_groupeda.sca,
                post_fix$b_groupctrl.wt)
dif<-(dif)

yla<-"Difference in rotarod latency (s)"
tckk=-0.018
ste<-seq(-40,60,by=20)
mons_poste(dif, 0)

zpos=seq(0,1,1/3)
xx=1;ind=0.4;xpol<- -32
text(xpol,zpos[xx]+zpos[2]*ind,
     "Wt: ed x 0 ",cex=1)
xx=xx+1

text(xpol,zpos[xx]+zpos[2]*ind,
     "SCA1: ed x 0 ",cex=1)
xx=xx+1

text(xpol,zpos[xx]+zpos[2]*ind,
     "0: Wt x SCA1",cex=1)