Extendable projection of social contact matrices

Telethon Kids Institute

Nicholas Tierney, Chitra Saraswati, Michael Lydeamore, Nick Golding, Aarathy Babu

Telethon Kids Institute

2024-07-24

Welcome!

  • First Infectious Disease Modelling Seminar Series!
  • Questions + discussion are welcome throughout

What this talk is about

  • Touch on the overall approach for methods. A large portion of my role was on software and interface design.

  • Why we needed our own method + software

  • Discuss applications of contact matrices

Joining an infectious disease team

  • August, 2021: Australia is working on the plan to reopen, part of “The Doherty Report”

  • I helped develop pipelines + software for disease modelling, establish code base for people to contribute

Social spread of disease

  • Diseases like COVID19 and Influenza spread through face to face social contact
  • Describe which 3 people had contact:

    • James has had contact with Luke

    • Nick has had contact with neither

Example: visually

Example: matrix

      James  Luke  Nick
James    NA  TRUE FALSE
Luke   TRUE    NA FALSE
Nick  FALSE FALSE    NA

Logical –> Numeric

People –> Age groups

What do you do with a contact matrix?

  • If we know the number of times people have contact, we can model:
    • Which age groups might spread COVID
    • How many COVID cases would get transmitted
    • How vaccination reduces transmission
  • Do the above for different areas in Australia

Do we know how much contact people have?

  • We don’t. Well, not in Australia. Yet.

  • You need to conduct a survey where people diary the amount and manner of daily contacts they have.

  • Mossong et al have this for 8 countries in Europe

  • Referred to as the POLYMOD study

POLYMOD

Published in 2008, Mossong et. al undertook a contact diary study of 7290 participants across Europe.

It remains the most widely cited contact diary study.

Method of Mossong et al

  • Random weekday: record every person in contact with.
  • Physical contact:
    • skin-to-skin contact (kiss or handshake)
  • Non-physical contact:
    • two-way conversation with 3+ words in physical presence of a person

Method of Mossong et al

  • Participants provide info on:
    • age and sex of each contact person
    • location (home, work, school, etc)
    • time spent together
    • frequency of usual contacts with this individual

Contact surveys are 💰 💰 💰

  • Part of why we don’t have them in Australia
  • Can we get a contact matrix for a country not on the list?
  • We need to have a best guess from existing surveys

Synthetic contact matrices

  • Pre-existing statistical methodologies project empirical contact matrices to new countries.
  • New projected contact matrices: “synthetic contact matrices”
  • Use existing contact surveys (e.g., POLYMOD)
  • Use setting-specific survey data on household, school, classroom, and workplace composition
  • Combine with empirical data on contact patterns in Europe using statistical models

Prem et al

  • One of the most widely used approaches to synthetic contact matrices
  • Extensively applied across infectious diseases applications
  • Initially provided 152 matrices for 152 countries (177 later in 2020)

Creating synthetic contact matrices

  • Prem et. al formed a model that predicts the number of contacts based on the age of participants in different settings (Home, Work, School, Other)
  • \(\text{n_contacts} \sim age_{ij} + setting_{k}\)
  • This model then allows for prediction to settings that are outside the original POLYMOD countries.
  • They provide new contact matrices for a given country

What we want

  • We want to be able use a population age distribution
subiaco <- abs_age_lga("Subiaco (C)")
subiaco
# A tibble: 18 × 4 (conmat_population)
 - age: lower.age.limit
 - population: population
   lga         lower.age.limit  year population
   <chr>                 <dbl> <dbl>      <dbl>
 1 Subiaco (C)               0  2020        881
 2 Subiaco (C)               5  2020        962
 3 Subiaco (C)              10  2020        903
 4 Subiaco (C)              15  2020        922
 5 Subiaco (C)              20  2020        938
 6 Subiaco (C)              25  2020       1336
 7 Subiaco (C)              30  2020       1444
 8 Subiaco (C)              35  2020       1191
 9 Subiaco (C)              40  2020       1187
10 Subiaco (C)              45  2020       1101
11 Subiaco (C)              50  2020       1044
12 Subiaco (C)              55  2020       1049
13 Subiaco (C)              60  2020       1074
14 Subiaco (C)              65  2020        904
15 Subiaco (C)              70  2020        923
16 Subiaco (C)              75  2020        658
17 Subiaco (C)              80  2020        487
18 Subiaco (C)              85  2020        444

What we want

  • Input population age distribution and get out a contact matrix.
extrapolate_from_data(
  population = subiaco
)

How do we extend Prem’s method?

  • Prem’s code is on github 🎉

  • But a few key issues 🚨

    • It was code not written for reuse (code vs software)

      • No interface to specify a given country/region

      • Unclear which code matches which methods

      • Australia in original 152 countries, not in updated estimates provided in 2020.

An alternative approach

  • We developed an open-source approach

  • The R package conmat

  • It can be applied to any input population (big or small).

  • github.com/idem-lab/conmat

  • install using:

remotes::install_github("idem-lab/conmat")

Model details

  • These models don’t have much to go on. They are trained on the number of contacts between age groups \(i\) and \(j\):

\[\begin{aligned} c_{ij} = \beta_0 + \beta_1(|i-j|) + &\beta_2(|i-j|^2) + \beta_3(i\times j) + \beta_4(i+j) +\\ &\beta_5\max(i, j) + \beta_6\min(i, j) \end{aligned} \]

Tip

We want to fit this as a generalised additive model, so actually we have splines on these terms to satisfy the smoothness requirements. This is very similar to the approach by Prem et. al who perform post-hoc smoothing of the parameters after MCMC.

Model details

  • All that is needed to make predictions is the number of individuals in different age groups.
  • This is easily obtainable information from most statistics bureaus/governments.

Data sources

The socialmixr package has this information for most countries:

socialmixr::wpp_age("Australia", 2015)
     country lower.age.limit year population
1  Australia               0 2015    1545114
2  Australia               5 2015    1521110
3  Australia              10 2015    1416482
4  Australia              15 2015    1480341
5  Australia              20 2015    1663584
6  Australia              25 2015    1763281
7  Australia              30 2015    1753076
8  Australia              35 2015    1574157
9  Australia              40 2015    1655520
10 Australia              45 2015    1559506
11 Australia              50 2015    1569432
12 Australia              55 2015    1451869
13 Australia              60 2015    1281612
14 Australia              65 2015    1153780
15 Australia              70 2015     843695
16 Australia              75 2015     628870
17 Australia              80 2015     466797
18 Australia              85 2015     303108
19 Australia              90 2015     135089
20 Australia              95 2015      29268
21 Australia             100 2015       3855

And for inside Australia, conmat provides some ABS functions:

conmat::abs_age_lga("Subiaco (C)")
# A tibble: 18 × 4 (conmat_population)
 - age: lower.age.limit
 - population: population
   lga         lower.age.limit  year population
   <chr>                 <dbl> <dbl>      <dbl>
 1 Subiaco (C)               0  2020        881
 2 Subiaco (C)               5  2020        962
 3 Subiaco (C)              10  2020        903
 4 Subiaco (C)              15  2020        922
 5 Subiaco (C)              20  2020        938
 6 Subiaco (C)              25  2020       1336
 7 Subiaco (C)              30  2020       1444
 8 Subiaco (C)              35  2020       1191
 9 Subiaco (C)              40  2020       1187
10 Subiaco (C)              45  2020       1101
11 Subiaco (C)              50  2020       1044
12 Subiaco (C)              55  2020       1049
13 Subiaco (C)              60  2020       1074
14 Subiaco (C)              65  2020        904
15 Subiaco (C)              70  2020        923
16 Subiaco (C)              75  2020        658
17 Subiaco (C)              80  2020        487
18 Subiaco (C)              85  2020        444

Demonstration of conmat

library(conmat)
subiaco <- abs_age_lga("Subiaco (C)")
subiaco
# A tibble: 18 × 4 (conmat_population)
 - age: lower.age.limit
 - population: population
   lga         lower.age.limit  year population
   <chr>                 <dbl> <dbl>      <dbl>
 1 Subiaco (C)               0  2020        881
 2 Subiaco (C)               5  2020        962
 3 Subiaco (C)              10  2020        903
 4 Subiaco (C)              15  2020        922
 5 Subiaco (C)              20  2020        938
 6 Subiaco (C)              25  2020       1336
 7 Subiaco (C)              30  2020       1444
 8 Subiaco (C)              35  2020       1191
 9 Subiaco (C)              40  2020       1187
10 Subiaco (C)              45  2020       1101
11 Subiaco (C)              50  2020       1044
12 Subiaco (C)              55  2020       1049
13 Subiaco (C)              60  2020       1074
14 Subiaco (C)              65  2020        904
15 Subiaco (C)              70  2020        923
16 Subiaco (C)              75  2020        658
17 Subiaco (C)              80  2020        487
18 Subiaco (C)              85  2020        444

Extrapolate to a new population

synthetic_subiaco <- extrapolate_polymod(
 population = subiaco,
 age_breaks = c(seq(0, 80, by = 5), Inf)
)
synthetic_subiaco

Contact matrix: Subiaco home

autoplot(synthetic_subiaco$home)

Contact matrix: Subiaco work

autoplot(synthetic_subiaco$work)

Contact matrix: Subiaco all

autoplot(synthetic_subiaco)

Comment: Software vs code

  • It is great Prem et al provide estimates, and code

  • Code describes how you did something

  • Software is designed for reuse

  • Github Issues are very useful

  • Extra contributions can be implemented as pull requests which can be tested with GH actions

Why should I use conmat? It’s easy!

world_data <- socialmixr::wpp_age()
population <- age_population(
    data = world_data,
    location_col = country,
    location = "Australia",
    age_col = lower.age.limit,
    year_col = year,
    year = 2015
)

population
# A tibble: 21 × 5 (conmat_population)
 - age: lower.age.limit
 - population: population
   country    year population lower.age.limit upper.age.limit
   <chr>     <int>      <dbl>           <dbl>           <dbl>
 1 Australia  2015    1545114               0               4
 2 Australia  2015    1521110               5               9
 3 Australia  2015    1416482              10              14
 4 Australia  2015    1480341              15              19
 5 Australia  2015    1663584              20              24
 6 Australia  2015    1763281              25              29
 7 Australia  2015    1753076              30              34
 8 Australia  2015    1574157              35              39
 9 Australia  2015    1655520              40              44
10 Australia  2015    1559506              45              49
# ℹ 11 more rows

Why should I use conmat?

Getting a contact matrix is easy:

contact_rates <- extrapolate_polymod(
    population = population,
    age_breaks = c(seq(0, 100, by = 5), Inf)
)

Why should I use conmat?

contact_rates$home
                 [0,5)       [5,10)      [10,15)      [15,20)      [20,25)
[0,5)     5.802591e-01 4.813549e-01 2.402471e-01 1.620169e-01 2.321232e-01
[5,10)    4.646578e-01 7.514361e-01 4.946728e-01 1.791579e-01 1.174632e-01
[10,15)   2.269854e-01 4.841612e-01 7.948923e-01 4.093514e-01 1.390883e-01
[15,20)   1.577753e-01 1.807368e-01 4.219247e-01 6.808458e-01 3.419038e-01
[20,25)   2.432882e-01 1.275370e-01 1.542955e-01 3.679832e-01 5.807800e-01
[25,30)   4.886107e-01 2.352219e-01 1.226892e-01 1.477810e-01 3.335959e-01
[30,35)   6.641648e-01 5.188639e-01 2.431926e-01 1.258683e-01 1.448990e-01
[35,40)   4.878934e-01 6.644817e-01 4.999019e-01 2.317582e-01 1.165367e-01
[40,45)   2.582931e-01 4.382340e-01 5.778488e-01 4.314489e-01 1.936253e-01
[45,50)   1.687273e-01 2.152100e-01 3.566710e-01 4.708383e-01 3.386774e-01
[50,55)   1.689770e-01 1.393551e-01 1.740598e-01 2.883215e-01 3.645253e-01
[55,60)   1.852236e-01 1.352834e-01 1.089212e-01 1.338642e-01 2.115404e-01
[60,65)   1.559059e-01 1.373831e-01 9.632628e-02 7.402672e-02 8.744629e-02
[65,70)   9.671786e-02 1.081266e-01 8.924898e-02 5.758573e-02 4.288228e-02
[70,75)   5.304213e-02 6.517089e-02 6.630047e-02 4.931502e-02 3.157968e-02
[75,80)   3.063155e-02 3.655708e-02 3.961536e-02 3.605985e-02 2.759811e-02
[80,85)   1.701003e-02 2.046395e-02 2.097059e-02 2.037989e-02 1.984339e-02
[85,90)   6.793228e-03 9.262530e-03 9.350083e-03 8.704453e-03 9.446582e-03
[90,95)   1.485635e-03 2.547974e-03 2.852779e-03 2.654936e-03 2.853791e-03
[95,100)  1.550040e-04 3.807001e-04 5.280096e-04 5.572703e-04 6.106408e-04
[100,Inf) 4.001678e-06 1.569944e-05 2.851021e-05 3.613939e-05 4.352133e-05
               [25,30)      [30,35)      [35,40)      [40,45)      [45,50)
[0,5)     4.406440e-01 5.982784e-01 4.552888e-01 2.465532e-01 1.640271e-01
[5,10)    2.047720e-01 4.511788e-01 5.985671e-01 4.038050e-01 2.019578e-01
[10,15)   1.045372e-01 2.069748e-01 4.407441e-01 5.211368e-01 3.275955e-01
[15,20)   1.297843e-01 1.104135e-01 2.106083e-01 4.010565e-01 4.457390e-01
[20,25)   3.153175e-01 1.368029e-01 1.139796e-01 1.937146e-01 3.450794e-01
[25,30)   5.243732e-01 3.144551e-01 1.356807e-01 1.013971e-01 1.623030e-01
[30,35)   3.148155e-01 4.980613e-01 2.954307e-01 1.163616e-01 8.325675e-02
[35,40)   1.311236e-01 2.851813e-01 4.517921e-01 2.542122e-01 9.813646e-02
[40,45)   9.579716e-02 1.098093e-01 2.485196e-01 4.075377e-01 2.345534e-01
[45,50)   1.505639e-01 7.714654e-02 9.420239e-02 2.303081e-01 4.062297e-01
[50,55)   2.628503e-01 1.238732e-01 6.901509e-02 9.188973e-02 2.408397e-01
[55,60)   2.718109e-01 2.122671e-01 1.101458e-01 6.639312e-02 9.279330e-02
[60,65)   1.446095e-01 2.063714e-01 1.771966e-01 9.622107e-02 5.879160e-02
[65,70)   5.498418e-02 1.035664e-01 1.608957e-01 1.394100e-01 7.437032e-02
[70,75)   2.651484e-02 3.913120e-02 7.821431e-02 1.191438e-01 1.011711e-01
[75,80)   2.059216e-02 1.972887e-02 2.968419e-02 5.702188e-02 8.691144e-02
[80,85)   1.798484e-02 1.488353e-02 1.402809e-02 2.034797e-02 4.046827e-02
[85,90)   1.090387e-02 1.044056e-02 8.227622e-03 7.649566e-03 1.201023e-02
[90,95)   3.633180e-03 4.228353e-03 3.796308e-03 3.023101e-03 3.099944e-03
[95,100)  7.478837e-04 9.265512e-04 1.031428e-03 9.725087e-04 8.415508e-04
[100,Inf) 5.166363e-05 6.101144e-05 7.499761e-05 8.726638e-05 8.258968e-05
               [50,55)      [55,60)      [60,65)      [65,70)      [70,75)
[0,5)     1.687022e-01 1.961683e-01 0.1832025702 0.1331132999 0.0918863354
[5,10)    1.343025e-01 1.383072e-01 0.1558369131 0.1436531774 0.1089811502
[10,15)   1.641843e-01 1.089894e-01 0.1069433218 0.1160533779 0.1085141367
[15,20)   2.803165e-01 1.380623e-01 0.0847102640 0.0771805911 0.0831931640
[20,25)   3.814376e-01 2.348162e-01 0.1076993145 0.0618578959 0.0573376911
[25,30)   2.909892e-01 3.192085e-01 0.1884261254 0.0839126928 0.0509323900
[30,35)   1.372914e-01 2.495673e-01 0.2692099753 0.1582363271 0.0752533160
[35,40)   7.383723e-02 1.250082e-01 0.2231323234 0.2372997628 0.1451958462
[40,45)   9.610865e-02 7.366441e-02 0.1184517518 0.2010068440 0.2162238279
[45,50)   2.473381e-01 1.010924e-01 0.0710647072 0.1052892436 0.1802835840
[50,55)   4.428859e-01 2.631261e-01 0.0980390321 0.0637188708 0.0974964688
[55,60)   2.480418e-01 4.500001e-01 0.2527757109 0.0905781696 0.0621663591
[60,65)   8.329582e-02 2.278236e-01 0.4239011662 0.2392786574 0.0895750648
[65,70)   4.622177e-02 6.970135e-02 0.2042952564 0.3920370894 0.2228202559
[70,75)   5.618912e-02 3.800650e-02 0.0607611916 0.1770269961 0.3268365761
[75,80)   7.927543e-02 4.788099e-02 0.0330311910 0.0500190560 0.1358156077
[80,85)   6.696845e-02 6.405183e-02 0.0377136045 0.0242834312 0.0344473988
[85,90)   2.589055e-02 4.275948e-02 0.0381342648 0.0207240237 0.0126427866
[90,95)   5.199957e-03 1.089333e-02 0.0165873700 0.0135501574 0.0068514835
[95,100)  8.791712e-04 1.406558e-03 0.0027504099 0.0038776570 0.0029390575
[100,Inf) 6.969596e-05 7.464274e-05 0.0001226298 0.0002243481 0.0002723907
               [75,80)      [80,85)      [85,90)      [90,95)     [95,100)
