library("lme4")
library("performance")
library("marginaleffects")
d <- readr::read_csv("data/calf-growth.csv")
head(d, 3)Class 10: one animal, several observations
Aarhus University
Wednesday, 11 November 2026
| Time | Work |
|---|---|
| 12:30–12:40 | Opening recall: allocation and repeated measurements |
| 12:40–13:15 | Calves: one diet, several weights |
| 13:15–13:40 | Cows: both treatments, in a random order |
| 13:40–13:55 | Break |
| 13:55–14:55 | Fit and check the crossover model |
| 14:55–15:10 | Break |
| 15:10–15:35 | Save a project analysis plan |
| 15:35–16:00 | Compare designs, report and exit |
Last class we saw animals sharing pens. A shared feeder means a whole pen may receive one diet.
Today, 32 individually housed calves each receive their own randomly assigned diet, within four rooms. Each calf is weighed five times.
Discuss with your seated group: did researchers choose a diet for each calf or for a whole room? If they assigned 16 calves to each diet, does weighing every calf five times create more diet assignments?
Control and Enhanced diets start after the baseline weight.
Calves are weighed at weeks 0, 2, 4, 6 and 8.
Our first question: how much heavier, on average, are Enhanced calves at week 8?
These are synthetic teaching data. We are practising analysis, not making a feeding recommendation.
Run in-class-student.R from the project root. These packages supply the tools we use directly.
One row is one weight. calf identifies repeated observations of the same animal.
# A tibble: 3 × 5
room calf diet time_week weight_kg
<chr> <chr> <chr> <dbl> <dbl>
1 R1 C01 Control 0 47.9
2 R1 C01 Control 2 58.6
3 R1 C01 Control 4 65.8
A category is a label rather than a numerical trend.
[1] "0" "2" "4" "6" "8"
Here we estimate a mean at each visit. We do not yet choose a growth curve between visits.
distinct() keeps each calf’s allocation once.
# A tibble: 8 × 3
room diet n
<fct> <fct> <int>
1 R1 Control 4
2 R1 Enhanced 4
3 R2 Control 4
4 R2 Enhanced 4
5 R3 Control 4
6 R3 Enhanced 4
7 R4 Control 4
8 R4 Enhanced 4
calves weights
32 160
Four calves per diet per room: 16 calves assigned to each diet, not 80.
Some calves tend to be heavier at every visit. (1 | calf) lets the model represent that shared pattern.
room allows different room means. diet * time_factor allows the diet gap to differ between visits.
Linear mixed model fit by REML ['lmerMod']
Formula: weight_kg ~ room + diet * time_factor + (1 | calf)
Data: d
REML criterion at convergence: 701.4
Scaled residuals:
Min 1Q Median 3Q Max
-2.31755 -0.51062 0.00236 0.64098 1.95874
Random effects:
Groups Name Variance Std.Dev.
calf (Intercept) 29.094 5.394
Residual 2.541 1.594
Number of obs: 160, groups: calf, 32
Fixed effects:
Estimate Std. Error t value
(Intercept) 38.43207 2.18001 17.629
roomR2 0.05863 2.72041 0.022
roomR3 2.40960 2.72041 0.886
roomR4 4.03348 2.72041 1.483
dietEnhanced 0.02500 1.98857 0.013
time_factor2 10.71919 0.56358 19.020
time_factor4 19.11194 0.56358 33.911
time_factor6 28.42313 0.56358 50.433
time_factor8 36.45800 0.56358 64.690
dietEnhanced:time_factor2 0.44562 0.79703 0.559
dietEnhanced:time_factor4 3.22037 0.79703 4.040
dietEnhanced:time_factor6 2.60100 0.79703 3.263
dietEnhanced:time_factor8 3.19725 0.79703 4.011
Correlation matrix not shown by default, as p = 13 > 12.
Use print(x, correlation=TRUE) or
vcov(x) if you need it
avg_comparisons() changes the diet label and compares the resulting predicted weights. by requests a row for each week.
Positive means Enhanced minus Control in kg. The comparison gives each of the four study rooms equal weight. re.form = NA sets each calf’s fitted weight difference to zero.
time_factor Estimate Std. Error z Pr(>|z|) S 2.5 % 97.5 %
0 0.025 1.99 0.0126 0.990 0.0 -3.872 3.92
2 0.471 1.99 0.2367 0.813 0.3 -3.427 4.37
4 3.245 1.99 1.6320 0.103 3.3 -0.652 7.14
6 2.626 1.99 1.3206 0.187 2.4 -1.271 6.52
8 3.222 1.99 1.6204 0.105 3.2 -0.675 7.12
Term: diet
Type: response
Comparison: Enhanced - Control
[1] TRUE
attr(,"gradient")
[1] 2.904132e-09
[1] FALSE
First result: did the fitting calculation finish successfully?
Second result: did the estimated between-calf variation collapse to zero? Here FALSE means it did not.
A successful calculation cannot tell us whether nearby weights share additional influences. We return to that issue in Class 11.
A researcher compares two rations, A and B, using daily feed intake.
In a crossover study, each cow receives A in one treatment period and B in another.
The same cow provides the two measurements. This may help when cows differ greatly in appetite.
It works only if a cow can return to a suitable starting condition between treatments.
| Assigned order, called the sequence | First treatment period | Second treatment period |
|---|---|---|
| AB: 12 cows | A | B |
| BA: 12 cows | B | A |
Randomly assign 24 cows to these two orders.
A period is a scheduled treatment phase. Both treatments appear in both periods, so a general change over time can be separated from the treatment comparison.
This synthetic example records average intake over the final three days of each ten-day treatment period. A ten-day treatment-free gap is specified between periods.
A washout is time for the earlier treatment’s influence to wear off. Carryover means that influence remains.
The stated ten days is a teaching assumption. A real study needs evidence about the particular treatment and outcome.
A ration may have a short-lived effect on intake. A vaccine may cause a lasting change. Growth and recovery may also be irreversible.
For each example, discuss: could the first treatment change the cow’s later outcome even after treatment stops?
If so, extending the gap needs scientific justification; assigning separate animals to treatments may be more appropriate.
Our cow study has two periods and two assigned orders.
After the break, we fit a model that allows for period and cows’ usual differences in appetite.
Break 13:40–13:55.