Here’s the data from our Oxidative Stress gene panel, which has been cleaned by:
Removing missing DCq values
Removing genes missing either N or IH Condition
Removing genes having less than 3 data points in either the N or IH Condition
2 Model fitting & diagnostics
2.1 Model fitting
Let’s define the model we will fit to each Gene’s DCq data.
Here, we will fit a Linear Mixed Effect Model, with a random effect per Experiment, to account for potential clustering:
\[
\begin{aligned}
DCq_{i} &\sim N \left(\alpha_{j[i]} + \beta_{1}(Condition), \sigma^2 \right) \\
\alpha_{j} &\sim N \left(\mu_{\alpha_{j}}, \sigma^2_{\alpha_{j}} \right)
\text{, for Experiment j = 1,} \dots \text{,J}
\end{aligned}
\]
OS_model<-function(data){form<-"DCq ~ Condition"# If the data contains an Experiment variable with more than two levels, add a random effect by Experimentif("Experiment"%in%colnames(data)&&n_distinct(data$Experiment)>=2)form<-str_c(form, " + (1 | Experiment)")glmmTMB(as.formula(form), family =gaussian("identity"), data =data, contrasts =list(Condition ="contr.sum"))}
Now, let’s fit said model to each Gene’s data, for a given Stage and Layer:
(OS_data$models<-OS_data$clean|>group_split(Stage, Layer, Gene)|>map_dfr( \(d)summarize(d, Mod =pick(Experiment, Condition, DCq)|>OS_model()|>list(), .by =c(Stage, Layer, Gene)), .progress ="Fitting models:")|>filter(!has_na_coefs(Mod))# Removing models that did not fit properly|>mutate(Fold =map_dbl(Mod, compute_fold_change))# Adding the Fold change|>select(Stage, Layer, Gene, Fold, Mod))
2.2 Model diagnostics
Here are the diagnostic plots for a random sample of the fitted models:
3 Model analysis
For each model we fit, we can then extract the CI and p.value for the relevant contrasts, and use those to establish if a Gene was up or down-regulated:
To get a better idea of how each Gene’s regulation changes through time, we can plot a timeline of their expression, split by Layer and Pathway, with a color coding of the Effect of this regulation.