[0,5)     0.0695641984 0.0532109912 3.471403e-02 1.729263e-02 0.0058435830
[5,10)    0.0801412678 0.0617950322 4.569054e-02 2.862937e-02 0.0138543803
[10,15)   0.0850002537 0.0619793297 4.514235e-02 3.137307e-02 0.0188069300
[15,20)   0.0797478903 0.0620835720 4.331605e-02 3.009411e-02 0.0204588230
[20,25)   0.0656899136 0.0650600964 5.059482e-02 3.481559e-02 0.0241281820
[25,30)   0.0518553897 0.0623847088 6.178521e-02 4.689333e-02 0.0312640673
[30,35)   0.0497383729 0.0516862432 5.922775e-02 5.463775e-02 0.0387773632
[35,40)   0.0722403975 0.0470254386 4.505482e-02 4.735311e-02 0.0416690143
[40,45)   0.1356627465 0.0666837054 4.095132e-02 3.686412e-02 0.0384089094
[45,50)   0.2030314881 0.1302208821 6.313202e-02 3.711697e-02 0.0326351958
[50,55)   0.1803275843 0.2098327714 1.325186e-01 6.062553e-02 0.0331983468
[55,60)   0.1026709549 0.1891888359 2.063141e-01 1.197230e-01 0.0500681572
[60,65)   0.0638369340 0.1003980607 1.658346e-01 1.643075e-01 0.0882398189
[65,70)   0.0825348941 0.0551939725 7.694638e-02 1.145984e-01 0.1062162347
[70,75)   0.1780478029 0.0622046521 3.729424e-02 4.603665e-02 0.0639608777
[75,80)   0.2379470305 0.1226411587 3.901666e-02 2.061227e-02 0.0235174032
[80,85)   0.0890341775 0.1467765207 6.996593e-02 2.039686e-02 0.0100720633
[85,90)   0.0173395593 0.0428305924 6.727551e-02 3.055193e-02 0.0085097343
[90,95)   0.0040215520 0.0054816419 1.341277e-02 2.108756e-02 0.0091691088
[95,100)  0.0014166741 0.0008357541 1.153476e-03 2.831000e-03 0.0045419826
[100,Inf) 0.0001757175 0.0000815589 5.608818e-05 9.113023e-05 0.0002356887
             [100,Inf)
[0,5)     0.0015969450
[5,10)    0.0060478325
[10,15)   0.0107494942
[15,20)   0.0140445284
[20,25)   0.0182033974
[25,30)   0.0228616687
[30,35)   0.0270291084
[35,40)   0.0320725374
[40,45)   0.0364835436
[45,50)   0.0339033995
[50,55)   0.0278587842
[55,60)   0.0281256815
[60,65)   0.0416461592
[65,70)   0.0650512285
[70,75)   0.0627494825
[75,80)   0.0308777682
[80,85)   0.0104045396
[85,90)   0.0043801633
[90,95)   0.0031243614
[95,100)  0.0024948840
[100,Inf) 0.0003784101

Why should I use conmat? You can use a custom population

flat_population_data <- tibble(
    country = "flatland",
    year = 2024,
    population = 1000,
    lower.age.limit = seq(0, 75, by=5)
)

flat_population <- age_population(
    data = flat_population_data,
    location_col = country,
    location = "flatland",
    age_col = lower.age.limit,
    year_col = year,
    year = 2024
)

flat_contact_rates <- extrapolate_polymod(
    population = flat_population,
    age_breaks = c(seq(0, 75, by=5), Inf)
)

Why should I use conmat? You can use a custom population

flat_contact_rates$home
              [0,5)     [5,10)    [10,15)    [15,20)    [20,25)    [25,30)
[0,5)    0.56828986 0.47107930 0.23528412 0.15828319 0.22562515 0.42964988
[5,10)   0.47107930 0.76196823 0.50231004 0.18255328 0.11883529 0.20659277
[10,15)  0.23528412 0.50231004 0.82299109 0.42595334 0.14470685 0.10812909
[15,20)  0.15828319 0.18255328 0.42595334 0.68440444 0.34414245 0.13015930
[20,25)  0.22562515 0.11883529 0.14470685 0.34414245 0.54276791 0.29342160
[25,30)  0.42964988 0.20659277 0.10812909 0.13015930 0.29342160 0.46253966
[30,35)  0.58525292 0.45701473 0.21462152 0.11113527 0.12706493 0.27630913
[35,40)  0.44529458 0.60639263 0.45689173 0.21281962 0.10667273 0.11928571
[40,45)  0.24127232 0.40933635 0.53934055 0.40417570 0.18192135 0.08953615
[45,50)  0.16037541 0.20465635 0.33875107 0.44747109 0.32351471 0.14362854
[50,55)  0.16492113 0.13600777 0.16964705 0.28029573 0.35573859 0.25736993
[55,60)  0.19180402 0.14014100 0.11268901 0.13779345 0.21749363 0.28104124
[60,65)  0.17876427 0.15784117 0.11080587 0.08487633 0.09950725 0.16466518
[65,70)  0.12947242 0.14506103 0.12018401 0.07774984 0.05748962 0.07309408
[70,75)  0.08932050 0.10972788 0.11192484 0.08381432 0.05375817 0.04473290
[75,Inf) 0.05512666 0.06576018 0.07106603 0.06492533 0.05030197 0.03782410
            [30,35)    [35,40)    [40,45)    [45,50)    [50,55)    [55,60)
[0,5)    0.58525292 0.44529458 0.24127232 0.16037541 0.16492113 0.19180402
[5,10)   0.45701473 0.60639263 0.40933635 0.20465635 0.13600777 0.14014100
[10,15)  0.21462152 0.45689173 0.53934055 0.33875107 0.16964705 0.11268901
[15,20)  0.11113527 0.21281962 0.40417570 0.44747109 0.28029573 0.13779345
[20,25)  0.12706493 0.10667273 0.18192135 0.32351471 0.35573859 0.21749363
[25,30)  0.27630913 0.11928571 0.08953615 0.14362854 0.25736993 0.28104124
[30,35)  0.43869100 0.26005794 0.10254775 0.07332365 0.12101602 0.22021310
[35,40)  0.26005794 0.41225918 0.23226955 0.08961730 0.06739027 0.11438638
[40,45)  0.10254775 0.23226955 0.38043054 0.21889793 0.08962625 0.06884477
[45,50)  0.07332365 0.08961730 0.21889793 0.38628120 0.23490447 0.09578732
[50,55)  0.12101602 0.06739027 0.08962625 0.23490447 0.43255518 0.25611626
[55,60)  0.22021310 0.11438638 0.06884477 0.09578732 0.25611626 0.46618257
[60,65)  0.23655846 0.20418776 0.11121066 0.06761476 0.09516248 0.26086699
[65,70)  0.13798606 0.21578768 0.18859484 0.10093986 0.06227115 0.09317464
[70,75)  0.06552314 0.13088028 0.20091654 0.17270637 0.09635242 0.06459090
[75,Inf) 0.03588289 0.05306184 0.10103208 0.15531574 0.14574253 0.09020024
            [60,65)    [65,70)    [70,75)   [75,Inf)
[0,5)    0.17876427 0.12947242 0.08932050 0.06737703
[5,10)   0.15784117 0.14506103 0.10972788 0.08037355
[10,15)  0.11080587 0.12018401 0.11192484 0.08685848
[15,20)  0.08487633 0.07774984 0.08381432 0.07935318
[20,25)  0.09950725 0.05748962 0.05375817 0.06148018
[25,30)  0.16466518 0.07309408 0.04473290 0.04622945
[30,35)  0.23655846 0.13798606 0.06552314 0.04385687
[35,40)  0.20418776 0.21578768 0.13088028 0.06485336
[40,45)  0.11121066 0.18859484 0.20091654 0.12348365
[45,50)  0.06761476 0.10093986 0.17270637 0.18983035
[50,55)  0.09516248 0.06227115 0.09635242 0.17812976
[55,60)  0.26086699 0.09317464 0.06459090 0.11024474
[60,65)  0.48737980 0.27379182 0.10227898 0.07483573
[65,70)  0.27379182 0.52813388 0.29877425 0.11049744
[70,75)  0.10227898 0.29877425 0.55330597 0.29782838
[75,Inf) 0.06122924 0.09040699 0.24367777 0.41218989

Future Directions

  • Pre compute new matrices for countries/regions syncomat by Chitra Saraswati
  • Implement other social contact diaries beyond POLYMOD
  • Allow for using sub-yearly age groups
  • Validating against Prem and other methods
  • Interface to changing GAM model terms or specify model

Conclusion

  • Contact matrices are frequently used in infectious diseases modelling

  • Standard Prem et. al matrices are not written for re-use

  • conmat provides an interface to easily generate and update models from any data source

  • Can integrate vaccination, calculate next generation matrices, and a handful of other features

  • It’s available right now: github.com/idem-lab/conmat

Thanks

  • Nick Golding
  • Aarathy Babu
  • Michael Lydeamore
  • Chitra Saraswati

Learning more

github.com/idem-lab/conmat

njtierney.github.io/conmat-tki-2024

njtierney.com

njtierney@aus.social

njtierney

nicholas.tierney@gmail.com

End.

Extras

How does the model work?

fit_single_contact_model <- function(contact_data, population) {

  # programatically add the offset term to the formula, so the model defines
  # information about the setting, without us having to pass it through to the
  # prediction data
  formula_no_offset <- contacts ~
    # deviation of contact age distribution from population age distribution
    s(age_to) +
    # number of contacts by age
    s(age_from) +
    # intergenerational contact patterns - enables the off-diagonals
    s(abs(age_from - age_to)) +
    # interaction between intergenerational patterns and age_from, to remove
    # ridge for some ages and settings
    s(abs(age_from - age_to), age_from) +
    # probabilities of both attending (any) school/work
    school_probability +
    work_probability
  
  # choose the offset variable based on the setting
  setting <- contact_data$setting[1]
  offset_variable <- switch(
    setting,
    school = "log_contactable_population_school",
    "log_contactable_population"
  )
  
  # add multiplicative offset for population contactable, to enable
  # extrapolation to new demographies
  # in mgcv, this part of the offset gets used in prediction, which 
  # is what we want. Those are the "contactable" parts, which we use
  # to extrapolate to new demographics.
  formula_offset <- sprintf("~. + offset(%s)", offset_variable)
  formula <- update(formula_no_offset, formula_offset)
  
  # contact model for all locations together
  contact_data %>%
    add_modelling_features() %>%
      # The modelling features added here are:
        # the school and work offsets
        # pop_age_to (interpolated population)
        # `log_contactable_population_school`, and ` log_contactable_population`
      population = population
    mgcv::bam(
      formula = formula,
      family = stats::poisson,
      # add number of participants as a multilpicative offset here rather than in
      # the formula, so it is not needed for prediction,
      # NOTE: the offset of participants allows us to get the rate per person
      offset = log(participants),
      data = .
    )
  
}

Alt approach to conmat model

# fit a model
library(conmat)
subiaco_age_pop <- abs_age_lga("Subiaco (C)")
subiaco_age_pop
# A tibble: 18 × 4 (conmat_population)
 - age: lower.age.limit
 - population: population
   lga         lower.age.limit  year population
   <chr>                 <dbl> <dbl>      <dbl>
 1 Subiaco (C)               0  2020        881
 2 Subiaco (C)               5  2020        962
 3 Subiaco (C)              10  2020        903
 4 Subiaco (C)              15  2020        922
 5 Subiaco (C)              20  2020        938
 6 Subiaco (C)              25  2020       1336
 7 Subiaco (C)              30  2020       1444
 8 Subiaco (C)              35  2020       1191
 9 Subiaco (C)              40  2020       1187
10 Subiaco (C)              45  2020       1101
11 Subiaco (C)              50  2020       1044
12 Subiaco (C)              55  2020       1049
13 Subiaco (C)              60  2020       1074
14 Subiaco (C)              65  2020        904
15 Subiaco (C)              70  2020        923
16 Subiaco (C)              75  2020        658
17 Subiaco (C)              80  2020        487
18 Subiaco (C)              85  2020        444

Alt approach to conmat model

polymod_contact_data <- get_polymod_setting_data()
polymod_survey_data <- get_polymod_population()

Alt approach to conmat model

setting_models <- fit_setting_contacts(
  contact_data_list = polymod_contact_data,
  population = polymod_survey_data
  )

str(setting_models)
List of 4
 $ home  :List of 54
  ..$ coefficients     : Named num [1:57] 0.617 -0.347 0.537 -68.875 4.169 ...
  .. ..- attr(*, "names")= chr [1:57] "(Intercept)" "school_probability" "work_probability" "s(gam_age_offdiag).1" ...
  ..$ db.drho          : num [1:55, 1:6] -0.00151 0.00455 0.00278 -0.91056 -0.334 ...
  ..$ gcv.ubre         : Named num 14790
  .. ..- attr(*, "names")= chr "fREML"
  ..$ mgcv.conv        :List of 2
  .. ..$ iter   : int 10
  .. ..$ message: chr "full convergence"
  ..$ rank             : int 55
  ..$ Ve               : num [1:57, 1:57] 0.001244 -0.000312 -0.003213 -0.075219 -0.013809 ...
  ..$ scale.estimated  : logi FALSE
  ..$ outer.info       :List of 4
  .. ..$ conv: chr "full convergence"
  .. ..$ iter: int 10
  .. ..$ grad: num [1:6] 7.09e-08 -1.92e-05 -1.44e-10 -4.01e-10 -1.35e-11 ...
  .. ..$ hess: num [1:6, 1:6] 3.50 3.76e-06 6.54e-03 -2.02e-02 -1.70e-03 ...
  ..$ optimizer        : chr [1:2] "perf" "newton"
  ..$ scale            : num 1
  ..$ sig2             : num 1
  ..$ sp               : Named num [1:6] 1.16e-03 1.03e+03 1.29e-01 2.06e-01 3.56e-02 ...
  .. ..- attr(*, "names")= chr [1:6] "s(gam_age_offdiag)" "s(gam_age_offdiag_2)" "s(gam_age_diag_prod)" "s(gam_age_diag_sum)" ...
  ..$ edf              : Named num [1:57] 1 1 1 0.903 0.976 ...
  .. ..- attr(*, "names")= chr [1:57] "(Intercept)" "school_probability" "work_probability" "s(gam_age_offdiag).1" ...
  ..$ edf1             : num [1:57] 1 1 1 0.989 0.995 ...
  ..$ edf2             : num [1:57] 1 1 1 1.08 0.975 ...
  ..$ hat              : num [1:57] 1 1 1 1 0.999 ...
  ..$ Vp               : num [1:57, 1:57] 0.001437 -0.000329 -0.00384 -0.097236 -0.017076 ...
  ..$ Vc               : num [1:57, 1:57] 0.001587 -0.000156 -0.004901 -0.10023 -0.016791 ...
  ..$ V.sp             : num [1:6, 1:6] 0.285793 -0.055921 0.001153 0.006059 0.000227 ...
  ..$ R                : num [1:57, 1:57] -117.23 72.94 8.84 -78.92 0 ...
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ : NULL
  .. .. ..$ : NULL
  ..$ iter             : int 8
  ..$ wt               : num [1:8787] 6.22 6.52 6.59 6.44 6.12 ...
  ..$ y                : int [1:8787] 10 7 12 14 12 6 8 9 6 6 ...
  ..$ prior.weights    : num [1:8787] 1 1 1 1 1 1 1 1 1 1 ...
  ..$ assign           : int [1:3] 0 1 2
  ..$ boundary         : logi FALSE
  ..$ call             : language mgcv::bam(formula = formula, family = stats::poisson, data = ., offset = log(participants))
  ..$ cmX              : Named num [1:57] 1.00 3.86e-02 1.42e-01 -2.69e-14 -5.18e-15 ...
  .. ..- attr(*, "names")= chr [1:57] "(Intercept)" "school_probability" "work_probability" "" ...
  ..$ control          :List of 19
  .. ..$ nthreads    : num 1
  .. ..$ ncv.threads : num 1
  .. ..$ irls.reg    : num 0
  .. ..$ epsilon     : num 1e-07
  .. ..$ maxit       : num 200
  .. ..$ trace       : logi FALSE
  .. ..$ mgcv.tol    : num 1e-07
  .. ..$ mgcv.half   : num 15
  .. ..$ rank.tol    : num 1.49e-08
  .. ..$ nlm         :List of 6
  .. .. ..$ ndigit           : num 7
  .. .. ..$ gradtol          : num 1e-06
  .. .. ..$ stepmax          : num 2
  .. .. ..$ steptol          : num 1e-04
  .. .. ..$ iterlim          : num 200
  .. .. ..$ check.analyticals: logi FALSE
  .. ..$ optim       :List of 1
  .. .. ..$ factr: num 1e+07
  .. ..$ newton      :List of 5
  .. .. ..$ conv.tol: num 1e-06
  .. .. ..$ maxNstep: num 5
  .. .. ..$ maxSstep: num 2
  .. .. ..$ maxHalf : num 30
  .. .. ..$ use.svd : logi FALSE
  .. ..$ idLinksBases: logi TRUE
  .. ..$ scalePenalty: logi TRUE
  .. ..$ efs.lspmax  : num 15
  .. ..$ efs.tol     : num 0.1
  .. ..$ keepData    : logi FALSE
  .. ..$ scale.est   : chr "fletcher"
  .. ..$ edge.correct: logi FALSE
  ..$ converged        : logi TRUE
  ..$ data             : logi NA
  ..$ df.null          : int 8787
  ..$ df.residual      : num 8753
  ..$ family           :List of 13
  .. ..$ family    : chr "poisson"
  .. ..$ link      : chr "log"
  .. ..$ linkfun   :function (mu)  
  .. ..$ linkinv   :function (eta)  
  .. ..$ variance  :function (mu)  
  .. ..$ dev.resids:function (y, mu, wt)  
  .. ..$ aic       :function (y, n, mu, wt, dev)  
  .. ..$ mu.eta    :function (eta)  
  .. ..$ initialize:  expression({  if (any(y < 0))  stop("negative values not allowed for the 'Poisson' family")  n <- rep.int(1, nobs| __truncated__
  .. ..$ validmu   :function (mu)  
  .. ..$ valideta  :function (eta)  
  .. ..$ simulate  :function (object, nsim)  
  .. ..$ dispersion: num 1
  .. ..- attr(*, "class")= chr "family"
  ..$ formula          :Class 'formula'  language contacts ~ s(gam_age_offdiag) + s(gam_age_offdiag_2) + s(gam_age_diag_prod) +      s(gam_age_diag_sum) + s(gam_ag| __truncated__ ...
  .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
  ..$ method           : chr "fREML"
  ..$ min.edf          : num 9
  ..$ model            :'data.frame':   8787 obs. of  11 variables:
  .. ..$ contacts                          : int [1:8787] 10 7 12 14 12 6 8 9 6 6 ...
  .. ..$ school_probability                : num [1:8787] 0 0 0 0 0 0 0 0 0 0 ...
  .. ..$ work_probability                  : num [1:8787] 0 0 0 0 0 0 0 0 0 0 ...
  .. ..$ offset(log_contactable_population): num [1:8787] -4.67 -4.66 -4.65 -4.63 -4.62 ...
  .. ..$ gam_age_offdiag                   : num [1:8787] 0 1 2 3 4 5 6 7 8 9 ...
  .. ..$ gam_age_offdiag_2                 : num [1:8787] 0 1 4 9 16 25 36 49 64 81 ...
  .. ..$ gam_age_diag_prod                 : num [1:8787] 0 0 0 0 0 0 0 0 0 0 ...
  .. ..$ gam_age_diag_sum                  : num [1:8787] 0 1 2 3 4 5 6 7 8 9 ...
  .. ..$ gam_age_pmax                      : num [1:8787] 0 1 2 3 4 5 6 7 8 9 ...
  .. ..$ gam_age_pmin                      : num [1:8787] 0 0 0 0 0 0 0 0 0 0 ...
  .. ..$ (offset)                          : num [1:8787] 4.52 4.52 4.52 4.52 4.52 ...
  .. ..- attr(*, "terms")=Classes 'terms', 'formula'  language contacts ~ school_probability + work_probability + offset(log_contactable_population) +      gam_age_offdiag + ga| __truncated__ ...
  .. .. .. ..- attr(*, "variables")= language list(contacts, school_probability, work_probability, offset(log_contactable_population),      gam_age_offdiag, ga| __truncated__ ...
  .. .. .. ..- attr(*, "offset")= int 4
  .. .. .. ..- attr(*, "factors")= int [1:10, 1:8] 0 1 0 0 0 0 0 0 0 0 ...
  .. .. .. .. ..- attr(*, "dimnames")=List of 2
  .. .. .. .. .. ..$ : chr [1:10] "contacts" "school_probability" "work_probability" "offset(log_contactable_population)" ...
  .. .. .. .. .. ..$ : chr [1:8] "school_probability" "work_probability" "gam_age_offdiag" "gam_age_offdiag_2" ...
  .. .. .. ..- attr(*, "term.labels")= chr [1:8] "school_probability" "work_probability" "gam_age_offdiag" "gam_age_offdiag_2" ...
  .. .. .. ..- attr(*, "order")= int [1:8] 1 1 1 1 1 1 1 1
  .. .. .. ..- attr(*, "intercept")= int 1
  .. .. .. ..- attr(*, "response")= int 1
  .. .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
  .. .. .. ..- attr(*, "predvars")= language list(contacts, school_probability, work_probability, offset(log_contactable_population),      gam_age_offdiag, ga| __truncated__ ...
  .. .. .. ..- attr(*, "dataClasses")= Named chr [1:11] "numeric" "numeric" "numeric" "numeric" ...
  .. .. .. .. ..- attr(*, "names")= chr [1:11] "contacts" "school_probability" "work_probability" "offset(log_contactable_population)" ...
  ..$ nsdf             : int 3
  ..$ offset           : num [1:8787] -0.1527 -0.1387 -0.1246 -0.1105 -0.0964 ...
  ..$ pterms           :Classes 'terms', 'formula'  language contacts ~ school_probability + work_probability + offset(log_contactable_population)
  .. .. ..- attr(*, "variables")= language list(contacts, school_probability, work_probability, offset(log_contactable_population))
  .. .. ..- attr(*, "offset")= int 4
  .. .. ..- attr(*, "factors")= int [1:4, 1:2] 0 1 0 0 0 0 1 0
  .. .. .. ..- attr(*, "dimnames")=List of 2
  .. .. .. .. ..$ : chr [1:4] "contacts" "school_probability" "work_probability" "offset(log_contactable_population)"
  .. .. .. .. ..$ : chr [1:2] "school_probability" "work_probability"
  .. .. ..- attr(*, "term.labels")= chr [1:2] "school_probability" "work_probability"
  .. .. ..- attr(*, "order")= int [1:2] 1 1
  .. .. ..- attr(*, "intercept")= int 1
  .. .. ..- attr(*, "response")= int 1
  .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
  .. .. ..- attr(*, "predvars")= language list(contacts, school_probability, work_probability, offset(log_contactable_population))
  .. .. ..- attr(*, "dataClasses")= Named chr [1:5] "numeric" "numeric" "numeric" "numeric" ...
  .. .. .. ..- attr(*, "names")= chr [1:5] "contacts" "school_probability" "work_probability" "offset(log_contactable_population)" ...
  ..$ pred.formula     :Class 'formula'  language ~school_probability + work_probability + log_contactable_population + gam_age_offdiag +      gam_age_offdiag_2 + | __truncated__ ...
  .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
  ..$ smooth           :List of 6
  .. ..$ :List of 29
  .. .. ..$ term          : chr "gam_age_offdiag"
  .. .. ..$ bs.dim        : num 10
  .. .. ..$ fixed         : logi FALSE
  .. .. ..$ dim           : int 1
  .. .. ..$ p.order       : num 0
  .. .. ..$ by            : chr "NA"
  .. .. ..$ label         : chr "s(gam_age_offdiag)"
  .. .. ..$ xt            : NULL
  .. .. ..$ id            : NULL
  .. .. ..$ sp            : Named num -1
  .. .. .. ..- attr(*, "names")= chr "s(gam_age_offdiag)"
  .. .. ..$ drop.null     : num 0
  .. .. ..$ S             :List of 1
  .. .. .. ..$ : num [1:9, 1:9] 2.558 -0.769 4.813 -1.005 4.801 ...
  .. .. ..$ UZ            : num [1:103, 1:10] -3.97e-06 -3.66e-06 -3.37e-06 -3.09e-06 -2.83e-06 ...
  .. .. ..$ Xu            : num [1:101, 1] -32 -31 -30 -29 -28 ...
  .. .. ..$ df            : num 9
  .. .. ..$ shift         : num [1(1d)] 32
  .. .. ..$ rank          : num 8
  .. .. ..$ null.space.dim: num 1
  .. .. ..$ plot.me       : logi TRUE
  .. .. ..$ side.constrain: logi TRUE
  .. .. ..$ repara        : logi TRUE
  .. .. ..$ C             : num 0
  .. .. ..$ S.scale       : num 2.27e-05
  .. .. ..$ Cp            : num 0
  .. .. ..$ vn            : chr "gam_age_offdiag"
  .. .. ..$ first.para    : num 4
  .. .. ..$ last.para     : num 12
  .. .. ..$ first.sp      : num 1
  .. .. ..$ last.sp       : num 1
  .. .. ..- attr(*, "class")= chr [1:2] "tprs.smooth" "mgcv.smooth"
  .. .. ..- attr(*, "qrc")= 'sweepDrop' num [1:10] 9 -0.938 -0.423 -0.743 -0.413 ...
  .. .. ..- attr(*, "nCons")= num 1
  .. ..$ :List of 29
  .. .. ..$ term          : chr "gam_age_offdiag_2"
  .. .. ..$ bs.dim        : num 10
  .. .. ..$ fixed         : logi FALSE
  .. .. ..$ dim           : int 1
  .. .. ..$ p.order       : num 0
  .. .. ..$ by            : chr "NA"
  .. .. ..$ label         : chr "s(gam_age_offdiag_2)"
  .. .. ..$ xt            : NULL
  .. .. ..$ id            : NULL
  .. .. ..$ sp            : Named num -1
  .. .. .. ..- attr(*, "names")= chr "s(gam_age_offdiag_2)"
  .. .. ..$ drop.null     : num 0
  .. .. ..$ S             :List of 1
  .. .. .. ..$ : num [1:9, 1:9] 1.75 -1.68 -3.12 -2.03 3.03 ...
  .. .. ..$ UZ            : num [1:103, 1:10] 1.54e-12 1.54e-12 1.54e-12 1.53e-12 1.51e-12 ...
  .. .. ..$ Xu            : num [1:101, 1] -1533 -1532 -1529 -1524 -1517 ...
  .. .. ..$ df            : num 9
  .. .. ..$ shift         : num [1(1d)] 1533
  .. .. ..$ rank          : num 8
  .. .. ..$ null.space.dim: num 1
  .. .. ..$ plot.me       : logi TRUE
  .. .. ..$ side.constrain: logi TRUE
  .. .. ..$ repara        : logi TRUE
  .. .. ..$ C             : num 0
  .. .. ..$ S.scale       : num 2.23e-11
  .. .. ..$ Cp            : num 0
  .. .. ..$ vn            : chr "gam_age_offdiag_2"
  .. .. ..$ first.para    : num 13
  .. .. ..$ last.para     : num 21
  .. .. ..$ first.sp      : num 2
  .. .. ..$ last.sp       : num 2
  .. .. ..- attr(*, "class")= chr [1:2] "tprs.smooth" "mgcv.smooth"
  .. .. ..- attr(*, "qrc")= 'sweepDrop' num [1:10] 9 0.961 0.691 -0.87 0.676 ...
  .. .. ..- attr(*, "nCons")= num 1
  .. ..$ :List of 29
  .. .. ..$ term          : chr "gam_age_diag_prod"
  .. .. ..$ bs.dim        : num 10
  .. .. ..$ fixed         : logi FALSE
  .. .. ..$ dim           : int 1
  .. .. ..$ p.order       : num 0
  .. .. ..$ by            : chr "NA"
  .. .. ..$ label         : chr "s(gam_age_diag_prod)"
  .. .. ..$ xt            : NULL
  .. .. ..$ id            : NULL
  .. .. ..$ sp            : Named num -1
  .. .. .. ..- attr(*, "names")= chr "s(gam_age_diag_prod)"
  .. .. ..$ drop.null     : num 0
  .. .. ..$ S             :List of 1
  .. .. .. ..$ : num [1:9, 1:9] 4.08 3.48 -8.2 -5.06 -7.78 ...
  .. .. ..$ UZ            : num [1:2002, 1:10] -2.38e-13 -2.37e-13 -2.37e-13 -2.36e-13 -2.36e-13 ...
  .. .. ..$ Xu            : num [1:2000, 1] -2152 -2150 -2149 -2146 -2145 ...
  .. .. ..$ df            : num 9
  .. .. ..$ shift         : num [1(1d)] 2152
  .. .. ..$ rank          : num 8
  .. .. ..$ null.space.dim: num 1
  .. .. ..$ plot.me       : logi TRUE
  .. .. ..$ side.constrain: logi TRUE
  .. .. ..$ repara        : logi TRUE
  .. .. ..$ C             : num 0
  .. .. ..$ S.scale       : num 2.26e-11
  .. .. ..$ Cp            : num 0
  .. .. ..$ vn            : chr "gam_age_diag_prod"
  .. .. ..$ first.para    : num 22
  .. .. ..$ last.para     : num 30
  .. .. ..$ first.sp      : num 3
  .. .. ..$ last.sp       : num 3
  .. .. ..- attr(*, "class")= chr [1:2] "tprs.smooth" "mgcv.smooth"
  .. .. ..- attr(*, "qrc")= 'sweepDrop' num [1:10] 9 -0.947 0.262 0.763 -0.162 ...
  .. .. ..- attr(*, "nCons")= num 1
  .. ..$ :List of 29
  .. .. ..$ term          : chr "gam_age_diag_sum"
  .. .. ..$ bs.dim        : num 10
  .. .. ..$ fixed         : logi FALSE
  .. .. ..$ dim           : int 1
  .. .. ..$ p.order       : num 0
  .. .. ..$ by            : chr "NA"
  .. .. ..$ label         : chr "s(gam_age_diag_sum)"
  .. .. ..$ xt            : NULL
  .. .. ..$ id            : NULL
  .. .. ..$ sp            : Named num -1
  .. .. .. ..- attr(*, "names")= chr "s(gam_age_diag_sum)"
  .. .. ..$ drop.null     : num 0
  .. .. ..$ S             :List of 1
  .. .. .. ..$ : num [1:9, 1:9] 4.97 1.09 11.11 -1.66 -11.93 ...
  .. .. ..$ UZ            : num [1:193, 1:10] 4.62e-07 4.42e-07 4.23e-07 4.04e-07 3.85e-07 ...
  .. .. ..$ Xu            : num [1:191, 1] -93 -92 -91 -90 -89 ...
  .. .. ..$ df            : num 9
  .. .. ..$ shift         : num [1(1d)] 93
  .. .. ..$ rank          : num 8
  .. .. ..$ null.space.dim: num 1
  .. .. ..$ plot.me       : logi TRUE
  .. .. ..$ side.constrain: logi TRUE
  .. .. ..$ repara        : logi TRUE
  .. .. ..$ C             : num 0
  .. .. ..$ S.scale       : num 2.88e-06
  .. .. ..$ Cp            : num 0
  .. .. ..$ vn            : chr "gam_age_diag_sum"
  .. .. ..$ first.para    : num 31
  .. .. ..$ last.para     : num 39
  .. .. ..$ first.sp      : num 4
  .. .. ..$ last.sp       : num 4
  .. .. ..- attr(*, "class")= chr [1:2] "tprs.smooth" "mgcv.smooth"
  .. .. ..- attr(*, "qrc")= 'sweepDrop' num [1:10] 9 0.951 0.292 0.558 -0.351 ...
  .. .. ..- attr(*, "nCons")= num 1
  .. ..$ :List of 29
  .. .. ..$ term          : chr "gam_age_pmax"
  .. .. ..$ bs.dim        : num 10
  .. .. ..$ fixed         : logi FALSE
  .. .. ..$ dim           : int 1
  .. .. ..$ p.order       : num 0
  .. .. ..$ by            : chr "NA"
  .. .. ..$ label         : chr "s(gam_age_pmax)"
  .. .. ..$ xt            : NULL
  .. .. ..$ id            : NULL
  .. .. ..$ sp            : Named num -1
  .. .. .. ..- attr(*, "names")= chr "s(gam_age_pmax)"
  .. .. ..$ drop.null     : num 0
  .. .. ..$ S             :List of 1
  .. .. .. ..$ : num [1:9, 1:9] 4.151 -0.822 7.91 -1.089 8.153 ...
  .. .. ..$ UZ            : num [1:103, 1:10] -4.38e-06 -4.04e-06 -3.72e-06 -3.41e-06 -3.12e-06 ...
  .. .. ..$ Xu            : num [1:101, 1] -62.5 -61.5 -60.5 -59.5 -58.5 ...
  .. .. ..$ df            : num 9
  .. .. ..$ shift         : num [1(1d)] 62.5
  .. .. ..$ rank          : num 8
  .. .. ..$ null.space.dim: num 1
  .. .. ..$ plot.me       : logi TRUE
  .. .. ..$ side.constrain: logi TRUE
  .. .. ..$ repara        : logi TRUE
  .. .. ..$ C             : num 0
  .. .. ..$ S.scale       : num 1.7e-05
  .. .. ..$ Cp            : num 0
  .. .. ..$ vn            : chr "gam_age_pmax"
  .. .. ..$ first.para    : num 40
  .. .. ..$ last.para     : num 48
  .. .. ..$ first.sp      : num 5
  .. .. ..$ last.sp       : num 5
  .. .. ..- attr(*, "class")= chr [1:2] "tprs.smooth" "mgcv.smooth"
  .. .. ..- attr(*, "qrc")= 'sweepDrop' num [1:10] 9 -0.943 0.625 -0.705 0.621 ...
  .. .. ..- attr(*, "nCons")= num 1
  .. ..$ :List of 29
  .. .. ..$ term          : chr "gam_age_pmin"
  .. .. ..$ bs.dim        : num 10
  .. .. ..$ fixed         : logi FALSE
  .. .. ..$ dim           : int 1
  .. .. ..$ p.order       : num 0
  .. .. ..$ by            : chr "NA"
  .. .. ..$ label         : chr "s(gam_age_pmin)"
  .. .. ..$ xt            : NULL
  .. .. ..$ id            : NULL
  .. .. ..$ sp            : Named num -1
  .. .. .. ..- attr(*, "names")= chr "s(gam_age_pmin)"
  .. .. ..$ drop.null     : num 0
  .. .. ..$ S             :List of 1
  .. .. .. ..$ : num [1:9, 1:9] 3.642 0.732 6.581 -0.913 6.554 ...
  .. .. ..$ UZ            : num [1:93, 1:10] -6.87e-06 -6.26e-06 -5.67e-06 -5.11e-06 -4.59e-06 ...
  .. .. ..$ Xu            : num [1:91, 1] -30.5 -29.5 -28.5 -27.5 -26.5 ...
  .. .. ..$ df            : num 9
  .. .. ..$ shift         : num [1(1d)] 30.5
  .. .. ..$ rank          : num 8
  .. .. ..$ null.space.dim: num 1
  .. .. ..$ plot.me       : logi TRUE
  .. .. ..$ side.constrain: logi TRUE
  .. .. ..$ repara        : logi TRUE
  .. .. ..$ C             : num 0
  .. .. ..$ S.scale       : num 2.24e-05
  .. .. ..$ Cp            : num 0
  .. .. ..$ vn            : chr "gam_age_pmin"
  .. .. ..$ first.para    : num 49
  .. .. ..$ last.para     : num 57
  .. .. ..$ first.sp      : num 6
  .. .. ..$ last.sp       : num 6
  .. .. ..- attr(*, "class")= chr [1:2] "tprs.smooth" "mgcv.smooth"
  .. .. ..- attr(*, "qrc")= 'sweepDrop' num [1:10] 9 -0.939 -0.671 -0.745 0.669 ...
  .. .. ..- attr(*, "nCons")= num 1
  ..$ terms            :Classes 'terms', 'formula'  language contacts ~ school_probability + work_probability + offset(log_contactable_population) +      gam_age_offdiag + ga| __truncated__ ...
  .. .. ..- attr(*, "variables")= language list(contacts, school_probability, work_probability, offset(log_contactable_population),      gam_age_offdiag, ga| __truncated__ ...
  .. .. ..- attr(*, "offset")= int 4
  .. .. ..- attr(*, "factors")= int [1:10, 1:8] 0 1 0 0 0 0 0 0 0 0 ...
  .. .. .. ..- attr(*, "dimnames")=List of 2
  .. .. .. .. ..$ : chr [1:10] "contacts" "school_probability" "work_probability" "offset(log_contactable_population)" ...
  .. .. .. .. ..$ : chr [1:8] "school_probability" "work_probability" "gam_age_offdiag" "gam_age_offdiag_2" ...
  .. .. ..- attr(*, "term.labels")= chr [1:8] "school_probability" "work_probability" "gam_age_offdiag" "gam_age_offdiag_2" ...
  .. .. ..- attr(*, "order")= int [1:8] 1 1 1 1 1 1 1 1
  .. .. ..- attr(*, "intercept")= int 1
  .. .. ..- attr(*, "response")= int 1
  .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
  .. .. ..- attr(*, "predvars")= language list(contacts, school_probability, work_probability, offset(log_contactable_population),      gam_age_offdiag, ga| __truncated__ ...
  .. .. ..- attr(*, "dataClasses")= Named chr [1:11] "numeric" "numeric" "numeric" "numeric" ...
  .. .. .. ..- attr(*, "names")= chr [1:11] "contacts" "school_probability" "work_probability" "offset(log_contactable_population)" ...
  ..$ var.summary      :List of 9
  .. ..$ school_probability        : num [1:3] 0 0.00147 0.90552
  .. ..$ work_probability          : num [1:3] 0 0.0183 0.58
  .. ..$ log_contactable_population: num [1:3] -9.34 -4.5 -4.16
  .. ..$ gam_age_offdiag           : num [1:3] 0 28 100
  .. ..$ gam_age_offdiag_2         : num [1:3] 0 784 10000
  .. ..$ gam_age_diag_prod         : num [1:3] 0 1596 9000
  .. ..$ gam_age_diag_sum          : num [1:3] 0 93 190
  .. ..$ gam_age_pmax              : num [1:3] 0 66 100
  .. ..$ gam_age_pmin              : num [1:3] 0 27 90
  ..$ weights          : num [1:8787] 6.22 6.52 6.59 6.44 6.12 ...
  ..$ xlevels          : Named list()
  ..$ NA.action        :function (object, ...)  
  ..$ linear.predictors: num [1:8787] 1.83 1.87 1.88 1.86 1.81 ...
  ..$ fitted.values    : num [1:8787] 6.22 6.52 6.59 6.44 6.12 ...
  ..$ residuals        : num [1:8787] 1.393 0.187 1.89 2.573 2.098 ...
  ..$ deviance         : num 10296
  ..$ aic              : num 26986
  ..$ null.deviance    : num 44061
  ..- attr(*, "class")= chr [1:4] "bam" "gam" "glm" "lm"
 $ work  :List of 54
  ..$ coefficients     : Named num [1:57] -9.56e-01 -3.50 2.16 4.35e-05 -7.51e-06 ...
  .. ..- attr(*, "names")= chr [1:57] "(Intercept)" "school_probability" "work_probability" "s(gam_age_offdiag).1" ...
  ..$ db.drho          : num [1:55, 1:6] 1.99e-07 -5.71e-06 -2.08e-06 -2.50e-04 -6.47e-05 ...
  ..$ gcv.ubre         : Named num 24356
  .. ..- attr(*, "names")= chr "fREML"
  ..$ mgcv.conv        :List of 2
  .. ..$ iter   : int 13
  .. ..$ message: chr "full convergence"
  ..$ rank             : int 55
  ..$ Ve               : num [1:57, 1:57] 1.16e-02 -6.12e-03 -1.49e-02 1.64e-07 -2.79e-07 ...
  ..$ scale.estimated  : logi FALSE
  ..$ outer.info       :List of 4
  .. ..$ conv: chr "full convergence"
  .. ..$ iter: int 13
  .. ..$ grad: num [1:6] -1.08e-04 6.46e-05 1.01e-05 -7.70e-06 -3.87e-06 ...
  .. ..$ hess: num [1:6, 1:6] 1.08e-04 -6.48e-05 -1.01e-05 7.75e-06 3.89e-06 ...
  ..$ optimizer        : chr [1:2] "perf" "newton"
  ..$ scale            : num 1
  ..$ sig2             : num 1
  ..$ sp               : Named num [1:6] 3.48e+03 9.06e-02 2.01e-02 8.45e-04 3.53e-03 ...
  .. ..- attr(*, "names")= chr [1:6] "s(gam_age_offdiag)" "s(gam_age_offdiag_2)" "s(gam_age_diag_prod)" "s(gam_age_diag_sum)" ...
  ..$ edf              : Named num [1:57] 1.00 1.00 1.00 -1.36e-05 2.30e-05 ...
  .. ..- attr(*, "names")= chr [1:57] "(Intercept)" "school_probability" "work_probability" "s(gam_age_offdiag).1" ...
  ..$ edf1             : num [1:57] 1.00 1.00 1.00 -1.18e-05 3.44e-05 ...
  ..$ edf2             : num [1:57] 1.00 1.00 1.00 3.16e-05 3.91e-05 ...
  ..$ hat              : num [1:57] 1 0.986 1 1 0.944 ...
  ..$ Vp               : num [1:57, 1:57] 2.12e-02 -6.60e-03 -1.73e-02 -5.76e-08 -4.47e-07 ...
  ..$ Vc               : num [1:57, 1:57] 2.87e-02 7.58e-03 -1.63e-02 -8.04e-07 -2.24e-07 ...
  ..$ V.sp             : num [1:6, 1:6] 9242.0084 0.3825 0.2028 -0.1229 -0.0125 ...
  ..$ R                : num [1:57, 1:57] -132 0 0 0 0 ...
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ : NULL
  .. .. ..$ : NULL
  ..$ iter             : int 11
  ..$ wt               : num [1:8787] 0.00929 0.01031 0.01129 0.01219 0.01302 ...
  ..$ y                : int [1:8787] 0 0 0 0 0 0 0 0 0 0 ...
  ..$ prior.weights    : num [1:8787] 1 1 1 1 1 1 1 1 1 1 ...
  ..$ assign           : int [1:3] 0 1 2
  ..$ boundary         : logi FALSE
  ..$ call             : language mgcv::bam(formula = formula, family = stats::poisson, data = ., offset = log(participants))
  ..$ cmX              : Named num [1:57] 1.00 3.86e-02 1.42e-01 -2.69e-14 -5.18e-15 ...
  .. ..- attr(*, "names")= chr [1:57] "(Intercept)" "school_probability" "work_probability" "" ...
  ..$ control          :List of 19
  .. ..$ nthreads    : num 1
  .. ..$ ncv.threads : num 1
  .. ..$ irls.reg    : num 0
  .. ..$ epsilon     : num 1e-07
  .. ..$ maxit       : num 200
  .. ..$ trace       : logi FALSE
  .. ..$ mgcv.tol    : num 1e-07
  .. ..$ mgcv.half   : num 15
  .. ..$ rank.tol    : num 1.49e-08
  .. ..$ nlm         :List of 6
  .. .. ..$ ndigit           : num 7
  .. .. ..$ gradtol          : num 1e-06
  .. .. ..$ stepmax          : num 2
  .. .. ..$ steptol          : num 1e-04
  .. .. ..$ iterlim          : num 200
  .. .. ..$ check.analyticals: logi FALSE
  .. ..$ optim       :List of 1
  .. .. ..$ factr: num 1e+07
  .. ..$ newton      :List of 5
  .. .. ..$ conv.tol: num 1e-06
  .. .. ..$ maxNstep: num 5
  .. .. ..$ maxSstep: num 2
  .. .. ..$ maxHalf : num 30
  .. .. ..$ use.svd : logi FALSE
  .. ..$ idLinksBases: logi TRUE
  .. ..$ scalePenalty: logi TRUE
  .. ..$ efs.lspmax  : num 15
  .. ..$ efs.tol     : num 0.1
  .. ..$ keepData    : logi FALSE
  .. ..$ scale.est   : chr "fletcher"
  .. ..$ edge.correct: logi FALSE
  ..$ converged        : logi TRUE
  ..$ data             : logi NA
  ..$ df.null          : int 8787
  ..$ df.residual      : num 8755
  ..$ family           :List of 13
  .. ..$ family    : chr "poisson"
  .. ..$ link      : chr "log"
  .. ..$ linkfun   :function (mu)  
  .. ..$ linkinv   :function (eta)  
  .. ..$ variance  :function (mu)  
  .. ..$ dev.resids:function (y, mu, wt)  
  .. ..$ aic       :function (y, n, mu, wt, dev)  
  .. ..$ mu.eta    :function (eta)  
  .. ..$ initialize:  expression({  if (any(y < 0))  stop("negative values not allowed for the 'Poisson' family")  n <- rep.int(1, nobs| __truncated__
  .. ..$ validmu   :function (mu)  
  .. ..$ valideta  :function (eta)  
  .. ..$ simulate  :function (object, nsim)  
  .. ..$ dispersion: num 1
  .. ..- attr(*, "class")= chr "family"
  ..$ formula          :Class 'formula'  language contacts ~ s(gam_age_offdiag) + s(gam_age_offdiag_2) + s(gam_age_diag_prod) +      s(gam_age_diag_sum) + s(gam_ag| __truncated__ ...
  .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
  ..$ method           : chr "fREML"
  ..$ min.edf          : num 9
  ..$ model            :'data.frame':   8787 obs. of  11 variables:
  .. ..$ contacts                          : int [1:8787] 0 0 0 0 0 0 0 0 0 0 ...
  .. ..$ school_probability                : num [1:8787] 0 0 0 0 0 0 0 0 0 0 ...
  .. ..$ work_probability                  : num [1:8787] 0 0 0 0 0 0 0 0 0 0 ...
  .. ..$ offset(log_contactable_population): num [1:8787] -4.67 -4.66 -4.65 -4.63 -4.62 ...
  .. ..$ gam_age_offdiag                   : num [1:8787] 0 1 2 3 4 5 6 7 8 9 ...
  .. ..$ gam_age_offdiag_2                 : num [1:8787] 0 1 4 9 16 25 36 49 64 81 ...
  .. ..$ gam_age_diag_prod                 : num [1:8787] 0 0 0 0 0 0 0 0 0 0 ...
  .. ..$ gam_age_diag_sum                  : num [1:8787] 0 1 2 3 4 5 6 7 8 9 ...
  .. ..$ gam_age_pmax                      : num [1:8787] 0 1 2 3 4 5 6 7 8 9 ...
  .. ..$ gam_age_pmin                      : num [1:8787] 0 0 0 0 0 0 0 0 0 0 ...
  .. ..$ (offset)                          : num [1:8787] 4.52 4.52 4.52 4.52 4.52 ...
  .. ..- attr(*, "terms")=Classes 'terms', 'formula'  language contacts ~ school_probability + work_probability + offset(log_contactable_population) +      gam_age_offdiag + ga| __truncated__ ...
  .. .. .. ..- attr(*, "variables")= language list(contacts, school_probability, work_probability, offset(log_contactable_population),      gam_age_offdiag, ga| __truncated__ ...
  .. .. .. ..- attr(*, "offset")= int 4
  .. .. .. ..- attr(*, "factors")= int [1:10, 1:8] 0 1 0 0 0 0 0 0 0 0 ...
  .. .. .. .. ..- attr(*, "dimnames")=List of 2
  .. .. .. .. .. ..$ : chr [1:10] "contacts" "school_probability" "work_probability" "offset(log_contactable_population)" ...
  .. .. .. .. .. ..$ : chr [1:8] "school_probability" "work_probability" "gam_age_offdiag" "gam_age_offdiag_2" ...
  .. .. .. ..- attr(*, "term.labels")= chr [1:8] "school_probability" "work_probability" "gam_age_offdiag" "gam_age_offdiag_2" ...
  .. .. .. ..- attr(*, "order")= int [1:8] 1 1 1 1 1 1 1 1
  .. .. .. ..- attr(*, "intercept")= int 1
  .. .. .. ..- attr(*, "response")= int 1
  .. .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
  .. .. .. ..- attr(*, "predvars")= language list(contacts, school_probability, work_probability, offset(log_contactable_population),      gam_age_offdiag, ga| __truncated__ ...
  .. .. .. ..- attr(*, "dataClasses")= Named chr [1:11] "numeric" "numeric" "numeric" "numeric" ...
  .. .. .. .. ..- attr(*, "names")= chr [1:11] "contacts" "school_probability" "work_probability" "offset(log_contactable_population)" ...
  ..$ nsdf             : int 3
  ..$ offset           : num [1:8787] -0.1527 -0.1387 -0.1246 -0.1105 -0.0964 ...
  ..$ pterms           :Classes 'terms', 'formula'  language contacts ~ school_probability + work_probability + offset(log_contactable_population)
  .. .. ..- attr(*, "variables")= language list(contacts, school_probability, work_probability, offset(log_contactable_population))
  .. .. ..- attr(*, "offset")= int 4
  .. .. ..- attr(*, "factors")= int [1:4, 1:2] 0 1 0 0 0 0 1 0
  .. .. .. ..- attr(*, "dimnames")=List of 2
  .. .. .. .. ..$ : chr [1:4] "contacts" "school_probability" "work_probability" "offset(log_contactable_population)"
  .. .. .. .. ..$ : chr [1:2] "school_probability" "work_probability"
  .. .. ..- attr(*, "term.labels")= chr [1:2] "school_probability" "work_probability"
  .. .. ..- attr(*, "order")= int [1:2] 1 1
  .. .. ..- attr(*, "intercept")= int 1
  .. .. ..- attr(*, "response")= int 1
  .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
  .. .. ..- attr(*, "predvars")= language list(contacts, school_probability, work_probability, offset(log_contactable_population))
  .. .. ..- attr(*, "dataClasses")= Named chr [1:5] "numeric" "numeric" "numeric" "numeric" ...
  .. .. .. ..- attr(*, "names")= chr [1:5] "contacts" "school_probability" "work_probability" "offset(log_contactable_population)" ...
  ..$ pred.formula     :Class 'formula'  language ~school_probability + work_probability + log_contactable_population + gam_age_offdiag +      gam_age_offdiag_2 + | __truncated__ ...
  .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
  ..$ smooth           :List of 6
  .. ..$ :List of 29
  .. .. ..$ term          : chr "gam_age_offdiag"
  .. .. ..$ bs.dim        : num 10
  .. .. ..$ fixed         : logi FALSE
  .. .. ..$ dim           : int 1
  .. .. ..$ p.order       : num 0
  .. .. ..$ by            : chr "NA"
  .. .. ..$ label         : chr "s(gam_age_offdiag)"
  .. .. ..$ xt            : NULL
  .. .. ..$ id            : NULL
  .. .. ..$ sp            : Named num -1
  .. .. .. ..- attr(*, "names")= chr "s(gam_age_offdiag)"
  .. .. ..$ drop.null     : num 0
  .. .. ..$ S             :List of 1
  .. .. .. ..$ : num [1:9, 1:9] 2.558 -0.769 4.813 -1.005 4.801 ...
  .. .. ..$ UZ            : num [1:103, 1:10] -3.97e-06 -3.66e-06 -3.37e-06 -3.09e-06 -2.83e-06 ...
  .. .. ..$ Xu            : num [1:101, 1] -32 -31 -30 -29 -28 ...
  .. .. ..$ df            : num 9
  .. .. ..$ shift         : num [1(1d)] 32
  .. .. ..$ rank          : num 8
  .. .. ..$ null.space.dim: num 1
  .. .. ..$ plot.me       : logi TRUE
  .. .. ..$ side.constrain: logi TRUE
  .. .. ..$ repara        : logi TRUE
  .. .. ..$ C             : num 0
  .. .. ..$ S.scale       : num 2.27e-05
  .. .. ..$ Cp            : num 0
  .. .. ..$ vn            : chr "gam_age_offdiag"
  .. .. ..$ first.para    : num 4
  .. .. ..$ last.para     : num 12
  .. .. ..$ first.sp      : num 1
  .. .. ..$ last.sp       : num 1
  .. .. ..- attr(*, "class")= chr [1:2] "tprs.smooth" "mgcv.smooth"
  .. .. ..- attr(*, "qrc")= 'sweepDrop' num [1:10] 9 -0.938 -0.423 -0.743 -0.413 ...
  .. .. ..- attr(*, "nCons")= num 1
  .. ..$ :List of 29
  .. .. ..$ term          : chr "gam_age_offdiag_2"
  .. .. ..$ bs.dim        : num 10
  .. .. ..$ fixed         : logi FALSE
  .. .. ..$ dim           : int 1
  .. .. ..$ p.order       : num 0
  .. .. ..$ by            : chr "NA"
  .. .. ..$ label         : chr "s(gam_age_offdiag_2)"
  .. .. ..$ xt            : NULL
  .. .. ..$ id            : NULL
  .. .. ..$ sp            : Named num -1
  .. .. .. ..- attr(*, "names")= chr "s(gam_age_offdiag_2)"
  .. .. ..$ drop.null     : num 0
  .. .. ..$ S             :List of 1
  .. .. .. ..$ : num [1:9, 1:9] 1.75 -1.68 -3.12 -2.03 3.03 ...
  .. .. ..$ UZ            : num [1:103, 1:10] 1.54e-12 1.54e-12 1.54e-12 1.53e-12 1.51e-12 ...
  .. .. ..$ Xu            : num [1:101, 1] -1533 -1532 -1529 -1524 -1517 ...
  .. .. ..$ df            : num 9
  .. .. ..$ shift         : num [1(1d)] 1533
  .. .. ..$ rank          : num 8
  .. .. ..$ null.space.dim: num 1
  .. .. ..$ plot.me       : logi TRUE
  .. .. ..$ side.constrain: logi TRUE
  .. .. ..$ repara        : logi TRUE
  .. .. ..$ C             : num 0
  .. .. ..$ S.scale       : num 2.23e-11
  .. .. ..$ Cp            : num 0
  .. .. ..$ vn            : chr "gam_age_offdiag_2"
  .. .. ..$ first.para    : num 13
  .. .. ..$ last.para     : num 21
  .. .. ..$ first.sp      : num 2
  .. .. ..$ last.sp       : num 2
  .. .. ..- attr(*, "class")= chr [1:2] "tprs.smooth" "mgcv.smooth"
  .. .. ..- attr(*, "qrc")= 'sweepDrop' num [1:10] 9 0.961 0.691 -0.87 0.676 ...
  .. .. ..- attr(*, "nCons")= num 1
  .. ..$ :List of 29
  .. .. ..$ term          : chr "gam_age_diag_prod"
  .. .. ..$ bs.dim        : num 10
  .. .. ..$ fixed         : logi FALSE
  .. .. ..$ dim           : int 1
  .. .. ..$ p.order       : num 0
  .. .. ..$ by            : chr "NA"
  .. .. ..$ label         : chr "s(gam_age_diag_prod)"
  .. .. ..$ xt            : NULL
  .. .. ..$ id            : NULL
  .. .. ..$ sp            : Named num -1
  .. .. .. ..- attr(*, "names")= chr "s(gam_age_diag_prod)"
  .. .. ..$ drop.null     : num 0
  .. .. ..$ S             :List of 1
  .. .. .. ..$ : num [1:9, 1:9] 4.08 3.48 -8.2 -5.06 -7.78 ...
  .. .. ..$ UZ            : num [1:2002, 1:10] -2.38e-13 -2.37e-13 -2.37e-13 -2.36e-13 -2.36e-13 ...
  .. .. ..$ Xu            : num [1:2000, 1] -2152 -2150 -2149 -2146 -2145 ...
  .. .. ..$ df            : num 9
  .. .. ..$ shift         : num [1(1d)] 2152
  .. .. ..$ rank          : num 8
  .. .. ..$ null.space.dim: num 1
  .. .. ..$ plot.me       : logi TRUE
  .. .. ..$ side.constrain: logi TRUE
  .. .. ..$ repara        : logi TRUE
  .. .. ..$ C             : num 0
  .. .. ..$ S.scale       : num 2.26e-11
  .. .. ..$ Cp            : num 0
  .. .. ..$ vn            : chr "gam_age_diag_prod"
  .. .. ..$ first.para    : num 22
  .. .. ..$ last.para     : num 30
  .. .. ..$ first.sp      : num 3
  .. .. ..$ last.sp       : num 3
  .. .. ..- attr(*, "class")= chr [1:2] "tprs.smooth" "mgcv.smooth"
  .. .. ..- attr(*, "qrc")= 'sweepDrop' num [1:10] 9 -0.947 0.262 0.763 -0.162 ...
  .. .. ..- attr(*, "nCons")= num 1
  .. ..$ :List of 29
  .. .. ..$ term          : chr "gam_age_diag_sum"
  .. .. ..$ bs.dim        : num 10
  .. .. ..$ fixed         : logi FALSE
  .. .. ..$ dim           : int 1
  .. .. ..$ p.order       : num 0
  .. .. ..$ by            : chr "NA"
  .. .. ..$ label         : chr "s(gam_age_diag_sum)"
  .. .. ..$ xt            : NULL
  .. .. ..$ id            : NULL
  .. .. ..$ sp            : Named num -1
  .. .. .. ..- attr(*, "names")= chr "s(gam_age_diag_sum)"
  .. .. ..$ drop.null     : num 0
  .. .. ..$ S             :List of 1
  .. .. .. ..$ : num [1:9, 1:9] 4.97 1.09 11.11 -1.66 -11.93 ...
  .. .. ..$ UZ            : num [1:193, 1:10] 4.62e-07 4.42e-07 4.23e-07 4.04e-07 3.85e-07 ...
  .. .. ..$ Xu            : num [1:191, 1] -93 -92 -91 -90 -89 ...
  .. .. ..$ df            : num 9
  .. .. ..$ shift         : num [1(1d)] 93
  .. .. ..$ rank          : num 8
  .. .. ..$ null.space.dim: num 1
  .. .. ..$ plot.me       : logi TRUE
  .. .. ..$ side.constrain: logi TRUE
  .. .. ..$ repara        : logi TRUE
  .. .. ..$ C             : num 0
  .. .. ..$ S.scale       : num 2.88e-06
  .. .. ..$ Cp            : num 0
  .. .. ..$ vn            : chr "gam_age_diag_sum"
  .. .. ..$ first.para    : num 31
  .. .. ..$ last.para     : num 39
  .. .. ..$ first.sp      : num 4
  .. .. ..$ last.sp       : num 4
  .. .. ..- attr(*, "class")= chr [1:2] "tprs.smooth" "mgcv.smooth"
  .. .. ..- attr(*, "qrc")= 'sweepDrop' num [1:10] 9 0.951 0.292 0.558 -0.351 ...
  .. .. ..- attr(*, "nCons")= num 1
  .. ..$ :List of 29
  .. .. ..$ term          : chr "gam_age_pmax"
  .. .. ..$ bs.dim        : num 10
  .. .. ..$ fixed         : logi FALSE
  .. .. ..$ dim           : int 1
  .. .. ..$ p.order       : num 0
  .. .. ..$ by            : chr "NA"
  .. .. ..$ label         : chr "s(gam_age_pmax)"
  .. .. ..$ xt            : NULL
  .. .. ..$ id            : NULL
  .. .. ..$ sp            : Named num -1
  .. .. .. ..- attr(*, "names")= chr "s(gam_age_pmax)"
  .. .. ..$ drop.null     : num 0
  .. .. ..$ S             :List of 1
  .. .. .. ..$ : num [1:9, 1:9] 4.151 -0.822 7.91 -1.089 8.153 ...
  .. .. ..$ UZ            : num [1:103, 1:10] -4.38e-06 -4.04e-06 -3.72e-06 -3.41e-06 -3.12e-06 ...
  .. .. ..$ Xu            : num [1:101, 1] -62.5 -61.5 -60.5 -59.5 -58.5 ...
  .. .. ..$ df            : num 9
  .. .. ..$ shift         : num [1(1d)] 62.5
  .. .. ..$ rank          : num 8
  .. .. ..$ null.space.dim: num 1
  .. .. ..$ plot.me       : logi TRUE
  .. .. ..$ side.constrain: logi TRUE
  .. .. ..$ repara        : logi TRUE
  .. .. ..$ C             : num 0
  .. .. ..$ S.scale       : num 1.7e-05
  .. .. ..$ Cp            : num 0
  .. .. ..$ vn            : chr "gam_age_pmax"
  .. .. ..$ first.para    : num 40
  .. .. ..$ last.para     : num 48
  .. .. ..$ first.sp      : num 5
  .. .. ..$ last.sp       : num 5
  .. .. ..- attr(*, "class")= chr [1:2] "tprs.smooth" "mgcv.smooth"
  .. .. ..- attr(*, "qrc")= 'sweepDrop' num [1:10] 9 -0.943 0.625 -0.705 0.621 ...
  .. .. ..- attr(*, "nCons")= num 1
  .. ..$ :List of 29
  .. .. ..$ term          : chr "gam_age_pmin"
  .. .. ..$ bs.dim        : num 10
  .. .. ..$ fixed         : logi FALSE
  .. .. ..$ dim           : int 1
  .. .. ..$ p.order       : num 0
  .. .. ..$ by            : chr "NA"
  .. .. ..$ label         : chr "s(gam_age_pmin)"
  .. .. ..$ xt            : NULL
  .. .. ..$ id            : NULL
  .. .. ..$ sp            : Named num -1
  .. .. .. ..- attr(*, "names")= chr "s(gam_age_pmin)"
  .. .. ..$ drop.null     : num 0
  .. .. ..$ S             :List of 1
  .. .. .. ..$ : num [1:9, 1:9] 3.642 0.732 6.581 -0.913 6.554 ...
  .. .. ..$ UZ            : num [1:93, 1:10] -6.87e-06 -6.26e-06 -5.67e-06 -5.11e-06 -4.59e-06 ...
  .. .. ..$ Xu            : num [1:91, 1] -30.5 -29.5 -28.5 -27.5 -26.5 ...
  .. .. ..$ df            : num 9
  .. .. ..$ shift         : num [1(1d)] 30.5
  .. .. ..$ rank          : num 8
  .. .. ..$ null.space.dim: num 1
  .. .. ..$ plot.me       : logi TRUE
  .. .. ..$ side.constrain: logi TRUE
  .. .. ..$ repara        : logi TRUE
  .. .. ..$ C             : num 0
  .. .. ..$ S.scale       : num 2.24e-05
  .. .. ..$ Cp            : num 0
  .. .. ..$ vn            : chr "gam_age_pmin"
  .. .. ..$ first.para    : num 49
  .. .. ..$ last.para     : num 57
  .. .. ..$ first.sp      : num 6
  .. .. ..$ last.sp       : num 6
  .. .. ..- attr(*, "class")= chr [1:2] "tprs.smooth" "mgcv.smooth"
  .. .. ..- attr(*, "qrc")= 'sweepDrop' num [1:10] 9 -0.939 -0.671 -0.745 0.669 ...
  .. .. ..- attr(*, "nCons")= num 1
  ..$ terms            :Classes 'terms', 'formula'  language contacts ~ school_probability + work_probability + offset(log_contactable_population) +      gam_age_offdiag + ga| __truncated__ ...
  .. .. ..- attr(*, "variables")= language list(contacts, school_probability, work_probability, offset(log_contactable_population),      gam_age_offdiag, ga| __truncated__ ...
  .. .. ..- attr(*, "offset")= int 4
  .. .. ..- attr(*, "factors")= int [1:10, 1:8] 0 1 0 0 0 0 0 0 0 0 ...
  .. .. .. ..- attr(*, "dimnames")=List of 2
  .. .. .. .. ..$ : chr [1:10] "contacts" "school_probability" "work_probability" "offset(log_contactable_population)" ...
  .. .. .. .. ..$ : chr [1:8] "school_probability" "work_probability" "gam_age_offdiag" "gam_age_offdiag_2" ...
  .. .. ..- attr(*, "term.labels")= chr [1:8] "school_probability" "work_probability" "gam_age_offdiag" "gam_age_offdiag_2" ...
  .. .. ..- attr(*, "order")= int [1:8] 1 1 1 1 1 1 1 1
  .. .. ..- attr(*, "intercept")= int 1
  .. .. ..- attr(*, "response")= int 1
  .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
  .. .. ..- attr(*, "predvars")= language list(contacts, school_probability, work_probability, offset(log_contactable_population),      gam_age_offdiag, ga| __truncated__ ...
  .. .. ..- attr(*, "dataClasses")= Named chr [1:11] "numeric" "numeric" "numeric" "numeric" ...
  .. .. .. ..- attr(*, "names")= chr [1:11] "contacts" "school_probability" "work_probability" "offset(log_contactable_population)" ...
  ..$ var.summary      :List of 9
  .. ..$ school_probability        : num [1:3] 0 0.00147 0.90552
  .. ..$ work_probability          : num [1:3] 0 0.0183 0.58
  .. ..$ log_contactable_population: num [1:3] -9.34 -4.5 -4.16
  .. ..$ gam_age_offdiag           : num [1:3] 0 28 100
  .. ..$ gam_age_offdiag_2         : num [1:3] 0 784 10000
  .. ..$ gam_age_diag_prod         : num [1:3] 0 1596 9000
  .. ..$ gam_age_diag_sum          : num [1:3] 0 93 190
  .. ..$ gam_age_pmax              : num [1:3] 0 66 100
  .. ..$ gam_age_pmin              : num [1:3] 0 27 90
  ..$ weights          : num [1:8787] 0.00929 0.01031 0.01129 0.01219 0.01302 ...
  ..$ xlevels          : Named list()
  ..$ NA.action        :function (object, ...)  
  ..$ linear.predictors: num [1:8787] -4.68 -4.57 -4.48 -4.41 -4.34 ...
  ..$ fitted.values    : num [1:8787] 0.00929 0.01031 0.01129 0.01219 0.01302 ...
  ..$ residuals        : num [1:8787] -0.136 -0.144 -0.15 -0.156 -0.161 ...
  ..$ deviance         : num 13263
  ..$ aic              : num 23512
  ..$ null.deviance    : num 48608
  ..- attr(*, "class")= chr [1:4] "bam" "gam" "glm" "lm"
 $ school:List of 54
  ..$ coefficients     : Named num [1:57] -7.622 -1.818 -0.255 -56.568 11.422 ...
  .. ..- attr(*, "names")= chr [1:57] "(Intercept)" "school_probability" "work_probability" "s(gam_age_offdiag).1" ...
  ..$ db.drho          : num [1:55, 1:6] 0.0468 0.0125 0.0408 -3.5456 -3.6435 ...
  ..$ gcv.ubre         : Named num 23077
  .. ..- attr(*, "names")= chr "fREML"
  ..$ mgcv.conv        :List of 2
  .. ..$ iter   : int 16
  .. ..$ message: chr "full convergence"
  ..$ rank             : int 55
  ..$ Ve               : num [1:57, 1:57] 1.28177 0.00594 0.01103 0.32637 0.04817 ...
  ..$ scale.estimated  : logi FALSE
  ..$ outer.info       :List of 4
  .. ..$ conv: chr "full convergence"
  .. ..$ iter: int 16
  .. ..$ grad: num [1:6] -1.24e-04 -9.10e-05 -5.40e-05 -5.08e-05 -3.23e-05 ...
  .. ..$ hess: num [1:6, 1:6] 3.014643 0.000124 0.15623 0.159387 0.092433 ...
  ..$ optimizer        : chr [1:2] "perf" "newton"
  ..$ scale            : num 1
  ..$ sig2             : num 1
  ..$ sp               : Named num [1:6] 1.10e-03 2.36e+01 6.19e-05 6.77e-06 7.52e-05 ...
  .. ..- attr(*, "names")= chr [1:6] "s(gam_age_offdiag)" "s(gam_age_offdiag_2)" "s(gam_age_diag_prod)" "s(gam_age_diag_sum)" ...
  ..$ edf              : Named num [1:57] 1 1 1 0.751 0.917 ...
  .. ..- attr(*, "names")= chr [1:57] "(Intercept)" "school_probability" "work_probability" "s(gam_age_offdiag).1" ...
  ..$ edf1             : num [1:57] 1 1 1 0.896 0.961 ...
  ..$ edf2             : num [1:57] 1 1 1 0.896 0.961 ...
  ..$ hat              : num [1:57] 1 1 1 1 1 ...
  ..$ Vp               : num [1:57, 1:57] 2.10274 0.00884 0.01803 0.50174 0.07166 ...
  ..$ Vc               : num [1:57, 1:57] 3.6672 0.0187 0.0399 -1.8361 -0.8078 ...
  ..$ V.sp             : num [1:6, 1:6] 0.3363 -0.4086 -0.04 -0.0356 -0.0176 ...
  ..$ R                : num [1:57, 1:57] -133.14 30.083 -25.536 -0.245 23.378 ...
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ : NULL
  .. .. ..$ : NULL
  ..$ iter             : int 19
  ..$ wt               : num [1:8787] 12.19 10.42 8.21 6.04 4.2 ...
  ..$ y                : int [1:8787] 13 4 2 1 1 3 0 0 0 0 ...
  ..$ prior.weights    : num [1:8787] 1 1 1 1 1 1 1 1 1 1 ...
  ..$ assign           : int [1:3] 0 1 2
  ..$ boundary         : logi FALSE
  ..$ call             : language mgcv::bam(formula = formula, family = stats::poisson, data = ., offset = log(participants))
  ..$ cmX              : Named num [1:57] 1.00 3.86e-02 1.42e-01 -2.69e-14 -5.18e-15 ...
  .. ..- attr(*, "names")= chr [1:57] "(Intercept)" "school_probability" "work_probability" "" ...
  ..$ control          :List of 19
  .. ..$ nthreads    : num 1
  .. ..$ ncv.threads : num 1
  .. ..$ irls.reg    : num 0
  .. ..$ epsilon     : num 1e-07
  .. ..$ maxit       : num 200
  .. ..$ trace       : logi FALSE
  .. ..$ mgcv.tol    : num 1e-07
  .. ..$ mgcv.half   : num 15
  .. ..$ rank.tol    : num 1.49e-08
  .. ..$ nlm         :List of 6
  .. .. ..$ ndigit           : num 7
  .. .. ..$ gradtol          : num 1e-06
  .. .. ..$ stepmax          : num 2
  .. .. ..$ steptol          : num 1e-04
  .. .. ..$ iterlim          : num 200
  .. .. ..$ check.analyticals: logi FALSE
  .. ..$ optim       :List of 1
  .. .. ..$ factr: num 1e+07
  .. ..$ newton      :List of 5
  .. .. ..$ conv.tol: num 1e-06
  .. .. ..$ maxNstep: num 5
  .. .. ..$ maxSstep: num 2
  .. .. ..$ maxHalf : num 30
  .. .. ..$ use.svd : logi FALSE
  .. ..$ idLinksBases: logi TRUE
  .. ..$ scalePenalty: logi TRUE
  .. ..$ efs.lspmax  : num 15
  .. ..$ efs.tol     : num 0.1
  .. ..$ keepData    : logi FALSE
  .. ..$ scale.est   : chr "fletcher"
  .. ..$ edge.correct: logi FALSE
  ..$ converged        : logi TRUE
  ..$ data             : logi NA
  ..$ df.null          : int 8787
  ..$ df.residual      : num 8744
  ..$ family           :List of 13
  .. ..$ family    : chr "poisson"
  .. ..$ link      : chr "log"
  .. ..$ linkfun   :function (mu)  
  .. ..$ linkinv   :function (eta)  
  .. ..$ variance  :function (mu)  
  .. ..$ dev.resids:function (y, mu, wt)  
  .. ..$ aic       :function (y, n, mu, wt, dev)  
  .. ..$ mu.eta    :function (eta)  
  .. ..$ initialize:  expression({  if (any(y < 0))  stop("negative values not allowed for the 'Poisson' family")  n <- rep.int(1, nobs| __truncated__
  .. ..$ validmu   :function (mu)  
  .. ..$ valideta  :function (eta)  
  .. ..$ simulate  :function (object, nsim)  
  .. ..$ dispersion: num 1
  .. ..- attr(*, "class")= chr "family"
  ..$ formula          :Class 'formula'  language contacts ~ s(gam_age_offdiag) + s(gam_age_offdiag_2) + s(gam_age_diag_prod) +      s(gam_age_diag_sum) + s(gam_ag| __truncated__ ...
  .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
  ..$ method           : chr "fREML"
  ..$ min.edf          : num 9
  ..$ model            :'data.frame':   8787 obs. of  11 variables:
  .. ..$ contacts                                 : int [1:8787] 13 4 2 1 1 3 0 0 0 0 ...
  .. ..$ school_probability                       : num [1:8787] 0 0 0 0 0 0 0 0 0 0 ...
  .. ..$ work_probability                         : num [1:8787] 0 0 0 0 0 0 0 0 0 0 ...
  .. ..$ offset(log_contactable_population_school): num [1:8787] -4.67 -4.66 -4.65 -4.63 -4.62 ...
  .. ..$ gam_age_offdiag                          : num [1:8787] 0 1 2 3 4 5 6 7 8 9 ...
  .. ..$ gam_age_offdiag_2                        : num [1:8787] 0 1 4 9 16 25 36 49 64 81 ...
  .. ..$ gam_age_diag_prod                        : num [1:8787] 0 0 0 0 0 0 0 0 0 0 ...
  .. ..$ gam_age_diag_sum                         : num [1:8787] 0 1 2 3 4 5 6 7 8 9 ...
  .. ..$ gam_age_pmax                             : num [1:8787] 0 1 2 3 4 5 6 7 8 9 ...
  .. ..$ gam_age_pmin                             : num [1:8787] 0 0 0 0 0 0 0 0 0 0 ...
  .. ..$ (offset)                                 : num [1:8787] 4.52 4.52 4.52 4.52 4.52 ...
  .. ..- attr(*, "terms")=Classes 'terms', 'formula'  language contacts ~ school_probability + work_probability + offset(log_contactable_population_school) +      gam_age_offdi| __truncated__ ...
  .. .. .. ..- attr(*, "variables")= language list(contacts, school_probability, work_probability, offset(log_contactable_population_school),      gam_age_offd| __truncated__ ...
  .. .. .. ..- attr(*, "offset")= int 4
  .. .. .. ..- attr(*, "factors")= int [1:10, 1:8] 0 1 0 0 0 0 0 0 0 0 ...
  .. .. .. .. ..- attr(*, "dimnames")=List of 2
  .. .. .. .. .. ..$ : chr [1:10] "contacts" "school_probability" "work_probability" "offset(log_contactable_population_school)" ...
  .. .. .. .. .. ..$ : chr [1:8] "school_probability" "work_probability" "gam_age_offdiag" "gam_age_offdiag_2" ...
  .. .. .. ..- attr(*, "term.labels")= chr [1:8] "school_probability" "work_probability" "gam_age_offdiag" "gam_age_offdiag_2" ...
  .. .. .. ..- attr(*, "order")= int [1:8] 1 1 1 1 1 1 1 1
  .. .. .. ..- attr(*, "intercept")= int 1
  .. .. .. ..- attr(*, "response")= int 1
  .. .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
  .. .. .. ..- attr(*, "predvars")= language list(contacts, school_probability, work_probability, offset(log_contactable_population_school),      gam_age_offd| __truncated__ ...
  .. .. .. ..- attr(*, "dataClasses")= Named chr [1:11] "numeric" "numeric" "numeric" "numeric" ...
  .. .. .. .. ..- attr(*, "names")= chr [1:11] "contacts" "school_probability" "work_probability" "offset(log_contactable_population_school)" ...
  ..$ nsdf             : int 3
  ..$ offset           : num [1:8787] -0.1527 -0.1387 -0.1246 -0.1105 -0.0964 ...
  ..$ pterms           :Classes 'terms', 'formula'  language contacts ~ school_probability + work_probability + offset(log_contactable_population_school)
  .. .. ..- attr(*, "variables")= language list(contacts, school_probability, work_probability, offset(log_contactable_population_school))
  .. .. ..- attr(*, "offset")= int 4
  .. .. ..- attr(*, "factors")= int [1:4, 1:2] 0 1 0 0 0 0 1 0
  .. .. .. ..- attr(*, "dimnames")=List of 2
  .. .. .. .. ..$ : chr [1:4] "contacts" "school_probability" "work_probability" "offset(log_contactable_population_school)"
  .. .. .. .. ..$ : chr [1:2] "school_probability" "work_probability"
  .. .. ..- attr(*, "term.labels")= chr [1:2] "school_probability" "work_probability"
  .. .. ..- attr(*, "order")= int [1:2] 1 1
  .. .. ..- attr(*, "intercept")= int 1
  .. .. ..- attr(*, "response")= int 1
  .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
  .. .. ..- attr(*, "predvars")= language list(contacts, school_probability, work_probability, offset(log_contactable_population_school))
  .. .. ..- attr(*, "dataClasses")= Named chr [1:5] "numeric" "numeric" "numeric" "numeric" ...
  .. .. .. ..- attr(*, "names")= chr [1:5] "contacts" "school_probability" "work_probability" "offset(log_contactable_population_school)" ...
  ..$ pred.formula     :Class 'formula'  language ~school_probability + work_probability + log_contactable_population_school +      gam_age_offdiag + gam_age_offdi| __truncated__ ...
  .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
  ..$ smooth           :List of 6
  .. ..$ :List of 29
  .. .. ..$ term          : chr "gam_age_offdiag"
  .. .. ..$ bs.dim        : num 10
  .. .. ..$ fixed         : logi FALSE
  .. .. ..$ dim           : int 1
  .. .. ..$ p.order       : num 0
  .. .. ..$ by            : chr "NA"
  .. .. ..$ label         : chr "s(gam_age_offdiag)"
  .. .. ..$ xt            : NULL
  .. .. ..$ id            : NULL
  .. .. ..$ sp            : Named num -1
  .. .. .. ..- attr(*, "names")= chr "s(gam_age_offdiag)"
  .. .. ..$ drop.null     : num 0
  .. .. ..$ S             :List of 1
  .. .. .. ..$ : num [1:9, 1:9] 2.558 -0.769 4.813 -1.005 4.801 ...
  .. .. ..$ UZ            : num [1:103, 1:10] -3.97e-06 -3.66e-06 -3.37e-06 -3.09e-06 -2.83e-06 ...
  .. .. ..$ Xu            : num [1:101, 1] -32 -31 -30 -29 -28 ...
  .. .. ..$ df            : num 9
  .. .. ..$ shift         : num [1(1d)] 32
  .. .. ..$ rank          : num 8
  .. .. ..$ null.space.dim: num 1
  .. .. ..$ plot.me       : logi TRUE
  .. .. ..$ side.constrain: logi TRUE
  .. .. ..$ repara        : logi TRUE
  .. .. ..$ C             : num 0
  .. .. ..$ S.scale       : num 2.27e-05
  .. .. ..$ Cp            : num 0
  .. .. ..$ vn            : chr "gam_age_offdiag"
  .. .. ..$ first.para    : num 4
  .. .. ..$ last.para     : num 12
  .. .. ..$ first.sp      : num 1
  .. .. ..$ last.sp       : num 1
  .. .. ..- attr(*, "class")= chr [1:2] "tprs.smooth" "mgcv.smooth"
  .. .. ..- attr(*, "qrc")= 'sweepDrop' num [1:10] 9 -0.938 -0.423 -0.743 -0.413 ...
  .. .. ..- attr(*, "nCons")= num 1
  .. ..$ :List of 29
  .. .. ..$ term          : chr "gam_age_offdiag_2"
  .. .. ..$ bs.dim        : num 10
  .. .. ..$ fixed         : logi FALSE
  .. .. ..$ dim           : int 1
  .. .. ..$ p.order       : num 0
  .. .. ..$ by            : chr "NA"
  .. .. ..$ label         : chr "s(gam_age_offdiag_2)"
  .. .. ..$ xt            : NULL
  .. .. ..$ id            : NULL
  .. .. ..$ sp            : Named num -1
  .. .. .. ..- attr(*, "names")= chr "s(gam_age_offdiag_2)"
  .. .. ..$ drop.null     : num 0
  .. .. ..$ S             :List of 1
  .. .. .. ..$ : num [1:9, 1:9] 1.75 -1.68 -3.12 -2.03 3.03 ...
  .. .. ..$ UZ            : num [1:103, 1:10] 1.54e-12 1.54e-12 1.54e-12 1.53e-12 1.51e-12 ...
  .. .. ..$ Xu            : num [1:101, 1] -1533 -1532 -1529 -1524 -1517 ...
  .. .. ..$ df            : num 9
  .. .. ..$ shift         : num [1(1d)] 1533
  .. .. ..$ rank          : num 8
  .. .. ..$ null.space.dim: num 1
  .. .. ..$ plot.me       : logi TRUE
  .. .. ..$ side.constrain: logi TRUE
  .. .. ..$ repara        : logi TRUE
  .. .. ..$ C             : num 0
  .. .. ..$ S.scale       : num 2.23e-11
  .. .. ..$ Cp            : num 0
  .. .. ..$ vn            : chr "gam_age_offdiag_2"
  .. .. ..$ first.para    : num 13
  .. .. ..$ last.para     : num 21
  .. .. ..$ first.sp      : num 2
  .. .. ..$ last.sp       : num 2
  .. .. ..- attr(*, "class")= chr [1:2] "tprs.smooth" "mgcv.smooth"
  .. .. ..- attr(*, "qrc")= 'sweepDrop' num [1:10] 9 0.961 0.691 -0.87 0.676 ...
  .. .. ..- attr(*, "nCons")= num 1
  .. ..$ :List of 29
  .. .. ..$ term          : chr "gam_age_diag_prod"
  .. .. ..$ bs.dim        : num 10
  .. .. ..$ fixed         : logi FALSE
  .. .. ..$ dim           : int 1
  .. .. ..$ p.order       : num 0
  .. .. ..$ by            : chr "NA"
  .. .. ..$ label         : chr "s(gam_age_diag_prod)"
  .. .. ..$ xt            : NULL
  .. .. ..$ id            : NULL
  .. .. ..$ sp            : Named num -1
  .. .. .. ..- attr(*, "names")= chr "s(gam_age_diag_prod)"
  .. .. ..$ drop.null     : num 0
  .. .. ..$ S             :List of 1
  .. .. .. ..$ : num [1:9, 1:9] 4.08 3.48 -8.2 -5.06 -7.78 ...
  .. .. ..$ UZ            : num [1:2002, 1:10] -2.38e-13 -2.37e-13 -2.37e-13 -2.36e-13 -2.36e-13 ...
  .. .. ..$ Xu            : num [1:2000, 1] -2152 -2150 -2149 -2146 -2145 ...
  .. .. ..$ df            : num 9
  .. .. ..$ shift         : num [1(1d)] 2152
  .. .. ..$ rank          : num 8
  .. .. ..$ null.space.dim: num 1
  .. .. ..$ plot.me       : logi TRUE
  .. .. ..$ side.constrain: logi TRUE
  .. .. ..$ repara        : logi TRUE
  .. .. ..$ C             : num 0
  .. .. ..$ S.scale       : num 2.26e-11
  .. .. ..$ Cp            : num 0
  .. .. ..$ vn            : chr "gam_age_diag_prod"
  .. .. ..$ first.para    : num 22
  .. .. ..$ last.para     : num 30
  .. .. ..$ first.sp      : num 3
  .. .. ..$ last.sp       : num 3
  .. .. ..- attr(*, "class")= chr [1:2] "tprs.smooth" "mgcv.smooth"
  .. .. ..- attr(*, "qrc")= 'sweepDrop' num [1:10] 9 -0.947 0.262 0.763 -0.162 ...
  .. .. ..- attr(*, "nCons")= num 1
  .. ..$ :List of 29
  .. .. ..$ term          : chr "gam_age_diag_sum"
  .. .. ..$ bs.dim        : num 10
  .. .. ..$ fixed         : logi FALSE
  .. .. ..$ dim           : int 1
  .. .. ..$ p.order       : num 0
  .. .. ..$ by            : chr "NA"
  .. .. ..$ label         : chr "s(gam_age_diag_sum)"
  .. .. ..$ xt            : NULL
  .. .. ..$ id            : NULL
  .. .. ..$ sp            : Named num -1
  .. .. .. ..- attr(*, "names")= chr "s(gam_age_diag_sum)"
  .. .. ..$ drop.null     : num 0
  .. .. ..$ S             :List of 1
  .. .. .. ..$ : num [1:9, 1:9] 4.97 1.09 11.11 -1.66 -11.93 ...
  .. .. ..$ UZ            : num [1:193, 1:10] 4.62e-07 4.42e-07 4.23e-07 4.04e-07 3.85e-07 ...
  .. .. ..$ Xu            : num [1:191, 1] -93 -92 -91 -90 -89 ...
  .. .. ..$ df            : num 9
  .. .. ..$ shift         : num [1(1d)] 93
  .. .. ..$ rank          : num 8
  .. .. ..$ null.space.dim: num 1
  .. .. ..$ plot.me       : logi TRUE
  .. .. ..$ side.constrain: logi TRUE
  .. .. ..$ repara        : logi TRUE
  .. .. ..$ C             : num 0
  .. .. ..$ S.scale       : num 2.88e-06
  .. .. ..$ Cp            : num 0
  .. .. ..$ vn            : chr "gam_age_diag_sum"
  .. .. ..$ first.para    : num 31
  .. .. ..$ last.para     : num 39
  .. .. ..$ first.sp      : num 4
  .. .. ..$ last.sp       : num 4
  .. .. ..- attr(*, "class")= chr [1:2] "tprs.smooth" "mgcv.smooth"
  .. .. ..- attr(*, "qrc")= 'sweepDrop' num [1:10] 9 0.951 0.292 0.558 -0.351 ...
  .. .. ..- attr(*, "nCons")= num 1
  .. ..$ :List of 29
  .. .. ..$ term          : chr "gam_age_pmax"
  .. .. ..$ bs.dim        : num 10
  .. .. ..$ fixed         : logi FALSE
  .. .. ..$ dim           : int 1
  .. .. ..$ p.order       : num 0
  .. .. ..$ by            : chr "NA"
  .. .. ..$ label         : chr "s(gam_age_pmax)"
  .. .. ..$ xt            : NULL
  .. .. ..$ id            : NULL
  .. .. ..$ sp            : Named num -1
  .. .. .. ..- attr(*, "names")= chr "s(gam_age_pmax)"
  .. .. ..$ drop.null     : num 0
  .. .. ..$ S             :List of 1
  .. .. .. ..$ : num [1:9, 1:9] 4.151 -0.822 7.91 -1.089 8.153 ...
  .. .. ..$ UZ            : num [1:103, 1:10] -4.38e-06 -4.04e-06 -3.72e-06 -3.41e-06 -3.12e-06 ...
  .. .. ..$ Xu            : num [1:101, 1] -62.5 -61.5 -60.5 -59.5 -58.5 ...
  .. .. ..$ df            : num 9
  .. .. ..$ shift         : num [1(1d)] 62.5
  .. .. ..$ rank          : num 8
  .. .. ..$ null.space.dim: num 1
  .. .. ..$ plot.me       : logi TRUE
  .. .. ..$ side.constrain: logi TRUE
  .. .. ..$ repara        : logi TRUE
  .. .. ..$ C             : num 0
  .. .. ..$ S.scale       : num 1.7e-05
  .. .. ..$ Cp            : num 0
  .. .. ..$ vn            : chr "gam_age_pmax"
  .. .. ..$ first.para    : num 40
  .. .. ..$ last.para     : num 48
  .. .. ..$ first.sp      : num 5
  .. .. ..$ last.sp       : num 5
  .. .. ..- attr(*, "class")= chr [1:2] "tprs.smooth" "mgcv.smooth"
  .. .. ..- attr(*, "qrc")= 'sweepDrop' num [1:10] 9 -0.943 0.625 -0.705 0.621 ...
  .. .. ..- attr(*, "nCons")= num 1
  .. ..$ :List of 29
  .. .. ..$ term          : chr "gam_age_pmin"
  .. .. ..$ bs.dim        : num 10
  .. .. ..$ fixed         : logi FALSE
  .. .. ..$ dim           : int 1
  .. .. ..$ p.order       : num 0
  .. .. ..$ by            : chr "NA"
  .. .. ..$ label         : chr "s(gam_age_pmin)"
  .. .. ..$ xt            : NULL
  .. .. ..$ id            : NULL
  .. .. ..$ sp            : Named num -1
  .. .. .. ..- attr(*, "names")= chr "s(gam_age_pmin)"
  .. .. ..$ drop.null     : num 0
  .. .. ..$ S             :List of 1
  .. .. .. ..$ : num [1:9, 1:9] 3.642 0.732 6.581 -0.913 6.554 ...
  .. .. ..$ UZ            : num [1:93, 1:10] -6.87e-06 -6.26e-06 -5.67e-06 -5.11e-06 -4.59e-06 ...
  .. .. ..$ Xu            : num [1:91, 1] -30.5 -29.5 -28.5 -27.5 -26.5 ...
  .. .. ..$ df            : num 9
  .. .. ..$ shift         : num [1(1d)] 30.5
  .. .. ..$ rank          : num 8
  .. .. ..$ null.space.dim: num 1
  .. .. ..$ plot.me       : logi TRUE
  .. .. ..$ side.constrain: logi TRUE
  .. .. ..$ repara        : logi TRUE
  .. .. ..$ C             : num 0
  .. .. ..$ S.scale       : num 2.24e-05
  .. .. ..$ Cp            : num 0
  .. .. ..$ vn            : chr "gam_age_pmin"
  .. .. ..$ first.para    : num 49
  .. .. ..$ last.para     : num 57
  .. .. ..$ first.sp      : num 6
  .. .. ..$ last.sp       : num 6
  .. .. ..- attr(*, "class")= chr [1:2] "tprs.smooth" "mgcv.smooth"
  .. .. ..- attr(*, "qrc")= 'sweepDrop' num [1:10] 9 -0.939 -0.671 -0.745 0.669 ...
  .. .. ..- attr(*, "nCons")= num 1
  ..$ terms            :Classes 'terms', 'formula'  language contacts ~ school_probability + work_probability + offset(log_contactable_population_school) +      gam_age_offdi| __truncated__ ...
  .. .. ..- attr(*, "variables")= language list(contacts, school_probability, work_probability, offset(log_contactable_population_school),      gam_age_offd| __truncated__ ...
  .. .. ..- attr(*, "offset")= int 4
  .. .. ..- attr(*, "factors")= int [1:10, 1:8] 0 1 0 0 0 0 0 0 0 0 ...
  .. .. .. ..- attr(*, "dimnames")=List of 2
  .. .. .. .. ..$ : chr [1:10] "contacts" "school_probability" "work_probability" "offset(log_contactable_population_school)" ...
  .. .. .. .. ..$ : chr [1:8] "school_probability" "work_probability" "gam_age_offdiag" "gam_age_offdiag_2" ...
  .. .. ..- attr(*, "term.labels")= chr [1:8] "school_probability" "work_probability" "gam_age_offdiag" "gam_age_offdiag_2" ...
  .. .. ..- attr(*, "order")= int [1:8] 1 1 1 1 1 1 1 1
  .. .. ..- attr(*, "intercept")= int 1
  .. .. ..- attr(*, "response")= int 1
  .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
  .. .. ..- attr(*, "predvars")= language list(contacts, school_probability, work_probability, offset(log_contactable_population_school),      gam_age_offd| __truncated__ ...
  .. .. ..- attr(*, "dataClasses")= Named chr [1:11] "numeric" "numeric" "numeric" "numeric" ...
  .. .. .. ..- attr(*, "names")= chr [1:11] "contacts" "school_probability" "work_probability" "offset(log_contactable_population_school)" ...
  ..$ var.summary      :List of 9
  .. ..$ school_probability               : num [1:3] 0 0.00147 0.90552
  .. ..$ work_probability                 : num [1:3] 0 0.0183 0.58
  .. ..$ log_contactable_population_school: num [1:3] -9.34 -4.5 -0.78
  .. ..$ gam_age_offdiag                  : num [1:3] 0 28 100
  .. ..$ gam_age_offdiag_2                : num [1:3] 0 784 10000
  .. ..$ gam_age_diag_prod                : num [1:3] 0 1596 9000
  .. ..$ gam_age_diag_sum                 : num [1:3] 0 93 190
  .. ..$ gam_age_pmax                     : num [1:3] 0 66 100
  .. ..$ gam_age_pmin                     : num [1:3] 0 27 90
  ..$ weights          : num [1:8787] 12.19 10.42 8.21 6.04 4.2 ...
  ..$ xlevels          : Named list()
  ..$ NA.action        :function (object, ...)  
  ..$ linear.predictors: num [1:8787] 2.5 2.34 2.11 1.8 1.43 ...
  ..$ fitted.values    : num [1:8787] 12.19 10.42 8.21 6.04 4.2 ...
  ..$ residuals        : num [1:8787] 0.228 -2.277 -2.604 -2.545 -1.877 ...
  ..$ deviance         : num 12770
  ..$ aic              : num 19174
  ..$ null.deviance    : num 133524
  ..- attr(*, "class")= chr [1:4] "bam" "gam" "glm" "lm"
 $ other :List of 54
  ..$ coefficients     : Named num [1:57] 0.926 -0.86 -1.082 40.002 -6.537 ...
  .. ..- attr(*, "names")= chr [1:57] "(Intercept)" "school_probability" "work_probability" "s(gam_age_offdiag).1" ...
  ..$ db.drho          : num [1:55, 1:6] 0.00142 -0.00374 -0.00655 4.02079 0.4178 ...
  ..$ gcv.ubre         : Named num 17677
  .. ..- attr(*, "names")= chr "fREML"
  ..$ mgcv.conv        :List of 2
  .. ..$ iter   : int 12
  .. ..$ message: chr "full convergence"
  ..$ rank             : int 55
  ..$ Ve               : num [1:57, 1:57] 0.003973 -0.000963 -0.004959 -0.024502 -0.001923 ...
  ..$ scale.estimated  : logi FALSE
  ..$ outer.info       :List of 4
  .. ..$ conv: chr "full convergence"
  .. ..$ iter: int 12
  .. ..$ grad: num [1:6] 2.94e-09 3.38e-09 -1.71e-10 -1.84e-10 -9.56e-11 ...
  .. ..$ hess: num [1:6, 1:6] 1.65562 0.13578 -0.00797 -0.01038 -0.00135 ...
  ..$ optimizer        : chr [1:2] "perf" "newton"
  ..$ scale            : num 1
  ..$ sig2             : num 1
  ..$ sp               : Named num [1:6] 1.05e-03 8.71e-04 2.78e-05 4.30e-06 1.03e-04 ...
  .. ..- attr(*, "names")= chr [1:6] "s(gam_age_offdiag)" "s(gam_age_offdiag_2)" "s(gam_age_diag_prod)" "s(gam_age_diag_sum)" ...
  ..$ edf              : Named num [1:57] 1 1 1 0.303 0.525 ...
  .. ..- attr(*, "names")= chr [1:57] "(Intercept)" "school_probability" "work_probability" "s(gam_age_offdiag).1" ...
  ..$ edf1             : num [1:57] 1 1 1 0.312 0.533 ...
  ..$ edf2             : num [1:57] 1 1 1 0.353 0.4 ...
  ..$ hat              : num [1:57] 1 1 1 1 1 ...
  ..$ Vp               : num [1:57, 1:57] 0.004087 -0.000984 -0.004991 -0.033431 -0.001424 ...
  ..$ Vc               : num [1:57, 1:57] 0.0042 -0.00106 -0.00505 0.02959 0.00869 ...
  ..$ V.sp             : num [1:6, 1:6] 0.607825 -0.046479 0.000519 0.00084 -0.000192 ...
  ..$ R                : num [1:57, 1:57] -145.1 87.9 26.7 -92.3 0 ...
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ : NULL
  .. .. ..$ : NULL
  ..$ iter             : int 9
  ..$ wt               : num [1:8787] 7.99 6.36 5.18 4.3 3.62 ...
  ..$ y                : int [1:8787] 7 7 11 11 5 5 4 4 2 3 ...
  ..$ prior.weights    : num [1:8787] 1 1 1 1 1 1 1 1 1 1 ...
  ..$ assign           : int [1:3] 0 1 2
  ..$ boundary         : logi FALSE
  ..$ call             : language mgcv::bam(formula = formula, family = stats::poisson, data = ., offset = log(participants))
  ..$ cmX              : Named num [1:57] 1.00 3.86e-02 1.42e-01 -2.69e-14 -5.18e-15 ...
  .. ..- attr(*, "names")= chr [1:57] "(Intercept)" "school_probability" "work_probability" "" ...
  ..$ control          :List of 19
  .. ..$ nthreads    : num 1
  .. ..$ ncv.threads : num 1
  .. ..$ irls.reg    : num 0
  .. ..$ epsilon     : num 1e-07
  .. ..$ maxit       : num 200
  .. ..$ trace       : logi FALSE
  .. ..$ mgcv.tol    : num 1e-07
  .. ..$ mgcv.half   : num 15
  .. ..$ rank.tol    : num 1.49e-08
  .. ..$ nlm         :List of 6
  .. .. ..$ ndigit           : num 7
  .. .. ..$ gradtol          : num 1e-06
  .. .. ..$ stepmax          : num 2
  .. .. ..$ steptol          : num 1e-04
  .. .. ..$ iterlim          : num 200
  .. .. ..$ check.analyticals: logi FALSE
  .. ..$ optim       :List of 1
  .. .. ..$ factr: num 1e+07
  .. ..$ newton      :List of 5
  .. .. ..$ conv.tol: num 1e-06
  .. .. ..$ maxNstep: num 5
  .. .. ..$ maxSstep: num 2
  .. .. ..$ maxHalf : num 30
  .. .. ..$ use.svd : logi FALSE
  .. ..$ idLinksBases: logi TRUE
  .. ..$ scalePenalty: logi TRUE
  .. ..$ efs.lspmax  : num 15
  .. ..$ efs.tol     : num 0.1
  .. ..$ keepData    : logi FALSE
  .. ..$ scale.est   : chr "fletcher"
  .. ..$ edge.correct: logi FALSE
  ..$ converged        : logi TRUE
  ..$ data             : logi NA
  ..$ df.null          : int 8787
  ..$ df.residual      : num 8738
  ..$ family           :List of 13
  .. ..$ family    : chr "poisson"
  .. ..$ link      : chr "log"
  .. ..$ linkfun   :function (mu)  
  .. ..$ linkinv   :function (eta)  
  .. ..$ variance  :function (mu)  
  .. ..$ dev.resids:function (y, mu, wt)  
  .. ..$ aic       :function (y, n, mu, wt, dev)  
  .. ..$ mu.eta    :function (eta)  
  .. ..$ initialize:  expression({  if (any(y < 0))  stop("negative values not allowed for the 'Poisson' family")  n <- rep.int(1, nobs| __truncated__
  .. ..$ validmu   :function (mu)  
  .. ..$ valideta  :function (eta)  
  .. ..$ simulate  :function (object, nsim)  
  .. ..$ dispersion: num 1
  .. ..- attr(*, "class")= chr "family"
  ..$ formula          :Class 'formula'  language contacts ~ s(gam_age_offdiag) + s(gam_age_offdiag_2) + s(gam_age_diag_prod) +      s(gam_age_diag_sum) + s(gam_ag| __truncated__ ...
  .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
  ..$ method           : chr "fREML"
  ..$ min.edf          : num 9
  ..$ model            :'data.frame':   8787 obs. of  11 variables:
  .. ..$ contacts                          : int [1:8787] 7 7 11 11 5 5 4 4 2 3 ...
  .. ..$ school_probability                : num [1:8787] 0 0 0 0 0 0 0 0 0 0 ...
  .. ..$ work_probability                  : num [1:8787] 0 0 0 0 0 0 0 0 0 0 ...
  .. ..$ offset(log_contactable_population): num [1:8787] -4.67 -4.66 -4.65 -4.63 -4.62 ...
  .. ..$ gam_age_offdiag                   : num [1:8787] 0 1 2 3 4 5 6 7 8 9 ...
  .. ..$ gam_age_offdiag_2                 : num [1:8787] 0 1 4 9 16 25 36 49 64 81 ...
  .. ..$ gam_age_diag_prod                 : num [1:8787] 0 0 0 0 0 0 0 0 0 0 ...
  .. ..$ gam_age_diag_sum                  : num [1:8787] 0 1 2 3 4 5 6 7 8 9 ...
  .. ..$ gam_age_pmax                      : num [1:8787] 0 1 2 3 4 5 6 7 8 9 ...
  .. ..$ gam_age_pmin                      : num [1:8787] 0 0 0 0 0 0 0 0 0 0 ...
  .. ..$ (offset)                          : num [1:8787] 4.52 4.52 4.52 4.52 4.52 ...
  .. ..- attr(*, "terms")=Classes 'terms', 'formula'  language contacts ~ school_probability + work_probability + offset(log_contactable_population) +      gam_age_offdiag + ga| __truncated__ ...
  .. .. .. ..- attr(*, "variables")= language list(contacts, school_probability, work_probability, offset(log_contactable_population),      gam_age_offdiag, ga| __truncated__ ...
  .. .. .. ..- attr(*, "offset")= int 4
  .. .. .. ..- attr(*, "factors")= int [1:10, 1:8] 0 1 0 0 0 0 0 0 0 0 ...
  .. .. .. .. ..- attr(*, "dimnames")=List of 2
  .. .. .. .. .. ..$ : chr [1:10] "contacts" "school_probability" "work_probability" "offset(log_contactable_population)" ...
  .. .. .. .. .. ..$ : chr [1:8] "school_probability" "work_probability" "gam_age_offdiag" "gam_age_offdiag_2" ...
  .. .. .. ..- attr(*, "term.labels")= chr [1:8] "school_probability" "work_probability" "gam_age_offdiag" "gam_age_offdiag_2" ...
  .. .. .. ..- attr(*, "order")= int [1:8] 1 1 1 1 1 1 1 1
  .. .. .. ..- attr(*, "intercept")= int 1
  .. .. .. ..- attr(*, "response")= int 1
  .. .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
  .. .. .. ..- attr(*, "predvars")= language list(contacts, school_probability, work_probability, offset(log_contactable_population),      gam_age_offdiag, ga| __truncated__ ...
  .. .. .. ..- attr(*, "dataClasses")= Named chr [1:11] "numeric" "numeric" "numeric" "numeric" ...
  .. .. .. .. ..- attr(*, "names")= chr [1:11] "contacts" "school_probability" "work_probability" "offset(log_contactable_population)" ...
  ..$ nsdf             : int 3
  ..$ offset           : num [1:8787] -0.1527 -0.1387 -0.1246 -0.1105 -0.0964 ...
  ..$ pterms           :Classes 'terms', 'formula'  language contacts ~ school_probability + work_probability + offset(log_contactable_population)
  .. .. ..- attr(*, "variables")= language list(contacts, school_probability, work_probability, offset(log_contactable_population))
  .. .. ..- attr(*, "offset")= int 4
  .. .. ..- attr(*, "factors")= int [1:4, 1:2] 0 1 0 0 0 0 1 0
  .. .. .. ..- attr(*, "dimnames")=List of 2
  .. .. .. .. ..$ : chr [1:4] "contacts" "school_probability" "work_probability" "offset(log_contactable_population)"
  .. .. .. .. ..$ : chr [1:2] "school_probability" "work_probability"
  .. .. ..- attr(*, "term.labels")= chr [1:2] "school_probability" "work_probability"
  .. .. ..- attr(*, "order")= int [1:2] 1 1
  .. .. ..- attr(*, "intercept")= int 1
  .. .. ..- attr(*, "response")= int 1
  .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
  .. .. ..- attr(*, "predvars")= language list(contacts, school_probability, work_probability, offset(log_contactable_population))
  .. .. ..- attr(*, "dataClasses")= Named chr [1:5] "numeric" "numeric" "numeric" "numeric" ...
  .. .. .. ..- attr(*, "names")= chr [1:5] "contacts" "school_probability" "work_probability" "offset(log_contactable_population)" ...
  ..$ pred.formula     :Class 'formula'  language ~school_probability + work_probability + log_contactable_population + gam_age_offdiag +      gam_age_offdiag_2 + | __truncated__ ...
  .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
  ..$ smooth           :List of 6
  .. ..$ :List of 29
  .. .. ..$ term          : chr "gam_age_offdiag"
  .. .. ..$ bs.dim        : num 10
  .. .. ..$ fixed         : logi FALSE
  .. .. ..$ dim           : int 1
  .. .. ..$ p.order       : num 0
  .. .. ..$ by            : chr "NA"
  .. .. ..$ label         : chr "s(gam_age_offdiag)"
  .. .. ..$ xt            : NULL
  .. .. ..$ id            : NULL
  .. .. ..$ sp            : Named num -1
  .. .. .. ..- attr(*, "names")= chr "s(gam_age_offdiag)"
  .. .. ..$ drop.null     : num 0
  .. .. ..$ S             :List of 1
  .. .. .. ..$ : num [1:9, 1:9] 2.558 -0.769 4.813 -1.005 4.801 ...
  .. .. ..$ UZ            : num [1:103, 1:10] -3.97e-06 -3.66e-06 -3.37e-06 -3.09e-06 -2.83e-06 ...
  .. .. ..$ Xu            : num [1:101, 1] -32 -31 -30 -29 -28 ...
  .. .. ..$ df            : num 9
  .. .. ..$ shift         : num [1(1d)] 32
  .. .. ..$ rank          : num 8
  .. .. ..$ null.space.dim: num 1
  .. .. ..$ plot.me       : logi TRUE
  .. .. ..$ side.constrain: logi TRUE
  .. .. ..$ repara        : logi TRUE
  .. .. ..$ C             : num 0
  .. .. ..$ S.scale       : num 2.27e-05
  .. .. ..$ Cp            : num 0
  .. .. ..$ vn            : chr "gam_age_offdiag"
  .. .. ..$ first.para    : num 4
  .. .. ..$ last.para     : num 12
  .. .. ..$ first.sp      : num 1
  .. .. ..$ last.sp       : num 1
  .. .. ..- attr(*, "class")= chr [1:2] "tprs.smooth" "mgcv.smooth"
  .. .. ..- attr(*, "qrc")= 'sweepDrop' num [1:10] 9 -0.938 -0.423 -0.743 -0.413 ...
  .. .. ..- attr(*, "nCons")= num 1
  .. ..$ :List of 29
  .. .. ..$ term          : chr "gam_age_offdiag_2"
  .. .. ..$ bs.dim        : num 10
  .. .. ..$ fixed         : logi FALSE
  .. .. ..$ dim           : int 1
  .. .. ..$ p.order       : num 0
  .. .. ..$ by            : chr "NA"
  .. .. ..$ label         : chr "s(gam_age_offdiag_2)"
  .. .. ..$ xt            : NULL
  .. .. ..$ id            : NULL
  .. .. ..$ sp            : Named num -1
  .. .. .. ..- attr(*, "names")= chr "s(gam_age_offdiag_2)"
  .. .. ..$ drop.null     : num 0
  .. .. ..$ S             :List of 1
  .. .. .. ..$ : num [1:9, 1:9] 1.75 -1.68 -3.12 -2.03 3.03 ...
  .. .. ..$ UZ            : num [1:103, 1:10] 1.54e-12 1.54e-12 1.54e-12 1.53e-12 1.51e-12 ...
  .. .. ..$ Xu            : num [1:101, 1] -1533 -1532 -1529 -1524 -1517 ...
  .. .. ..$ df            : num 9
  .. .. ..$ shift         : num [1(1d)] 1533
  .. .. ..$ rank          : num 8
  .. .. ..$ null.space.dim: num 1
  .. .. ..$ plot.me       : logi TRUE
  .. .. ..$ side.constrain: logi TRUE
  .. .. ..$ repara        : logi TRUE
  .. .. ..$ C             : num 0
  .. .. ..$ S.scale       : num 2.23e-11
  .. .. ..$ Cp            : num 0
  .. .. ..$ vn            : chr "gam_age_offdiag_2"
  .. .. ..$ first.para    : num 13
  .. .. ..$ last.para     : num 21
  .. .. ..$ first.sp      : num 2
  .. .. ..$ last.sp       : num 2
  .. .. ..- attr(*, "class")= chr [1:2] "tprs.smooth" "mgcv.smooth"
  .. .. ..- attr(*, "qrc")= 'sweepDrop' num [1:10] 9 0.961 0.691 -0.87 0.676 ...
  .. .. ..- attr(*, "nCons")= num 1
  .. ..$ :List of 29
  .. .. ..$ term          : chr "gam_age_diag_prod"
  .. .. ..$ bs.dim        : num 10
  .. .. ..$ fixed         : logi FALSE
  .. .. ..$ dim           : int 1
  .. .. ..$ p.order       : num 0
  .. .. ..$ by            : chr "NA"
  .. .. ..$ label         : chr "s(gam_age_diag_prod)"
  .. .. ..$ xt            : NULL
  .. .. ..$ id            : NULL
  .. .. ..$ sp            : Named num -1
  .. .. .. ..- attr(*, "names")= chr "s(gam_age_diag_prod)"
  .. .. ..$ drop.null     : num 0
  .. .. ..$ S             :List of 1
  .. .. .. ..$ : num [1:9, 1:9] 4.08 3.48 -8.2 -5.06 -7.78 ...
  .. .. ..$ UZ            : num [1:2002, 1:10] -2.38e-13 -2.37e-13 -2.37e-13 -2.36e-13 -2.36e-13 ...
  .. .. ..$ Xu            : num [1:2000, 1] -2152 -2150 -2149 -2146 -2145 ...
  .. .. ..$ df            : num 9
  .. .. ..$ shift         : num [1(1d)] 2152
  .. .. ..$ rank          : num 8
  .. .. ..$ null.space.dim: num 1
  .. .. ..$ plot.me       : logi TRUE
  .. .. ..$ side.constrain: logi TRUE
  .. .. ..$ repara        : logi TRUE
  .. .. ..$ C             : num 0
  .. .. ..$ S.scale       : num 2.26e-11
  .. .. ..$ Cp            : num 0
  .. .. ..$ vn            : chr "gam_age_diag_prod"
  .. .. ..$ first.para    : num 22
  .. .. ..$ last.para     : num 30
  .. .. ..$ first.sp      : num 3
  .. .. ..$ last.sp       : num 3
  .. .. ..- attr(*, "class")= chr [1:2] "tprs.smooth" "mgcv.smooth"
  .. .. ..- attr(*, "qrc")= 'sweepDrop' num [1:10] 9 -0.947 0.262 0.763 -0.162 ...
  .. .. ..- attr(*, "nCons")= num 1
  .. ..$ :List of 29
  .. .. ..$ term          : chr "gam_age_diag_sum"
  .. .. ..$ bs.dim        : num 10
  .. .. ..$ fixed         : logi FALSE
  .. .. ..$ dim           : int 1
  .. .. ..$ p.order       : num 0
  .. .. ..$ by            : chr "NA"
  .. .. ..$ label         : chr "s(gam_age_diag_sum)"
  .. .. ..$ xt            : NULL
  .. .. ..$ id            : NULL
  .. .. ..$ sp            : Named num -1
  .. .. .. ..- attr(*, "names")= chr "s(gam_age_diag_sum)"
  .. .. ..$ drop.null     : num 0
  .. .. ..$ S             :List of 1
  .. .. .. ..$ : num [1:9, 1:9] 4.97 1.09 11.11 -1.66 -11.93 ...
  .. .. ..$ UZ            : num [1:193, 1:10] 4.62e-07 4.42e-07 4.23e-07 4.04e-07 3.85e-07 ...
  .. .. ..$ Xu            : num [1:191, 1] -93 -92 -91 -90 -89 ...
  .. .. ..$ df            : num 9
  .. .. ..$ shift         : num [1(1d)] 93
  .. .. ..$ rank          : num 8
  .. .. ..$ null.space.dim: num 1
  .. .. ..$ plot.me       : logi TRUE
  .. .. ..$ side.constrain: logi TRUE
  .. .. ..$ repara        : logi TRUE
  .. .. ..$ C             : num 0
  .. .. ..$ S.scale       : num 2.88e-06
  .. .. ..$ Cp            : num 0
  .. .. ..$ vn            : chr "gam_age_diag_sum"
  .. .. ..$ first.para    : num 31
  .. .. ..$ last.para     : num 39
  .. .. ..$ first.sp      : num 4
  .. .. ..$ last.sp       : num 4
  .. .. ..- attr(*, "class")= chr [1:2] "tprs.smooth" "mgcv.smooth"
  .. .. ..- attr(*, "qrc")= 'sweepDrop' num [1:10] 9 0.951 0.292 0.558 -0.351 ...
  .. .. ..- attr(*, "nCons")= num 1
  .. ..$ :List of 29
  .. .. ..$ term          : chr "gam_age_pmax"
  .. .. ..$ bs.dim        : num 10
  .. .. ..$ fixed         : logi FALSE
  .. .. ..$ dim           : int 1
  .. .. ..$ p.order       : num 0
  .. .. ..$ by            : chr "NA"
  .. .. ..$ label         : chr "s(gam_age_pmax)"
  .. .. ..$ xt            : NULL
  .. .. ..$ id            : NULL
  .. .. ..$ sp            : Named num -1
  .. .. .. ..- attr(*, "names")= chr "s(gam_age_pmax)"
  .. .. ..$ drop.null     : num 0
  .. .. ..$ S             :List of 1
  .. .. .. ..$ : num [1:9, 1:9] 4.151 -0.822 7.91 -1.089 8.153 ...
  .. .. ..$ UZ            : num [1:103, 1:10] -4.38e-06 -4.04e-06 -3.72e-06 -3.41e-06 -3.12e-06 ...
  .. .. ..$ Xu            : num [1:101, 1] -62.5 -61.5 -60.5 -59.5 -58.5 ...
  .. .. ..$ df            : num 9
  .. .. ..$ shift         : num [1(1d)] 62.5
  .. .. ..$ rank          : num 8
  .. .. ..$ null.space.dim: num 1
  .. .. ..$ plot.me       : logi TRUE
  .. .. ..$ side.constrain: logi TRUE
  .. .. ..$ repara        : logi TRUE
  .. .. ..$ C             : num 0
  .. .. ..$ S.scale       : num 1.7e-05
  .. .. ..$ Cp            : num 0
  .. .. ..$ vn            : chr "gam_age_pmax"
  .. .. ..$ first.para    : num 40
  .. .. ..$ last.para     : num 48
  .. .. ..$ first.sp      : num 5
  .. .. ..$ last.sp       : num 5
  .. .. ..- attr(*, "class")= chr [1:2] "tprs.smooth" "mgcv.smooth"
  .. .. ..- attr(*, "qrc")= 'sweepDrop' num [1:10] 9 -0.943 0.625 -0.705 0.621 ...
  .. .. ..- attr(*, "nCons")= num 1
  .. ..$ :List of 29
  .. .. ..$ term          : chr "gam_age_pmin"
  .. .. ..$ bs.dim        : num 10
  .. .. ..$ fixed         : logi FALSE
  .. .. ..$ dim           : int 1
  .. .. ..$ p.order       : num 0
  .. .. ..$ by            : chr "NA"
  .. .. ..$ label         : chr "s(gam_age_pmin)"
  .. .. ..$ xt            : NULL
  .. .. ..$ id            : NULL
  .. .. ..$ sp            : Named num -1
  .. .. .. ..- attr(*, "names")= chr "s(gam_age_pmin)"
  .. .. ..$ drop.null     : num 0
  .. .. ..$ S             :List of 1
  .. .. .. ..$ : num [1:9, 1:9] 3.642 0.732 6.581 -0.913 6.554 ...
  .. .. ..$ UZ            : num [1:93, 1:10] -6.87e-06 -6.26e-06 -5.67e-06 -5.11e-06 -4.59e-06 ...
  .. .. ..$ Xu            : num [1:91, 1] -30.5 -29.5 -28.5 -27.5 -26.5 ...
  .. .. ..$ df            : num 9
  .. .. ..$ shift         : num [1(1d)] 30.5
  .. .. ..$ rank          : num 8
  .. .. ..$ null.space.dim: num 1
  .. .. ..$ plot.me       : logi TRUE
  .. .. ..$ side.constrain: logi TRUE
  .. .. ..$ repara        : logi TRUE
  .. .. ..$ C             : num 0
  .. .. ..$ S.scale       : num 2.24e-05
  .. .. ..$ Cp            : num 0
  .. .. ..$ vn            : chr "gam_age_pmin"
  .. .. ..$ first.para    : num 49
  .. .. ..$ last.para     : num 57
  .. .. ..$ first.sp      : num 6
  .. .. ..$ last.sp       : num 6
  .. .. ..- attr(*, "class")= chr [1:2] "tprs.smooth" "mgcv.smooth"
  .. .. ..- attr(*, "qrc")= 'sweepDrop' num [1:10] 9 -0.939 -0.671 -0.745 0.669 ...
  .. .. ..- attr(*, "nCons")= num 1
  ..$ terms            :Classes 'terms', 'formula'  language contacts ~ school_probability + work_probability + offset(log_contactable_population) +      gam_age_offdiag + ga| __truncated__ ...
  .. .. ..- attr(*, "variables")= language list(contacts, school_probability, work_probability, offset(log_contactable_population),      gam_age_offdiag, ga| __truncated__ ...
  .. .. ..- attr(*, "offset")= int 4
  .. .. ..- attr(*, "factors")= int [1:10, 1:8] 0 1 0 0 0 0 0 0 0 0 ...
  .. .. .. ..- attr(*, "dimnames")=List of 2
  .. .. .. .. ..$ : chr [1:10] "contacts" "school_probability" "work_probability" "offset(log_contactable_population)" ...
  .. .. .. .. ..$ : chr [1:8] "school_probability" "work_probability" "gam_age_offdiag" "gam_age_offdiag_2" ...
  .. .. ..- attr(*, "term.labels")= chr [1:8] "school_probability" "work_probability" "gam_age_offdiag" "gam_age_offdiag_2" ...
  .. .. ..- attr(*, "order")= int [1:8] 1 1 1 1 1 1 1 1
  .. .. ..- attr(*, "intercept")= int 1
  .. .. ..- attr(*, "response")= int 1
  .. .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
  .. .. ..- attr(*, "predvars")= language list(contacts, school_probability, work_probability, offset(log_contactable_population),      gam_age_offdiag, ga| __truncated__ ...
  .. .. ..- attr(*, "dataClasses")= Named chr [1:11] "numeric" "numeric" "numeric" "numeric" ...
  .. .. .. ..- attr(*, "names")= chr [1:11] "contacts" "school_probability" "work_probability" "offset(log_contactable_population)" ...
  ..$ var.summary      :List of 9
  .. ..$ school_probability        : num [1:3] 0 0.00147 0.90552
  .. ..$ work_probability          : num [1:3] 0 0.0183 0.58
  .. ..$ log_contactable_population: num [1:3] -9.34 -4.5 -4.16
  .. ..$ gam_age_offdiag           : num [1:3] 0 28 100
  .. ..$ gam_age_offdiag_2         : num [1:3] 0 784 10000
  .. ..$ gam_age_diag_prod         : num [1:3] 0 1596 9000
  .. ..$ gam_age_diag_sum          : num [1:3] 0 93 190
  .. ..$ gam_age_pmax              : num [1:3] 0 66 100
  .. ..$ gam_age_pmin              : num [1:3] 0 27 90
  ..$ weights          : num [1:8787] 7.99 6.36 5.18 4.3 3.62 ...
  ..$ xlevels          : Named list()
  ..$ NA.action        :function (object, ...)  
  ..$ linear.predictors: num [1:8787] 2.08 1.85 1.64 1.46 1.29 ...
  ..$ fitted.values    : num [1:8787] 7.99 6.36 5.18 4.3 3.62 ...
  ..$ residuals        : num [1:8787] -0.358 0.25 2.222 2.698 0.683 ...
  ..$ deviance         : num 14913
  ..$ aic              : num 33995
  ..$ null.deviance    : num 76245
  ..- attr(*, "class")= chr [1:4] "bam" "gam" "glm" "lm"
 - attr(*, "class")= chr [1:2] "setting_contact_model" "list"

Alt approach to conmat model

synthetic_settings_5y_subiaco <- predict_setting_contacts(
  population = subiaco_age_pop,
  contact_model = setting_models,
  age_breaks = c(seq(0, 85, by = 5), Inf)
  )

synthetic_settings_5y_subiaco

In code: How does the model work?

(simplified)

mgcv::bam(
  formula = contacts ~
    # deviation of contact age distribution from population age distribution
    s(age_to) +
    # number of contacts by age
    s(age_from) +
    # intergenerational contact patterns - enables the off-diagonals
    s(abs(age_from - age_to)) +
    # interaction between intergenerational patterns and age_from, to remove
    # ridge for some ages and settings
    s(abs(age_from - age_to), age_from) +
    # probabilities of both attending (any) school/work
    school_probability +
    work_probability +
    offset(school_popn/work_popn),
    family = stats::poisson,
    # NOTE: the offset of participants allows us to get the rate per person
    offset = log(participants)
    )

This is the last slide.