Data set up

library(haven)
library(readstata13)
library(sjlabelled)
library(dplyr)
library(readxl)
library(stringr)
library(table1)
library(ggplot2)
library(ggpubr)
library(lme4)
library(nlme)
library(survey)
library(Hmisc)
library(tidyr)
library(metafor)
library(effects)
library(ppcor)
library(tidyverse)
library(igraph)
library(ggraph)
library(kableExtra)
library(reshape2)
library(abind)

# load the function metareg.timeXgroup() which outputs the group by time interaction term from a meta-regression
source(paste0(path,"Project A. Targets for intervention in life satisfaction/R outputs/UndSoc_functions.R"))

# load cleaned long-form dataset "usoc", as well as summary datasets "osm.list" on households and "pidp.list" on unique participants
load(paste0(path, "R code/usoc_cleaned.RData"))
# remove the very few 16 year olds from the dataset (n=15): surveyed in error
usoc <- usoc[usoc$dvage!="16",]
usoc$dvage <- droplevels(usoc$dvage)

# remove any data collected in the year 2025 (only 18 participants)
usoc <- usoc[usoc$intdaty_dv!="2025", ]
usoc$intdaty_dv <- droplevels(usoc$intdaty_dv)

# remove rows where ID is missing (all variables are NA for these two rows)
usoc <- usoc[!is.na(usoc$pidp),]

Note: most data cleaning is done in the “Cleaning UndSoc Youth data.Rmd” script. But here, we create some additional categorical variables.

usoc$time.window <- factor(cut(usoc$int.year.sched, breaks=c(-Inf,2013, 2018, Inf), labels=c(1, 2, 3)))
# note you're using the scheduled-interview year variable, not the actual interview year variable. They're only max 4 months off.

usoc$age.3groups <- factor(factor(usoc$dvage, levels=c(10,11,12,13,14,15),
                         labels=c("10-11", "10-11", "12-13", "12-13", "14-15", "14-15")))

# change order of levels from most to least prevalent/in order asked
usoc$ethnicity <- factor(usoc$ethnicity, levels=c("British or Irish" ,"Any other white background","South or East Asian",  "African or Caribbean", "Mixed background" , "Other"))


# create income groups 
for (x in unique(usoc$int.year.sched)){
usoc$income.groups[usoc$int.year.sched==x] <- 
  cut(usoc$equivinc[usoc$int.year.sched==x], 
                    breaks=c(-Inf,
                              quantile(usoc$equivinc[usoc$int.year.sched==x], 
                                       probs=c(.33, .66)), 
                             Inf))                   
}

usoc$income.groups <- factor(usoc$income.groups, levels=c(1,2,3), 
                               labels=c("low.inc", "mid.inc", "high.inc"))

usoc$income.groups <- relevel(usoc$income.groups, "high.inc")

#  # £1054.068,  £1577.720 are the breakpoints (TO UPDATE)

# create a version of income where its capped at £8000 per month to avoid influence of extreme outliers.
# not used in main analysis
usoc$equivinc.capped <- ifelse(usoc$equivinc > 8000 | usoc$equivinc < 0, NA, usoc$equivinc)

Set colours of life domains, for plots: Grey = life in general Orange = family Blue = friends Mid green = school Lime green = schoolwork Pink = appearance

cols6 <- c("lightgrey","#FC8D62FF", "#8DA0CBFF", "#66C2A5FF","#A6D854FF",  "#E78AC3FF" )
            # life.    family.      friends.       school     schoolwork  appearance, 

cols5 <- c(           "#FC8D62FF", "#8DA0CBFF", "#66C2A5FF","#A6D854FF",  "#E78AC3FF")
                       # family.      friends.       school     schoolwork  appearance

cols18 <- c("#FC8D62FF","#FC8D62FF", "#FC8D62FF",  "#8DA0CBFF", "#8DA0CBFF", "#8DA0CBFF", "#66C2A5FF","#66C2A5FF","#66C2A5FF","#A6D854FF", "#A6D854FF", "#A6D854FF",  "#E78AC3FF", "#E78AC3FF", "#E78AC3FF","lightgrey", "lightgrey", "lightgrey" )

Variable naming

Note that some variable names were changed from their original names.

Life satisfaction variables - h.schoolwork <- yphsw - h.appear <- yphap - h.fam <- yphfm - h.friends <- yphfr - h.school <- yphsc - h.life <- yphlf Note, the numbering of these variables changed from 1 to 7 to -3 to +3. Also centered versions of these variables also exist with the suffic “.c” e.g. “h.schoolwork.c”

Socio-demographics hsdincome <- fihhmnnet1_dv

Descriptives

# Table of sociodemographics by wave (note: participants may be counted multiple times in the "overall" column)

table1(~age.group + sex_dv + ethnicity + hsdincome + equivinc  + country + h.life.c + doby_dv.n | wave.y, data=usoc) 
2009-10
(N=4899)
2010-11
(N=5015)
2011-12
(N=4427)
2012-13
(N=4044)
2013-14
(N=3655)
2014-15
(N=3427)
2015-16
(N=3602)
2016-17
(N=3227)
2017-18
(N=2729)
2018-19
(N=2443)
2019-20
(N=2049)
2020-21
(N=1626)
2021-22
(N=1719)
2022-23
(N=1552)
2023-24
(N=1400)
Overall
(N=45814)
age.group
10-12 2427 (49.5%) 2485 (49.6%) 2185 (49.4%) 1945 (48.1%) 1781 (48.7%) 1599 (46.7%) 1811 (50.3%) 1589 (49.2%) 1391 (51.0%) 1197 (49.0%) 1005 (49.0%) 800 (49.2%) 823 (47.9%) 758 (48.8%) 694 (49.6%) 22490 (49.1%)
13-15 2472 (50.5%) 2530 (50.4%) 2242 (50.6%) 2099 (51.9%) 1874 (51.3%) 1828 (53.3%) 1791 (49.7%) 1638 (50.8%) 1338 (49.0%) 1246 (51.0%) 1044 (51.0%) 826 (50.8%) 896 (52.1%) 794 (51.2%) 706 (50.4%) 23324 (50.9%)
sex_dv
inconsistent 2 (0.0%) 2 (0.0%) 0 (0%) 1 (0.0%) 2 (0.1%) 1 (0.0%) 1 (0.0%) 0 (0%) 2 (0.1%) 0 (0%) 1 (0.0%) 0 (0%) 1 (0.1%) 0 (0%) 0 (0%) 13 (0.0%)
Male 2435 (49.7%) 2529 (50.4%) 2221 (50.2%) 2040 (50.4%) 1855 (50.8%) 1736 (50.7%) 1787 (49.6%) 1598 (49.5%) 1356 (49.7%) 1196 (49.0%) 1012 (49.4%) 813 (50.0%) 812 (47.2%) 717 (46.2%) 672 (48.0%) 22779 (49.7%)
Female 2462 (50.3%) 2484 (49.5%) 2206 (49.8%) 2003 (49.5%) 1798 (49.2%) 1690 (49.3%) 1814 (50.4%) 1629 (50.5%) 1371 (50.2%) 1247 (51.0%) 1036 (50.6%) 813 (50.0%) 906 (52.7%) 835 (53.8%) 728 (52.0%) 23022 (50.3%)
ethnicity
British or Irish 3463 (70.7%) 3873 (77.2%) 3402 (76.8%) 3071 (75.9%) 2759 (75.5%) 2577 (75.2%) 2439 (67.7%) 2194 (68.0%) 1913 (70.1%) 1651 (67.6%) 1483 (72.4%) 1145 (70.4%) 1208 (70.3%) 1100 (70.9%) 949 (67.8%) 33227 (72.5%)
Any other white background 81 (1.7%) 73 (1.5%) 62 (1.4%) 59 (1.5%) 55 (1.5%) 51 (1.5%) 62 (1.7%) 65 (2.0%) 52 (1.9%) 54 (2.2%) 51 (2.5%) 34 (2.1%) 42 (2.4%) 51 (3.3%) 49 (3.5%) 841 (1.8%)
South or East Asian 637 (13.0%) 499 (10.0%) 469 (10.6%) 458 (11.3%) 425 (11.6%) 417 (12.2%) 591 (16.4%) 527 (16.3%) 410 (15.0%) 408 (16.7%) 272 (13.3%) 237 (14.6%) 248 (14.4%) 205 (13.2%) 215 (15.4%) 6018 (13.1%)
African or Caribbean 327 (6.7%) 229 (4.6%) 205 (4.6%) 180 (4.5%) 170 (4.7%) 153 (4.5%) 216 (6.0%) 177 (5.5%) 137 (5.0%) 109 (4.5%) 63 (3.1%) 55 (3.4%) 57 (3.3%) 54 (3.5%) 29 (2.1%) 2161 (4.7%)
Mixed background 244 (5.0%) 197 (3.9%) 180 (4.1%) 169 (4.2%) 167 (4.6%) 154 (4.5%) 211 (5.9%) 177 (5.5%) 164 (6.0%) 145 (5.9%) 133 (6.5%) 125 (7.7%) 123 (7.2%) 104 (6.7%) 92 (6.6%) 2385 (5.2%)
Other 146 (3.0%) 129 (2.6%) 107 (2.4%) 99 (2.4%) 78 (2.1%) 66 (1.9%) 78 (2.2%) 78 (2.4%) 47 (1.7%) 64 (2.6%) 38 (1.9%) 28 (1.7%) 35 (2.0%) 29 (1.9%) 42 (3.0%) 1064 (2.3%)
Missing 1 (0.0%) 15 (0.3%) 2 (0.0%) 8 (0.2%) 1 (0.0%) 9 (0.3%) 5 (0.1%) 9 (0.3%) 6 (0.2%) 12 (0.5%) 9 (0.4%) 2 (0.1%) 6 (0.3%) 9 (0.6%) 24 (1.7%) 118 (0.3%)
hsdincome
Mean (SD) 2900 (1960) 3110 (2200) 3300 (2290) 3350 (2250) 3390 (2140) 3660 (4200) 3780 (12300) 3870 (3550) 3780 (2500) 3920 (2460) 4070 (2320) 4290 (2890) 4220 (2750) 4550 (3180) 5010 (3150) 3610 (4320)
Median [Min, Max] 2480 [-777, 27000] 2700 [-1630, 47300] 2900 [-5390, 45300] 2940 [-991, 44700] 3020 [0, 51300] 3110 [-9.00, 198000] 3130 [-3190, 724000] 3240 [0, 58000] 3340 [-452, 59200] 3470 [0, 29800] 3640 [-451, 23700] 3830 [91.7, 42300] 3750 [0, 43500] 3980 [-510, 45000] 4490 [-419, 46300] 3100 [-5390, 724000]
equivinc
Mean (SD) 1240 (820) 1330 (900) 1400 (971) 1420 (977) 1430 (888) 1540 (1740) 1560 (3680) 1620 (1440) 1600 (1080) 1630 (1010) 1720 (956) 1830 (1200) 1790 (1200) 1940 (1350) 2140 (1260) 1530 (1500)
Median [Min, Max] 1070 [-565, 12500] 1150 [-494, 20600] 1230 [-2240, 19700] 1240 [-431, 27900] 1260 [0, 20500] 1310 [-1430, 79200] 1300 [-1770, 213000] 1370 [-938, 24400] 1410 [-181, 28200] 1430 [-209, 12900] 1520 [-399, 8690] 1650 [70.6, 16900] 1580 [-2340, 21800] 1700 [-182, 17300] 1950 [-343, 16500] 1310 [-2340, 213000]
country
England 4145 (84.6%) 3792 (75.6%) 3408 (77.0%) 3131 (77.4%) 2922 (79.9%) 2694 (78.6%) 2971 (82.5%) 2618 (81.1%) 2233 (81.8%) 2032 (83.2%) 1673 (81.6%) 1369 (84.2%) 1411 (82.1%) 1284 (82.7%) 1177 (84.1%) 36860 (80.5%)
Wales 221 (4.5%) 353 (7.0%) 303 (6.8%) 271 (6.7%) 186 (5.1%) 174 (5.1%) 139 (3.9%) 144 (4.5%) 128 (4.7%) 112 (4.6%) 96 (4.7%) 78 (4.8%) 84 (4.9%) 55 (3.5%) 59 (4.2%) 2403 (5.2%)
Scotland 321 (6.6%) 448 (8.9%) 381 (8.6%) 357 (8.8%) 284 (7.8%) 292 (8.5%) 285 (7.9%) 267 (8.3%) 219 (8.0%) 186 (7.6%) 156 (7.6%) 117 (7.2%) 139 (8.1%) 122 (7.9%) 129 (9.2%) 3703 (8.1%)
Northern Ireland 212 (4.3%) 414 (8.3%) 334 (7.5%) 284 (7.0%) 260 (7.1%) 265 (7.7%) 205 (5.7%) 198 (6.1%) 148 (5.4%) 109 (4.5%) 123 (6.0%) 62 (3.8%) 85 (4.9%) 91 (5.9%) 35 (2.5%) 2825 (6.2%)
Missing 0 (0%) 8 (0.2%) 1 (0.0%) 1 (0.0%) 3 (0.1%) 2 (0.1%) 2 (0.1%) 0 (0%) 1 (0.0%) 4 (0.2%) 1 (0.0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 23 (0.1%)
h.life.c
Mean (SD) 1.90 (1.18) 1.94 (1.11) 1.94 (1.13) 1.91 (1.13) 1.87 (1.19) 1.86 (1.19) 1.84 (1.23) 1.80 (1.21) 1.76 (1.21) 1.71 (1.26) 1.62 (1.27) 1.61 (1.28) 1.57 (1.31) 1.54 (1.27) 1.56 (1.25) 1.82 (1.20)
Median [Min, Max] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00]
Missing 40 (0.8%) 44 (0.9%) 46 (1.0%) 29 (0.7%) 63 (1.7%) 51 (1.5%) 37 (1.0%) 27 (0.8%) 25 (0.9%) 16 (0.7%) 24 (1.2%) 12 (0.7%) 22 (1.3%) 15 (1.0%) 15 (1.1%) 466 (1.0%)
doby_dv.n
Mean (SD) 2000 (1.84) 2000 (1.81) 2000 (1.83) 2000 (1.84) 2000 (1.82) 2000 (1.86) 2000 (1.83) 2000 (1.87) 2000 (1.82) 2010 (1.81) 2010 (1.80) 2010 (1.80) 2010 (1.86) 2010 (1.86) 2010 (1.82) 2000 (4.43)
Median [Min, Max] 2000 [1990, 2000] 2000 [1990, 2000] 2000 [1990, 2000] 2000 [2000, 2000] 2000 [2000, 2000] 2000 [2000, 2010] 2000 [2000, 2010] 2000 [2000, 2010] 2010 [2000, 2010] 2010 [2000, 2010] 2010 [2000, 2010] 2010 [2000, 2010] 2010 [2010, 2010] 2010 [2010, 2010] 2010 [2010, 2010] 2000 [1990, 2010]
Missing 3 (0.1%) 0 (0%) 1 (0.0%) 1 (0.0%) 0 (0%) 0 (0%) 1 (0.0%) 0 (0%) 0 (0%) 2 (0.1%) 1 (0.0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 9 (0.0%)
# ... and by calendar year
table1(~age.group + sex_dv + ethnicity + hsdincome + equivinc  + country + h.life.c + doby_dv.n | int.year.sched, data=usoc) 
2009
(N=2578)
2010
(N=5361)
2011
(N=4657)
2012
(N=4157)
2013
(N=3888)
2014
(N=3612)
2015
(N=3225)
2016
(N=3418)
2017
(N=3024)
2018
(N=2490)
2019
(N=2377)
2020
(N=1662)
2021
(N=1683)
2022
(N=1577)
2023
(N=1349)
2024
(N=756)
Overall
(N=45814)
age.group
10-12 1298 (50.3%) 2626 (49.0%) 2312 (49.6%) 1994 (48.0%) 1909 (49.1%) 1710 (47.3%) 1598 (49.6%) 1678 (49.1%) 1534 (50.7%) 1231 (49.4%) 1162 (48.9%) 818 (49.2%) 820 (48.7%) 776 (49.2%) 646 (47.9%) 378 (50.0%) 22490 (49.1%)
13-15 1280 (49.7%) 2735 (51.0%) 2345 (50.4%) 2163 (52.0%) 1979 (50.9%) 1902 (52.7%) 1627 (50.4%) 1740 (50.9%) 1490 (49.3%) 1259 (50.6%) 1215 (51.1%) 844 (50.8%) 863 (51.3%) 801 (50.8%) 703 (52.1%) 378 (50.0%) 23324 (50.9%)
sex_dv
inconsistent 2 (0.1%) 2 (0.0%) 0 (0%) 1 (0.0%) 1 (0.0%) 2 (0.1%) 1 (0.0%) 0 (0%) 1 (0.0%) 1 (0.0%) 1 (0.0%) 0 (0%) 1 (0.1%) 0 (0%) 0 (0%) 0 (0%) 13 (0.0%)
Male 1295 (50.2%) 2707 (50.5%) 2344 (50.3%) 2067 (49.7%) 1967 (50.6%) 1844 (51.1%) 1609 (49.9%) 1687 (49.4%) 1502 (49.7%) 1226 (49.2%) 1163 (48.9%) 830 (49.9%) 804 (47.8%) 748 (47.4%) 625 (46.3%) 361 (47.8%) 22779 (49.7%)
Female 1281 (49.7%) 2652 (49.5%) 2313 (49.7%) 2089 (50.3%) 1920 (49.4%) 1766 (48.9%) 1615 (50.1%) 1731 (50.6%) 1521 (50.3%) 1263 (50.7%) 1213 (51.0%) 832 (50.1%) 878 (52.2%) 829 (52.6%) 724 (53.7%) 395 (52.2%) 23022 (50.3%)
ethnicity
British or Irish 1876 (72.8%) 4072 (76.0%) 3580 (76.9%) 3172 (76.3%) 2921 (75.1%) 2725 (75.4%) 2407 (74.6%) 2300 (67.3%) 2037 (67.4%) 1698 (68.2%) 1605 (67.5%) 1172 (70.5%) 1208 (71.8%) 1088 (69.0%) 922 (68.3%) 444 (58.7%) 33227 (72.5%)
Any other white background 45 (1.7%) 71 (1.3%) 69 (1.5%) 60 (1.4%) 56 (1.4%) 53 (1.5%) 42 (1.3%) 64 (1.9%) 65 (2.1%) 50 (2.0%) 60 (2.5%) 39 (2.3%) 39 (2.3%) 50 (3.2%) 44 (3.3%) 34 (4.5%) 841 (1.8%)
South or East Asian 310 (12.0%) 560 (10.4%) 472 (10.1%) 449 (10.8%) 463 (11.9%) 413 (11.4%) 414 (12.8%) 573 (16.8%) 507 (16.8%) 394 (15.8%) 389 (16.4%) 243 (14.6%) 240 (14.3%) 230 (14.6%) 204 (15.1%) 157 (20.8%) 6018 (13.1%)
African or Caribbean 157 (6.1%) 274 (5.1%) 221 (4.7%) 194 (4.7%) 180 (4.6%) 176 (4.9%) 136 (4.2%) 194 (5.7%) 170 (5.6%) 125 (5.0%) 110 (4.6%) 53 (3.2%) 50 (3.0%) 59 (3.7%) 41 (3.0%) 21 (2.8%) 2161 (4.7%)
Mixed background 115 (4.5%) 230 (4.3%) 195 (4.2%) 171 (4.1%) 178 (4.6%) 161 (4.5%) 165 (5.1%) 203 (5.9%) 167 (5.5%) 166 (6.7%) 146 (6.1%) 117 (7.0%) 115 (6.8%) 110 (7.0%) 89 (6.6%) 57 (7.5%) 2385 (5.2%)
Other 74 (2.9%) 142 (2.6%) 115 (2.5%) 106 (2.6%) 87 (2.2%) 77 (2.1%) 56 (1.7%) 76 (2.2%) 70 (2.3%) 51 (2.0%) 52 (2.2%) 34 (2.0%) 26 (1.5%) 35 (2.2%) 30 (2.2%) 33 (4.4%) 1064 (2.3%)
Missing 1 (0.0%) 12 (0.2%) 5 (0.1%) 5 (0.1%) 3 (0.1%) 7 (0.2%) 5 (0.2%) 8 (0.2%) 8 (0.3%) 6 (0.2%) 15 (0.6%) 4 (0.2%) 5 (0.3%) 5 (0.3%) 19 (1.4%) 10 (1.3%) 118 (0.3%)
hsdincome
Mean (SD) 2870 (1910) 3000 (2010) 3210 (2180) 3340 (2380) 3360 (2060) 3630 (4220) 3600 (2150) 3860 (12600) 3920 (3640) 3870 (2650) 3950 (2270) 4230 (2790) 4230 (2840) 4310 (2640) 4740 (3140) 5260 (3620) 3610 (4320)
Median [Min, Max] 2450 [-777, 22500] 2620 [-1630, 34500] 2790 [-5390, 47300] 2950 [-2510, 45300] 2990 [-991, 44700] 3080 [-9.00, 198000] 3190 [-3190, 27200] 3150 [0, 724000] 3290 [0, 58000] 3390 [-452, 59200] 3540 [-451, 24700] 3790 [259, 42300] 3730 [0, 43500] 3900 [-510, 29300] 4230 [-419, 45000] 4560 [-118, 46300] 3100 [-5390, 724000]
equivinc
Mean (SD) 1230 (815) 1290 (809) 1370 (946) 1420 (1020) 1420 (849) 1530 (1750) 1520 (908) 1590 (3780) 1640 (1470) 1630 (1130) 1650 (954) 1800 (1170) 1800 (1200) 1840 (1150) 2020 (1290) 2220 (1430) 1530 (1500)
Median [Min, Max] 1060 [-296, 12500] 1120 [-565, 12900] 1190 [-2240, 20600] 1240 [-1090, 27900] 1250 [-431, 19400] 1300 [-1430, 79200] 1330 [-1770, 12700] 1320 [-536, 213000] 1390 [-938, 24400] 1420 [-209, 28200] 1450 [-399, 11700] 1620 [123, 16900] 1590 [0, 21800] 1650 [-2340, 13900] 1830 [-343, 17300] 2000 [-35.6, 16500] 1310 [-2340, 213000]
country
England 2086 (80.9%) 4091 (76.3%) 3597 (77.2%) 3240 (77.9%) 3102 (79.8%) 2864 (79.3%) 2604 (80.7%) 2795 (81.8%) 2525 (83.5%) 2062 (82.8%) 1964 (82.6%) 1409 (84.8%) 1379 (81.9%) 1313 (83.3%) 1135 (84.1%) 694 (91.8%) 36860 (80.5%)
Wales 102 (4.0%) 372 (6.9%) 323 (6.9%) 285 (6.9%) 218 (5.6%) 178 (4.9%) 144 (4.5%) 147 (4.3%) 125 (4.1%) 115 (4.6%) 110 (4.6%) 76 (4.6%) 82 (4.9%) 53 (3.4%) 57 (4.2%) 16 (2.1%) 2403 (5.2%)
Scotland 178 (6.9%) 478 (8.9%) 400 (8.6%) 347 (8.3%) 306 (7.9%) 302 (8.4%) 272 (8.4%) 276 (8.1%) 226 (7.5%) 201 (8.1%) 179 (7.5%) 115 (6.9%) 136 (8.1%) 119 (7.5%) 122 (9.0%) 46 (6.1%) 3703 (8.1%)
Northern Ireland 212 (8.2%) 414 (7.7%) 334 (7.2%) 284 (6.8%) 260 (6.7%) 265 (7.3%) 204 (6.3%) 199 (5.8%) 148 (4.9%) 109 (4.4%) 121 (5.1%) 62 (3.7%) 86 (5.1%) 92 (5.8%) 35 (2.6%) 0 (0%) 2825 (6.2%)
Missing 0 (0%) 6 (0.1%) 3 (0.1%) 1 (0.0%) 2 (0.1%) 3 (0.1%) 1 (0.0%) 1 (0.0%) 0 (0%) 3 (0.1%) 3 (0.1%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 23 (0.1%)
h.life.c
Mean (SD) 1.89 (1.20) 1.93 (1.14) 1.94 (1.12) 1.92 (1.11) 1.90 (1.18) 1.86 (1.18) 1.84 (1.22) 1.82 (1.22) 1.81 (1.19) 1.70 (1.28) 1.67 (1.26) 1.61 (1.26) 1.57 (1.30) 1.54 (1.30) 1.57 (1.25) 1.55 (1.27) 1.82 (1.20)
Median [Min, Max] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00] 2.00 [-3.00, 3.00]
Missing 11 (0.4%) 55 (1.0%) 46 (1.0%) 32 (0.8%) 54 (1.4%) 60 (1.7%) 29 (0.9%) 33 (1.0%) 27 (0.9%) 24 (1.0%) 25 (1.1%) 11 (0.7%) 19 (1.1%) 22 (1.4%) 6 (0.4%) 12 (1.6%) 466 (1.0%)
doby_dv.n
Mean (SD) 2000 (1.77) 2000 (1.75) 2000 (1.76) 2000 (1.76) 2000 (1.76) 2000 (1.77) 2000 (1.78) 2000 (1.77) 2000 (1.76) 2010 (1.76) 2010 (1.75) 2010 (1.74) 2010 (1.76) 2010 (1.77) 2010 (1.78) 2010 (1.80) 2000 (4.43)
Median [Min, Max] 2000 [1990, 2000] 2000 [1990, 2000] 2000 [1990, 2000] 2000 [2000, 2000] 2000 [2000, 2000] 2000 [2000, 2010] 2000 [2000, 2010] 2000 [2000, 2010] 2000 [2000, 2010] 2010 [2000, 2010] 2010 [2000, 2010] 2010 [2000, 2010] 2010 [2010, 2010] 2010 [2010, 2010] 2010 [2010, 2010] 2010 [2010, 2010] 2000 [1990, 2010]
Missing 2 (0.1%) 1 (0.0%) 1 (0.0%) 1 (0.0%) 0 (0%) 0 (0%) 0 (0%) 1 (0.0%) 0 (0%) 0 (0%) 3 (0.1%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 0 (0%) 9 (0.0%)
# list number of *unique individuals* per calendar year *with data* on all satisfaction items
nbyyear <- usoc[!is.na(usoc$h.life.c) & !is.na(usoc$h.school.c) & !is.na(usoc$h.schoolwork.c) & !is.na(usoc$h.fam.c) & !is.na(usoc$h.friends.c) & !is.na(usoc$h.appear.c),] %>%
  group_by(int.year.sched) %>%
  distinct(pidp, .keep_all = T) %>%
  summarise(n=n()) %>%
  ungroup()


ggplot(data=nbyyear, aes(x=int.year.sched, y=n))+
  geom_col()+
  labs(title = "Total N per calendar year")

  theme(axis.text.x = element_text(angle=30))
## <theme> List of 1
##  $ axis.text.x: <ggplot2::element_text>
##   ..@ family       : NULL
##   ..@ face         : NULL
##   ..@ italic       : chr NA
##   ..@ fontweight   : num NA
##   ..@ fontwidth    : num NA
##   ..@ colour       : NULL
##   ..@ size         : NULL
##   ..@ hjust        : NULL
##   ..@ vjust        : NULL
##   ..@ angle        : num 30
##   ..@ lineheight   : NULL
##   ..@ margin       : NULL
##   ..@ debug        : NULL
##   ..@ inherit.blank: logi FALSE
##  @ complete: logi FALSE
##  @ validate: logi TRUE
# also check N per year with SDQ data
nbyyear <- usoc[!is.na(usoc$ypsdqtd_dv),] %>%
  group_by(int.year.sched) %>%
  distinct(pidp, .keep_all = T) %>%
  summarise(n=n()) %>%
  ungroup()

ggplot(data=nbyyear, aes(x=int.year.sched, y=n))+
  geom_col()+
  labs(title = "N per calendar year with SDQ")+
  theme(axis.text.x = element_text(angle=30))

Note dropping N over time. Sampling weights used to account for non-randomly distributed attrition.

# tabulate unchanging features of participants
table1(~sex +  dob + country + ethnic + age_atfirst + num.rows, data=pidp.list )
Overall
(N=16287)
sex
inconsistent 6 (0.0%)
male 8153 (50.1%)
female 8128 (49.9%)
dob
Mean (SD) 2000 (5.18)
Median [Min, Max] 2000 [1990, 2010]
Missing 5 (0.0%)
country
England 13089 (80.4%)
Wales 907 (5.6%)
Scotland 1291 (7.9%)
Northern Ireland 992 (6.1%)
Missing 8 (0.0%)
ethnic
British or Irish 11341 (69.6%)
Any other white background 336 (2.1%)
South or East Asian 859 (5.3%)
African or Caribbean 2273 (14.0%)
Mixed background 952 (5.8%)
Other 432 (2.7%)
Missing 94 (0.6%)
age_atfirst
Mean (SD) 12.5 (1.76)
Median [Min, Max] 13.0 [10.0, 16.0]
Missing 2 (0.0%)
num.rows
Mean (SD) 2.82 (1.67)
Median [Min, Max] 2.00 [1.00, 7.00]
# something strange happenining with the dob variable-- the min year of birth should be 1993, not 1990.

# calculate number and proportion of :

## males and females
usoc %>%
  distinct(pidp, .keep_all = T) %>%
  group_by(sex_dv) %>%
  summarise(n=n()) %>%
  mutate(tot.n = sum(n),
         prop = n/tot.n)%>%
  ungroup()
## # A tibble: 3 × 4
##   sex_dv           n tot.n     prop
##   <fct>        <int> <int>    <dbl>
## 1 inconsistent     6 16280 0.000369
## 2 Male          8150 16280 0.501   
## 3 Female        8124 16280 0.499
## from England, Scotland, Wales & NI
usoc %>%
  distinct(pidp, .keep_all = T) %>%
  group_by(country) %>%
  summarise(n=n()) %>%
  mutate(tot.n = sum(n),
         prop = n/tot.n)%>%
  ungroup()
## # A tibble: 5 × 4
##   country              n tot.n     prop
##   <fct>            <int> <int>    <dbl>
## 1 England          13082 16280 0.804   
## 2 Wales              907 16280 0.0557  
## 3 Scotland          1291 16280 0.0793  
## 4 Northern Ireland   992 16280 0.0609  
## 5 <NA>                 8 16280 0.000491
# observe number of participants from *same* origin household
osm.list <- usoc %>%
  distinct(pidp, .keep_all = T) %>%
  group_by(osm_hh) %>%
  summarise(n=n()) %>%
  ungroup()

Explore specific variables

Time

We use the scheduled (sampling) month/year as the measure of calender year. This is to avoid including the same individual twice in the one year (which happened when actual year of interview would happen e.g. Jan 2017 & Dec 2017; >100 participants had observations ~11 months apart, who would be doubly represented)

E.g. if a hsd is scheduled to be interviewed Nov 2009 (and Nov every year) but they are 2 months late completing their interview (actually doing it in Jan 2010), their next interview will come around again Nov 2010, and they may be counted twice if we used actual year of interview.

# make sure each pidp has only been included once per year
df <- data.frame(year = sort(unique(usoc$int.year.sched)), 
                 num.dbls = NA, 
                 pidps = NA)

dup.pidps <- c()
for (y in sort(unique(usoc$int.year.sched)) )
  if (sum(table(usoc$pidp[usoc$int.year.sched==y])>1)>0) {
    tmp <- usoc[usoc$int.year.sched==y,]
    df$num.dbls[df$year==y] <- length(tmp$pidp[duplicated(tmp$pidp)])
    df$pidps[df$year==y] <- toString(tmp$pidp[duplicated(tmp$pidp)])
    
    dup.pidps <- unique(c(dup.pidps, tmp$pidp[duplicated(tmp$pidp)]))
  }

# look at full data for these participnats (not all from NI)
tmp <- usoc[is.element(usoc$pidp,dup.pidps),]

Time of youth survey “Scheduled interview date” may not always be the same date the youth (aged 10-15) filled in the survey. Its the date the adult respondent in the hsd was scheduled to be interviewed.

The actual interview date may not even be the youth survey completion date… intdatm_dv: “this is the date the personal interview of adult respondents took place. If all interviews in the household took place on the same day, all non-respondents (and youth respondents for whom no interview date is recorded) received the other household members’ interview date.” For interviews that are held in-person, the YP would put it in an envelope hand the survey back on the same day they were there interviewing. In those cases, the HSD interview date is an accurate reflection of youth survey completion. For remote interviews the YP would post the survey back to the Usoc team, which could be delayed by several weeks.

“For each sample month (e.g. a_month), interviews (e.g. intdatm_dv) take place over 3-4 months, but the majority of interviews take place in the calendar month coinciding with the sample month.”

Weights

## EXPLORE WEIGHTS
# check number of 0 weights per year
table(usoc$x_wgt==0, usoc$int.year.sched)
##        
##         2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022
##   FALSE 2568 5340 4635 4145 3871 3241 3079 3399 3012 2476 2364 1655 1678 1573
##   TRUE    10   21   22   12   17  371  146   19   12   14   13    7    5    4
##        
##         2023 2024
##   FALSE 1349  754
##   TRUE     0    2
# check mean and SD of weights in first wave
summary(usoc$x_wgt[usoc$wave=="a"])
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  0.0000  0.6003  1.1013  0.9955  1.3256  3.4091
sd(usoc$x_wgt[usoc$wave=="a"])
## [1] 0.4517437
# weights have a mean of 0 (or close) and a SD of 0.45 

summary(usoc$x_wgt[usoc$wave=="c"])
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  0.0000  0.5694  1.0333  0.9959  1.3502  2.4254
sd(usoc$x_wgt[usoc$wave=="c"])
## [1] 0.4862356
# sum of the weights in wave A should approximate N...
sum(usoc$x_wgt[usoc$wave=="a"]) # 4877
## [1] 4877
# number of unique participants in wave A?
length(unique(usoc$pidp[usoc$wave=="a"]))  # 4899
## [1] 4899
# shouldnt they add up to the same total N? maybe 22 individuals were missing basic info to "weight" on.
# maybe 22 participants were given a zero weight? -- yes that's it: 
tmp[usoc$x_wgt==0 & usoc$wave=="a", ]
##       pidp hidp osm_hh hsdincome x_wgt hh_wgt wave month int.mth.sched
## NA      NA   NA     NA        NA    NA     NA <NA>  <NA>          <NA>
## NA.1    NA   NA     NA        NA    NA     NA <NA>  <NA>          <NA>
## NA.2    NA   NA     NA        NA    NA     NA <NA>  <NA>          <NA>
## NA.3    NA   NA     NA        NA    NA     NA <NA>  <NA>          <NA>
## NA.4    NA   NA     NA        NA    NA     NA <NA>  <NA>          <NA>
## NA.5    NA   NA     NA        NA    NA     NA <NA>  <NA>          <NA>
## NA.6    NA   NA     NA        NA    NA     NA <NA>  <NA>          <NA>
## NA.7    NA   NA     NA        NA    NA     NA <NA>  <NA>          <NA>
## NA.8    NA   NA     NA        NA    NA     NA <NA>  <NA>          <NA>
## NA.9    NA   NA     NA        NA    NA     NA <NA>  <NA>          <NA>
## NA.10   NA   NA     NA        NA    NA     NA <NA>  <NA>          <NA>
## NA.11   NA   NA     NA        NA    NA     NA <NA>  <NA>          <NA>
## NA.12   NA   NA     NA        NA    NA     NA <NA>  <NA>          <NA>
## NA.13   NA   NA     NA        NA    NA     NA <NA>  <NA>          <NA>
## NA.14   NA   NA     NA        NA    NA     NA <NA>  <NA>          <NA>
## NA.15   NA   NA     NA        NA    NA     NA <NA>  <NA>          <NA>
## NA.16   NA   NA     NA        NA    NA     NA <NA>  <NA>          <NA>
## NA.17   NA   NA     NA        NA    NA     NA <NA>  <NA>          <NA>
## NA.18   NA   NA     NA        NA    NA     NA <NA>  <NA>          <NA>
## NA.19   NA   NA     NA        NA    NA     NA <NA>  <NA>          <NA>
## NA.20   NA   NA     NA        NA    NA     NA <NA>  <NA>          <NA>
## NA.21   NA   NA     NA        NA    NA     NA <NA>  <NA>          <NA>
##       int.year.sched intdatm_dv intdaty_dv interview.delay.y  psu strata dvage
## NA                NA       <NA>       <NA>                NA <NA>   <NA>  <NA>
## NA.1              NA       <NA>       <NA>                NA <NA>   <NA>  <NA>
## NA.2              NA       <NA>       <NA>                NA <NA>   <NA>  <NA>
## NA.3              NA       <NA>       <NA>                NA <NA>   <NA>  <NA>
## NA.4              NA       <NA>       <NA>                NA <NA>   <NA>  <NA>
## NA.5              NA       <NA>       <NA>                NA <NA>   <NA>  <NA>
## NA.6              NA       <NA>       <NA>                NA <NA>   <NA>  <NA>
## NA.7              NA       <NA>       <NA>                NA <NA>   <NA>  <NA>
## NA.8              NA       <NA>       <NA>                NA <NA>   <NA>  <NA>
## NA.9              NA       <NA>       <NA>                NA <NA>   <NA>  <NA>
## NA.10             NA       <NA>       <NA>                NA <NA>   <NA>  <NA>
## NA.11             NA       <NA>       <NA>                NA <NA>   <NA>  <NA>
## NA.12             NA       <NA>       <NA>                NA <NA>   <NA>  <NA>
## NA.13             NA       <NA>       <NA>                NA <NA>   <NA>  <NA>
## NA.14             NA       <NA>       <NA>                NA <NA>   <NA>  <NA>
## NA.15             NA       <NA>       <NA>                NA <NA>   <NA>  <NA>
## NA.16             NA       <NA>       <NA>                NA <NA>   <NA>  <NA>
## NA.17             NA       <NA>       <NA>                NA <NA>   <NA>  <NA>
## NA.18             NA       <NA>       <NA>                NA <NA>   <NA>  <NA>
## NA.19             NA       <NA>       <NA>                NA <NA>   <NA>  <NA>
## NA.20             NA       <NA>       <NA>                NA <NA>   <NA>  <NA>
## NA.21             NA       <NA>       <NA>                NA <NA>   <NA>  <NA>
##       ypdoby doby_dv  sex ypsex sex_dv bsbx_N hsbx_N asbx_N ssbx_N fsbx_N
## NA        NA    <NA> <NA>  <NA>   <NA>     NA     NA     NA     NA     NA
## NA.1      NA    <NA> <NA>  <NA>   <NA>     NA     NA     NA     NA     NA
## NA.2      NA    <NA> <NA>  <NA>   <NA>     NA     NA     NA     NA     NA
## NA.3      NA    <NA> <NA>  <NA>   <NA>     NA     NA     NA     NA     NA
## NA.4      NA    <NA> <NA>  <NA>   <NA>     NA     NA     NA     NA     NA
## NA.5      NA    <NA> <NA>  <NA>   <NA>     NA     NA     NA     NA     NA
## NA.6      NA    <NA> <NA>  <NA>   <NA>     NA     NA     NA     NA     NA
## NA.7      NA    <NA> <NA>  <NA>   <NA>     NA     NA     NA     NA     NA
## NA.8      NA    <NA> <NA>  <NA>   <NA>     NA     NA     NA     NA     NA
## NA.9      NA    <NA> <NA>  <NA>   <NA>     NA     NA     NA     NA     NA
## NA.10     NA    <NA> <NA>  <NA>   <NA>     NA     NA     NA     NA     NA
## NA.11     NA    <NA> <NA>  <NA>   <NA>     NA     NA     NA     NA     NA
## NA.12     NA    <NA> <NA>  <NA>   <NA>     NA     NA     NA     NA     NA
## NA.13     NA    <NA> <NA>  <NA>   <NA>     NA     NA     NA     NA     NA
## NA.14     NA    <NA> <NA>  <NA>   <NA>     NA     NA     NA     NA     NA
## NA.15     NA    <NA> <NA>  <NA>   <NA>     NA     NA     NA     NA     NA
## NA.16     NA    <NA> <NA>  <NA>   <NA>     NA     NA     NA     NA     NA
## NA.17     NA    <NA> <NA>  <NA>   <NA>     NA     NA     NA     NA     NA
## NA.18     NA    <NA> <NA>  <NA>   <NA>     NA     NA     NA     NA     NA
## NA.19     NA    <NA> <NA>  <NA>   <NA>     NA     NA     NA     NA     NA
## NA.20     NA    <NA> <NA>  <NA>   <NA>     NA     NA     NA     NA     NA
## NA.21     NA    <NA> <NA>  <NA>   <NA>     NA     NA     NA     NA     NA
##       ethn_dv country gor_dv urban_dv hhorig ypsocweb yphsw yphap yphfm yphfr
## NA       <NA>    <NA>   <NA>     <NA>   <NA>     <NA>    NA    NA    NA    NA
## NA.1     <NA>    <NA>   <NA>     <NA>   <NA>     <NA>    NA    NA    NA    NA
## NA.2     <NA>    <NA>   <NA>     <NA>   <NA>     <NA>    NA    NA    NA    NA
## NA.3     <NA>    <NA>   <NA>     <NA>   <NA>     <NA>    NA    NA    NA    NA
## NA.4     <NA>    <NA>   <NA>     <NA>   <NA>     <NA>    NA    NA    NA    NA
## NA.5     <NA>    <NA>   <NA>     <NA>   <NA>     <NA>    NA    NA    NA    NA
## NA.6     <NA>    <NA>   <NA>     <NA>   <NA>     <NA>    NA    NA    NA    NA
## NA.7     <NA>    <NA>   <NA>     <NA>   <NA>     <NA>    NA    NA    NA    NA
## NA.8     <NA>    <NA>   <NA>     <NA>   <NA>     <NA>    NA    NA    NA    NA
## NA.9     <NA>    <NA>   <NA>     <NA>   <NA>     <NA>    NA    NA    NA    NA
## NA.10    <NA>    <NA>   <NA>     <NA>   <NA>     <NA>    NA    NA    NA    NA
## NA.11    <NA>    <NA>   <NA>     <NA>   <NA>     <NA>    NA    NA    NA    NA
## NA.12    <NA>    <NA>   <NA>     <NA>   <NA>     <NA>    NA    NA    NA    NA
## NA.13    <NA>    <NA>   <NA>     <NA>   <NA>     <NA>    NA    NA    NA    NA
## NA.14    <NA>    <NA>   <NA>     <NA>   <NA>     <NA>    NA    NA    NA    NA
## NA.15    <NA>    <NA>   <NA>     <NA>   <NA>     <NA>    NA    NA    NA    NA
## NA.16    <NA>    <NA>   <NA>     <NA>   <NA>     <NA>    NA    NA    NA    NA
## NA.17    <NA>    <NA>   <NA>     <NA>   <NA>     <NA>    NA    NA    NA    NA
## NA.18    <NA>    <NA>   <NA>     <NA>   <NA>     <NA>    NA    NA    NA    NA
## NA.19    <NA>    <NA>   <NA>     <NA>   <NA>     <NA>    NA    NA    NA    NA
## NA.20    <NA>    <NA>   <NA>     <NA>   <NA>     <NA>    NA    NA    NA    NA
## NA.21    <NA>    <NA>   <NA>     <NA>   <NA>     <NA>    NA    NA    NA    NA
##       yphsc yphlf ypsdqa ypsdqb ypsdqc ypsdqd ypsdqe ypsdqf ypsdqg ypsdqh
## NA       NA    NA   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.1     NA    NA   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.2     NA    NA   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.3     NA    NA   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.4     NA    NA   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.5     NA    NA   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.6     NA    NA   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.7     NA    NA   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.8     NA    NA   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.9     NA    NA   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.10    NA    NA   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.11    NA    NA   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.12    NA    NA   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.13    NA    NA   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.14    NA    NA   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.15    NA    NA   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.16    NA    NA   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.17    NA    NA   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.18    NA    NA   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.19    NA    NA   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.20    NA    NA   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.21    NA    NA   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
##       ypsdqi ypsdqj ypsdqk ypsdql ypsdqm ypsdqn ypsdqo ypsdqp ypsdqq ypsdqr
## NA      <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.1    <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.2    <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.3    <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.4    <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.5    <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.6    <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.7    <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.8    <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.9    <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.10   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.11   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.12   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.13   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.14   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.15   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.16   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.17   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.18   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.19   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.20   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
## NA.21   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>
##       ypsdqs ypsdqt ypsdqu ypsdqv ypsdqw ypsdqx ypsdqy ypsdqes_dv ypsdqcp_dv
## NA      <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>         NA         NA
## NA.1    <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>         NA         NA
## NA.2    <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>         NA         NA
## NA.3    <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>         NA         NA
## NA.4    <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>         NA         NA
## NA.5    <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>         NA         NA
## NA.6    <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>         NA         NA
## NA.7    <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>         NA         NA
## NA.8    <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>         NA         NA
## NA.9    <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>         NA         NA
## NA.10   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>         NA         NA
## NA.11   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>         NA         NA
## NA.12   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>         NA         NA
## NA.13   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>         NA         NA
## NA.14   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>         NA         NA
## NA.15   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>         NA         NA
## NA.16   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>         NA         NA
## NA.17   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>         NA         NA
## NA.18   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>         NA         NA
## NA.19   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>         NA         NA
## NA.20   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>         NA         NA
## NA.21   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>   <NA>         NA         NA
##       ypsdqha_dv ypsdqpp_dv ypsdqps_dv ypsdqtd_dv fihhmnnet1_dv ieqmoecd_dv
## NA            NA         NA         NA         NA            NA          NA
## NA.1          NA         NA         NA         NA            NA          NA
## NA.2          NA         NA         NA         NA            NA          NA
## NA.3          NA         NA         NA         NA            NA          NA
## NA.4          NA         NA         NA         NA            NA          NA
## NA.5          NA         NA         NA         NA            NA          NA
## NA.6          NA         NA         NA         NA            NA          NA
## NA.7          NA         NA         NA         NA            NA          NA
## NA.8          NA         NA         NA         NA            NA          NA
## NA.9          NA         NA         NA         NA            NA          NA
## NA.10         NA         NA         NA         NA            NA          NA
## NA.11         NA         NA         NA         NA            NA          NA
## NA.12         NA         NA         NA         NA            NA          NA
## NA.13         NA         NA         NA         NA            NA          NA
## NA.14         NA         NA         NA         NA            NA          NA
## NA.15         NA         NA         NA         NA            NA          NA
## NA.16         NA         NA         NA         NA            NA          NA
## NA.17         NA         NA         NA         NA            NA          NA
## NA.18         NA         NA         NA         NA            NA          NA
## NA.19         NA         NA         NA         NA            NA          NA
## NA.20         NA         NA         NA         NA            NA          NA
## NA.21         NA         NA         NA         NA            NA          NA
##       doby_dv.n equivinc ethnicity h.schoolwork h.appear h.fam h.friends
## NA           NA       NA      <NA>           NA       NA    NA        NA
## NA.1         NA       NA      <NA>           NA       NA    NA        NA
## NA.2         NA       NA      <NA>           NA       NA    NA        NA
## NA.3         NA       NA      <NA>           NA       NA    NA        NA
## NA.4         NA       NA      <NA>           NA       NA    NA        NA
## NA.5         NA       NA      <NA>           NA       NA    NA        NA
## NA.6         NA       NA      <NA>           NA       NA    NA        NA
## NA.7         NA       NA      <NA>           NA       NA    NA        NA
## NA.8         NA       NA      <NA>           NA       NA    NA        NA
## NA.9         NA       NA      <NA>           NA       NA    NA        NA
## NA.10        NA       NA      <NA>           NA       NA    NA        NA
## NA.11        NA       NA      <NA>           NA       NA    NA        NA
## NA.12        NA       NA      <NA>           NA       NA    NA        NA
## NA.13        NA       NA      <NA>           NA       NA    NA        NA
## NA.14        NA       NA      <NA>           NA       NA    NA        NA
## NA.15        NA       NA      <NA>           NA       NA    NA        NA
## NA.16        NA       NA      <NA>           NA       NA    NA        NA
## NA.17        NA       NA      <NA>           NA       NA    NA        NA
## NA.18        NA       NA      <NA>           NA       NA    NA        NA
## NA.19        NA       NA      <NA>           NA       NA    NA        NA
## NA.20        NA       NA      <NA>           NA       NA    NA        NA
## NA.21        NA       NA      <NA>           NA       NA    NA        NA
##       h.school h.life h.schoolwork.c h.appear.c h.fam.c h.friends.c h.school.c
## NA          NA     NA             NA         NA      NA          NA         NA
## NA.1        NA     NA             NA         NA      NA          NA         NA
## NA.2        NA     NA             NA         NA      NA          NA         NA
## NA.3        NA     NA             NA         NA      NA          NA         NA
## NA.4        NA     NA             NA         NA      NA          NA         NA
## NA.5        NA     NA             NA         NA      NA          NA         NA
## NA.6        NA     NA             NA         NA      NA          NA         NA
## NA.7        NA     NA             NA         NA      NA          NA         NA
## NA.8        NA     NA             NA         NA      NA          NA         NA
## NA.9        NA     NA             NA         NA      NA          NA         NA
## NA.10       NA     NA             NA         NA      NA          NA         NA
## NA.11       NA     NA             NA         NA      NA          NA         NA
## NA.12       NA     NA             NA         NA      NA          NA         NA
## NA.13       NA     NA             NA         NA      NA          NA         NA
## NA.14       NA     NA             NA         NA      NA          NA         NA
## NA.15       NA     NA             NA         NA      NA          NA         NA
## NA.16       NA     NA             NA         NA      NA          NA         NA
## NA.17       NA     NA             NA         NA      NA          NA         NA
## NA.18       NA     NA             NA         NA      NA          NA         NA
## NA.19       NA     NA             NA         NA      NA          NA         NA
## NA.20       NA     NA             NA         NA      NA          NA         NA
## NA.21       NA     NA             NA         NA      NA          NA         NA
##       h.life.c unhappy.life unhappy.school unhappy.schoolwk unhappy.fam
## NA          NA           NA             NA               NA          NA
## NA.1        NA           NA             NA               NA          NA
## NA.2        NA           NA             NA               NA          NA
## NA.3        NA           NA             NA               NA          NA
## NA.4        NA           NA             NA               NA          NA
## NA.5        NA           NA             NA               NA          NA
## NA.6        NA           NA             NA               NA          NA
## NA.7        NA           NA             NA               NA          NA
## NA.8        NA           NA             NA               NA          NA
## NA.9        NA           NA             NA               NA          NA
## NA.10       NA           NA             NA               NA          NA
## NA.11       NA           NA             NA               NA          NA
## NA.12       NA           NA             NA               NA          NA
## NA.13       NA           NA             NA               NA          NA
## NA.14       NA           NA             NA               NA          NA
## NA.15       NA           NA             NA               NA          NA
## NA.16       NA           NA             NA               NA          NA
## NA.17       NA           NA             NA               NA          NA
## NA.18       NA           NA             NA               NA          NA
## NA.19       NA           NA             NA               NA          NA
## NA.20       NA           NA             NA               NA          NA
## NA.21       NA           NA             NA               NA          NA
##       unhappy.friends unhappy.appear sex.bin dvage.n socialmed wave.y wave.n
## NA                 NA             NA    <NA>      NA      <NA>   <NA>     NA
## NA.1               NA             NA    <NA>      NA      <NA>   <NA>     NA
## NA.2               NA             NA    <NA>      NA      <NA>   <NA>     NA
## NA.3               NA             NA    <NA>      NA      <NA>   <NA>     NA
## NA.4               NA             NA    <NA>      NA      <NA>   <NA>     NA
## NA.5               NA             NA    <NA>      NA      <NA>   <NA>     NA
## NA.6               NA             NA    <NA>      NA      <NA>   <NA>     NA
## NA.7               NA             NA    <NA>      NA      <NA>   <NA>     NA
## NA.8               NA             NA    <NA>      NA      <NA>   <NA>     NA
## NA.9               NA             NA    <NA>      NA      <NA>   <NA>     NA
## NA.10              NA             NA    <NA>      NA      <NA>   <NA>     NA
## NA.11              NA             NA    <NA>      NA      <NA>   <NA>     NA
## NA.12              NA             NA    <NA>      NA      <NA>   <NA>     NA
## NA.13              NA             NA    <NA>      NA      <NA>   <NA>     NA
## NA.14              NA             NA    <NA>      NA      <NA>   <NA>     NA
## NA.15              NA             NA    <NA>      NA      <NA>   <NA>     NA
## NA.16              NA             NA    <NA>      NA      <NA>   <NA>     NA
## NA.17              NA             NA    <NA>      NA      <NA>   <NA>     NA
## NA.18              NA             NA    <NA>      NA      <NA>   <NA>     NA
## NA.19              NA             NA    <NA>      NA      <NA>   <NA>     NA
## NA.20              NA             NA    <NA>      NA      <NA>   <NA>     NA
## NA.21              NA             NA    <NA>      NA      <NA>   <NA>     NA
##       age.group  gen bpx_N time.window age.3groups income.groups
## NA         <NA> <NA>    NA        <NA>        <NA>          <NA>
## NA.1       <NA> <NA>    NA        <NA>        <NA>          <NA>
## NA.2       <NA> <NA>    NA        <NA>        <NA>          <NA>
## NA.3       <NA> <NA>    NA        <NA>        <NA>          <NA>
## NA.4       <NA> <NA>    NA        <NA>        <NA>          <NA>
## NA.5       <NA> <NA>    NA        <NA>        <NA>          <NA>
## NA.6       <NA> <NA>    NA        <NA>        <NA>          <NA>
## NA.7       <NA> <NA>    NA        <NA>        <NA>          <NA>
## NA.8       <NA> <NA>    NA        <NA>        <NA>          <NA>
## NA.9       <NA> <NA>    NA        <NA>        <NA>          <NA>
## NA.10      <NA> <NA>    NA        <NA>        <NA>          <NA>
## NA.11      <NA> <NA>    NA        <NA>        <NA>          <NA>
## NA.12      <NA> <NA>    NA        <NA>        <NA>          <NA>
## NA.13      <NA> <NA>    NA        <NA>        <NA>          <NA>
## NA.14      <NA> <NA>    NA        <NA>        <NA>          <NA>
## NA.15      <NA> <NA>    NA        <NA>        <NA>          <NA>
## NA.16      <NA> <NA>    NA        <NA>        <NA>          <NA>
## NA.17      <NA> <NA>    NA        <NA>        <NA>          <NA>
## NA.18      <NA> <NA>    NA        <NA>        <NA>          <NA>
## NA.19      <NA> <NA>    NA        <NA>        <NA>          <NA>
## NA.20      <NA> <NA>    NA        <NA>        <NA>          <NA>
## NA.21      <NA> <NA>    NA        <NA>        <NA>          <NA>
##       equivinc.capped
## NA                 NA
## NA.1               NA
## NA.2               NA
## NA.3               NA
## NA.4               NA
## NA.5               NA
## NA.6               NA
## NA.7               NA
## NA.8               NA
## NA.9               NA
## NA.10              NA
## NA.11              NA
## NA.12              NA
## NA.13              NA
## NA.14              NA
## NA.15              NA
## NA.16              NA
## NA.17              NA
## NA.18              NA
## NA.19              NA
## NA.20              NA
## NA.21              NA
# reasons for zero weight could be: missing info on key hsd variables used for wgt creation; exclusion from the target pop



## RECONSTRUCT CUSTOM WEIGHTS PER YEAR
# for each calendar year, rescale or normalise the weights so they sum to the sample size (or population total) for that year.

usoc <- usoc %>%
  group_by(int.year.sched, wave) %>%
  #  within each year, calculate the total of the weights for each *wave*
  mutate(wgt.total = sum(x_wgt, na.rm=T)) %>%
  ungroup() 

# now we have the total weight for each year x wave

usoc$wgt.rescaled <- NA # initialise 

# for each calendar year...
for (yr in sort(unique(usoc$int.year.sched))) {
  # list all waves contributing to that year
  waves.in.yr <- sort(unique(usoc$wave[usoc$int.year.sched==yr]))
  # choose the first wave of that list as the ref (note: for 2009, there's just one contributing wave "a")
  ref.wave  <- waves.in.yr[1] 
  ref.total <- unique(usoc$wgt.total[usoc$int.year.sched==yr & usoc$wave==ref.wave])[1] # one number: the sum of all weights for this year & the ref wave
  
  # for all waves contributing to this year...
  for (wv in waves.in.yr) {
   wv.total <- unique(usoc$wgt.total[usoc$int.year.sched == yr & usoc$wave == wv])[1] # one number
   SCALING.FACTOR <- ref.total/wv.total # e.g. sum of wgts for wave "a" / sum of wgts for wave "b" (similar to scaling of the N)
   usoc$wgt.rescaled[usoc$int.year.sched == yr & usoc$wave == wv] <- SCALING.FACTOR * usoc$x_wgt[usoc$int.year.sched == yr & usoc$wave == wv]
  }
}

Observations about the weight-rescaling * no change to weights in wave “a” (2009 or 2010) * change to wave “b” weights in 2010 but not in 2011 * change to wave c weights in 2011 (upscaled by ~0.22) but not change to wave c weights in 2012 * only negative scaling factor was in wave o for 2023.

Top 3 points make sense when you look at this table, only the “first in class” remain unchanged, the first wave in each year:

table(usoc\(wave, usoc\)int.year.sched)

2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024

a 2578 2321 0 0 0 0 0 0 0 0 0 0 0 0 0 0 b 0 3040 1975 0 0 0 0 0 0 0 0 0 0 0 0 0 c 0 0 2682 1745 0 0 0 0 0 0 0 0 0 0 0 0 d 0 0 0 2412 1632 0 0 0 0 0 0 0 0 0 0 0 e 0 0 0 0 2256 1399 0 0 0 0 0 0 0 0 0 0 f 0 0 0 0 0 2213 1214 0 0 0 0 0 0 0 0 0 g 0 0 0 0 0 0 2011 1591 0 0 0 0 0 0 0 0 h 0 0 0 0 0 0 0 1827 1400 0 0 0 0 0 0 0 i 0 0 0 0 0 0 0 0 1624 1105 0 0 0 0 0 0 j 0 0 0 0 0 0 0 0 0 1385 1058 0 0 0 0 0 k 0 0 0 0 0 0 0 0 0 0 1319 730 0 0 0 0 l 0 0 0 0 0 0 0 0 0 0 0 932 694 0 0 0 m 0 0 0 0 0 0 0 0 0 0 0 0 989 730 0 0 n 0 0 0 0 0 0 0 0 0 0 0 0 0 847 705 0 o 0 0 0 0 0 0 0 0 0 0 0 0 0 0 644 756

Household income

The household income and equivalised income variables were calculated per wave. i.e. one person in one household could have very different equivalised incomes across wave A and B due to change in income, change in # dependants, or both.

But that’s not why you would want to bin income variables into groups for each wave separately– the distribution of income changes over 15 years, so what was “low income” in 2009 might not be the same as in 2024. Do we really want to split households into income groups based on 15-year averages?

hist(usoc$equivinc[usoc$equivinc<5000])

# most households have about £1000 per month per person. Anything over $4000 pm pp is an outlier

ggplot(data=usoc[usoc$hsdincome>0 & usoc$hsdincome<10000,], aes(hsdincome))+
  geom_histogram(fill="darkorange", colour="black", binwidth = 500)+
  facet_wrap(~wave.y)+
  labs(title="Distribution of net monthly incomes (limited to £0 - £10,000)")

# this plot shows us that the mean of the sample has increased from <£2500 to >£2500 per month. But the distribution has also become much flatter-- lower numbers in the sample and more people at lower and higher ends of this range. 


# plot income across income groups
ggplot(data=usoc[usoc$hsdincome>0 & usoc$hsdincome<10000,], aes(x=hsdincome, fill=income.groups))+
  geom_histogram(colour="black", binwidth = 500, alpha=0.7)+
  facet_wrap(~int.year.sched)+
  labs(title="Distribution of net monthly incomes (limited to £0 - £10,000)")

Life Satisfaction

In the UKHLS young people were asked to tick a box to indicate,“which best describes how you feel about your life as a whole?.” Response options were presented on a 7‐point scale represented by more or less smiley faces. Participants were instructed that 1 (happiest face) “is completely happy” and 7 (very sad face) is “not at all happy” and asked to mark the scale point that most closely resembles how they currently feel about their life. We reverse coded so that high scores indicated high levels of life satisfaction.

This question has previously been used to examine the relationship between life satisfaction and neighborhood deprivation in the UKHLS (Jonsson et al., 2020).

for (age in sort(unique(usoc$dvage))){
  
usoc.lim <- usoc[usoc$dvage==age, ]

data4cor <- subset(usoc.lim, select=c(ypsdqtd_dv, h.appear.c, h.school.c , h.schoolwork.c , h.friends.c , h.fam.c, h.life.c ))

names(data4cor) <- c("SDQ total diff", "Satis.appear", "Satis.school", "Satis.schoolwork", "Satis.friends", "Satis.family", "Satis.life")
  
cormat <- round(cor(data4cor, use="pairwise.complete.obs"), digits=3)

lower <- cormat
lower[lower.tri(cormat)] <- NA

meltedcormat <- melt(lower, na.rm=T)
meltedcormat$value[meltedcormat$value==1] <- NA


ggplot(data=meltedcormat, aes(Var2, Var1, fill=value))+
  geom_tile(color="white") +
  scale_fill_gradient2(low="red", mid = "white", high="royalblue3", 
                       limit = c(-1,1),        # you might want to alter these min and max colour limits
                       space="Lab",
                       name="Pearson's r") +
  theme_minimal()+
  labs(title= paste("Participants aged ", age))+
  theme(plot.title = element_text(hjust = 0.5),
        axis.text.x = element_text(angle=60, 
                                   vjust=1 ,  hjust=1),
        axis.title.x=element_blank(),
        axis.title.y=element_blank())+
  geom_text(aes(Var2, Var1, label=round(value,2)), color="black", size=3)+
  coord_flip()


ggsave(paste0("/Users/niamhdooley/Library/CloudStorage/OneDrive-RoyalCollegeofSurgeonsinIreland/DOROTHY CO-FUND/WP2-Understanding Society/Project A. Targets for intervention in life satisfaction/R outputs/correlation_heatmaps/age_", age, ".tiff"), units="in", width=6, height=5, dpi=600, compression = 'lzw')

}
  dvlist <- c("h.life","h.school", "h.schoolwork", "h.friends","h.fam", "h.appear" )

# calculate % with each response in each year
# data.frame with 7 columns and ~15 rows
# cell should show % of that year's sample

d <- usoc %>%
  group_by(int.year.sched, socialmed) %>%
  summarise(n=n()) %>%
  mutate(tot.n = sum(n),
         prop = n/tot.n)


# for (x in dvlist){
# var.ind <- which(names(usoc)==x)
# g<-ggplot(data=usoc, aes_string(x= as.character(x)))+
#     geom_histogram(aes(y=after_stat(count / sum(count))))+
#     facet_grid(~wave.y)
#     #geom_vline(xintercept = mean(usoc[,var.ind], na.rm=T) )
# print(g)
# }

# note: the mean is not updating across facets (waves)

for (x in dvlist){
var.ind <- which(names(usoc)==x)

d <- usoc %>%
  group_by(int.year.sched, usoc[,var.ind]) %>%
  summarise(n=n()) %>%
  mutate(tot.n = sum(n),
         prop = n/tot.n)

d <- d[!is.na(d[,2]),]

g<-ggplot(data=d, aes_string(x=x, y="prop"))+
  geom_col()+
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L), name="% each response")+
  scale_x_continuous(breaks=c(1,4,7), labels=c(":-(", ":-|", ":-)"), name = x)+
  facet_wrap(~int.year.sched)+
  theme(axis.text.x = element_text(angle=270, vjust = 0.5))
print(g)

}

# it's much clearer with percentage as the y-axis rather than N-- next plot the mean too.



d <- usoc %>%
  group_by(wave.y, ypsdqtd_dv) %>%
  summarise(n=n()) %>%
  mutate(tot.n = sum(n),
         prop = n/tot.n)

d <- d[!is.na(d$ypsdqtd_dv),]

d$clin <- as.factor(ifelse(d$ypsdqtd_dv>=20, "Very high (>=20)", "<20"))

ggplot(data=d, aes(x=ypsdqtd_dv, y=prop, fill=clin))+
  geom_col(binwidth=1)+
  scale_y_continuous(labels = scales::percent_format(), name="% each response")+
  #scale_x_continuous(breaks=c(1,4,7), labels=c(":-(", ":-|", ":-)"), name = x)+
  facet_wrap(~wave.y)+
  scale_fill_manual(values=c("black", "red"))

Only cross-sectional weights available in each youth survey, with different “zz” parts, which reflects the timeline of your research:
- a_ythscus_xw # us = starting at wave 1 (2009-10)
- b_ythscub_xw # ub = starting between wave 2 and 5
… - m_ythscui_xw # ui = starting at wave 6 onwards (2014-15)

Note change from us to ub to ui

Here are the original weights variables from imported data: “a_ythscus_xw” [US] “b_ythscub_xw” [UB] “c_ythscub_xw” [UB] “d_ythscub_xw” [UB] “e_ythscub_xw” [UB] “f_ythscui_xw” [UI] “g_ythscui_xw” [UI] “h_ythscui_xw” [UI] “i_ythscui_xw” [UI] “j_ythscui_xw” [UI] “k_ythscui_xw” [UI] “l_ythscui_xw” [UI] “m_ythscui_xw” [UI] “n_ythscg2_xw” [G2]

Main analysis

2. Relative influence of sub-domains on general life satisfaction

Beta coefficients (-Inf, Inf)

– full population

# takes ~15 seconds

# create data frames to store B coef and SEs of domain onto general life satisfaction, for each wave of data
coefs.wgts <- c() # adjusted for all other domains of life
coefs.wgts.unadj <- c() # unadjusted


 for (year.x in sort(unique(usoc$int.year.sched)) ){
#for (wave.x in c("a", "c", "e", "g", "i", "k", "m")){

  # extract cross-sec data for wave x
  xs <- usoc[usoc$int.year.sched==year.x,]

  # exclude participants with missing data on any life satis var
  xs <- xs[!is.na(xs$h.school.c) & !is.na(xs$h.schoolwork.c) & !is.na(xs$h.friends.c) & !is.na(xs$h.fam.c) & !is.na(xs$h.appear.c) & !is.na(xs$h.life.c), ]
  
  # set svy design for this wave
  usoc.svy <- svydesign(id=~psu + hidp, # hidp accounts for dependence among individuals within the same household by adjusting standard errors (via robust sandwich estimators)
                        strata=~strata, 
                        weights=~wgt.rescaled, 
                        data=xs,
                        nest=TRUE)
  options(survey.lonely.psu = "adjust") 

  
  # PREDICT GENERAL LIFE SATISFACTIONF FROM EACH DOMAIN (adjusting for all other domains)
  svyglm.multi <- svyglm(formula = h.life.c ~ h.school.c + h.schoolwork.c + h.friends.c + h.fam.c + h.appear.c,
                          design = usoc.svy)
  
  x= as.data.frame(summary(svyglm.multi)[["coefficients"]])
  
  coefs.wgts <- rbind(coefs.wgts, c(as.numeric(coef(svyglm.multi)), # betas
                                    as.numeric(x[,2])) ) # SEs
  
  
  # PREDICT GENERAL LIFE SATISFACTIONF FROM EACH DOMAIN (univariate-ly)
  ivlist <- c("h.school.c", "h.schoolwork.c", "h.friends.c", "h.fam.c", "h.appear.c")
  
  # run GLM substituting each area of life as only predictor
  svyglm.uni <- lapply(ivlist, function(x) {
                  svyglm(eval(substitute(h.life.c ~   i , 
                         list(i = as.name(x)))), 
                        design = usoc.svy)})
  
   x <- c()
  for (domain in 1:5){
    x <- as.data.frame(rbind(x, 
                             data.frame(year.x=year.x,
                                        domain=ivlist[domain],
                                        Beta = summary(svyglm.uni[[domain]])[["coefficients"]][2,1], # mean of the 1st (non-intercept) term
                                        SE = summary(svyglm.uni[[domain]])[["coefficients"]][2,2], # this is the sampling error of the mean.
                                        N = length(svyglm.uni[[1]][["effects"]])
                                          ))) }
   
   coefs.wgts.unadj <- rbind(coefs.wgts.unadj, x)
   
 }  



coefs.wgts <- cbind(sort(unique(usoc$int.year.sched)), as.data.frame(round(coefs.wgts,4)))

names(coefs.wgts) <- c("year", "B.intercept", "B.school", "B.schoolwork", "B.friends", "B.family", "B.appearance",
                       "SE.intercept", "SE.school", "SE.schoolwork", "SE.friends", "SE.family", "SE.appearance")

coefs.wgts$year.n <- coefs.wgts$year-2009 # centers at 2009
coefs.wgts$window <- c(rep(1,5), rep(2,5), rep(3,6)) # note extra year in window3!


# re-structure to long-format data
long.wgts <- coefs.wgts %>%
  dplyr::select(year, B.school, B.schoolwork, B.friends, B.family, B.appearance)%>%
  gather(key = "domain", value="Beta", -year)
long.se <- coefs.wgts %>%
  dplyr::select(year, SE.school, SE.schoolwork, SE.friends, SE.family, SE.appearance)%>%
  gather(key = "domain", value="SE", -year)
wgts.long <- cbind(long.wgts, long.se[,"SE"])
names(wgts.long)[4] <- "SE"

wgts.long$`Happiness with...` <- factor(wgts.long$domain, 
                                   levels=c( "B.family" , "B.friends", 
                                             "B.school", "B.schoolwork",
                                             "B.appearance" ),
                                   labels=c( "Family" , "Friends", 
                                             "School", "Schoolwork",
                                             "Appearance" ))
wgts.long$year.n <- wgts.long$year-2009
wgts.long$windows <- cut(wgts.long$year, breaks=c(2009, 2014, 2019, 2025), labels=c(1, 2, 3))



# Plot change over time in asssociations


# points connected by straight lines
# ggplot(data=wgts.long, aes(x=year, y=Beta, group=`Happiness with...`, fill=`Happiness with...`))+
#   geom_ribbon(aes(ymin=Beta-SE, ymax=Beta+SE), alpha=0.5)+
#   geom_point(aes(colour=`Happiness with...`))+
#   geom_line(aes(colour=`Happiness with...`))+
#   labs(y="Association with gen life happiness (B ± SE)")+
#   scale_colour_manual(values=cols5)+
#   scale_fill_manual(values=cols5)+
#   theme_minimal()+
#   theme(axis.text.x = element_text(angle=30, hjust = 1))

coefs.wgts.unadj$`Satisfaction with...` <- factor(coefs.wgts.unadj$domain, 
                                   levels=c( "h.fam.c" , "h.friends.c", 
                                             "h.school.c", "h.schoolwork.c",
                                             "h.appear.c" ),
                                   labels=c( "Family" , "Friends", 
                                             "School", "Schoolwork",
                                             "Appearance" ))

# bar chart UNADJUSTED
ggplot(data=coefs.wgts.unadj, aes(x=year.x, y=Beta))+
  geom_col(aes(fill=`Satisfaction with...`), alpha=0.7)+
  geom_errorbar(aes(ymin=Beta-SE, ymax=Beta+SE, colour=`Satisfaction with...`), width=0)+
  geom_smooth(aes(x=year.x, y=Beta), method="loess",  colour="grey60", se=F)+
  geom_smooth(aes(x=year.x, y=Beta), method="lm", formula = y~x, colour="black", se=T)+
  #geom_smooth(aes(x=year.x, y=Beta), method="lm", formula = y~poly(x,2), colour="black", se=F)+
  labs(y="Unadjusted association with life satisfaction (B ± SE)\n", x="\nSurvey year")+
  facet_grid(~`Satisfaction with...`)+
  scale_x_continuous(breaks= seq(2010,2024,2),  limits = c(2008,2025), name = "")+
  scale_y_continuous(limits=c(0, 1))+
  scale_fill_manual(values=cols5)+
  scale_colour_manual(values=cols5)+
  theme_minimal()+
  theme(axis.text.x = element_text(size=8, angle=60, hjust=1, vjust = 1),
        #panel.grid.major.x = element_blank(),
        panel.grid.minor.x = element_blank(),
        panel.grid.minor.y = element_blank())

ggsave("/Users/niamhdooley/Library/CloudStorage/OneDrive-RoyalCollegeofSurgeonsinIreland/DOROTHY CO-FUND/WP2-Understanding Society/Project A. Targets for intervention in life satisfaction/R outputs/weights_over_time_unadj.tiff", units="in", width=10, height=5, dpi=600, compression = 'lzw')

# bar chart ADJUSTED
ggplot(data=wgts.long, aes(x=year, y=Beta))+
  geom_col(aes(fill=`Happiness with...`), alpha=0.7)+
  geom_errorbar(aes(ymin=Beta-SE, ymax=Beta+SE, colour=`Happiness with...`), width=0)+
  geom_smooth(aes(x=year, y=Beta), method="loess",  colour="grey60", se=F)+
  geom_smooth(aes(x=year, y=Beta), method="lm", formula = y~x, colour="black", se=T)+
  #geom_smooth(aes(x=year, y=Beta), method="lm", formula = y~poly(x,2), colour="black", se=F)+
  labs(y="Adjusted association with life satisfaction (B ± SE)\n", x="\nSurvey year")+
  facet_grid(~`Happiness with...`)+
  scale_x_continuous(breaks= seq(2010,2024,2),  limits = c(2008,2025), name = "")+
  scale_y_continuous(limits=c(0, 0.5))+
  scale_fill_manual(values=cols5)+
  scale_colour_manual(values=cols5)+
  theme_minimal()+
  theme(axis.text.x = element_text(size=8, angle=60, hjust=1, vjust = 1),
        #panel.grid.major.x = element_blank(),
        panel.grid.minor.x = element_blank(),
        panel.grid.minor.y = element_blank())

#ggsave("/Users/niamhdooley/Library/CloudStorage/OneDrive-RoyalCollegeofSurgeonsinIreland/DOROTHY CO-FUND/WP2-Understanding Society/Project A. Targets for intervention in life satisfaction/R outputs/weights_over_time.tiff", units="in", width=10, height=5, dpi=600, compression = 'lzw')


## WITHOUT COVID
# bar chart UNADJUSTED
ggplot(data=coefs.wgts.unadj[coefs.wgts.unadj$year.x!=2020 & coefs.wgts.unadj$year.x!=2021,], aes(x=year.x, y=Beta))+
  geom_col(aes(fill=`Satisfaction with...`), alpha=0.7)+
  geom_errorbar(aes(ymin=Beta-SE, ymax=Beta+SE, colour=`Satisfaction with...`), width=0)+
  geom_smooth(aes(x=year.x, y=Beta), method="loess",  colour="grey60", se=F)+
  geom_smooth(aes(x=year.x, y=Beta), method="lm", formula = y~x, colour="black", se=T)+
  #geom_smooth(aes(x=year.x, y=Beta), method="lm", formula = y~poly(x,2), colour="black", se=F)+
  labs(y="UNADJUSTED association with life satisfaction (B ± SE)\n", x="\nSurvey year")+
  facet_grid(~`Satisfaction with...`)+
  scale_x_continuous(breaks= seq(2010,2024,2),  limits = c(2008,2025), name = "")+
  scale_y_continuous(limits=c(0, 1))+
  scale_fill_manual(values=cols5)+
  scale_colour_manual(values=cols5)+
  theme_minimal()+
  theme(axis.text.x = element_text(size=8, angle=60, hjust=1, vjust = 1),
        #panel.grid.major.x = element_blank(),
        panel.grid.minor.x = element_blank(),
        panel.grid.minor.y = element_blank())

# bar chart ADJUSTED
ggplot(data=wgts.long[wgts.long$year!=2020 & wgts.long$year!=2021,], aes(x=year, y=Beta))+
  geom_col(aes(fill=`Happiness with...`), alpha=0.7)+
  geom_errorbar(aes(ymin=Beta-SE, ymax=Beta+SE, colour=`Happiness with...`), width=0)+
  geom_smooth(aes(x=year, y=Beta), method="loess",  colour="grey60", se=F)+
  geom_smooth(aes(x=year, y=Beta), method="lm", formula = y~x, colour="black", se=T)+
  #geom_smooth(aes(x=year, y=Beta), method="lm", formula = y~poly(x,2), colour="black", se=F)+
  labs(y="Adjusted association with life satisfaction (B ± SE)\n", x="\nSurvey year")+
  facet_grid(~`Happiness with...`)+
  scale_x_continuous(breaks= seq(2010,2024,2),  limits = c(2008,2025), name = "")+
  scale_y_continuous(limits=c(0, 0.5))+
  scale_fill_manual(values=cols5)+
  scale_colour_manual(values=cols5)+
  theme_minimal()+
  theme(axis.text.x = element_text(size=8, angle=60, hjust=1, vjust = 1),
        #panel.grid.major.x = element_blank(),
        panel.grid.minor.x = element_blank(),
        panel.grid.minor.y = element_blank())

Note the y-axis represents the association between each domain and “general life satisfaction”, after controlling for the other domains.

  • Notable rise in the relative influence of “happiness with appearance” on general life satisfcation, over full time period
  • Rise in relative influence of “happiness with family”
  • Smaller changes in friends, school and schoolwork

But these correlations are relative on each other… what is the pure bivariate correlation between each domain and general life satisfaction

# save meta-regression output here:
wgt.avgs <- c()
wgt.trends  <- c()
wgt.avg.5ywin  <- c() # this one's different to the previous "change *within* 5 year windows". This time we're looking at 5-year *average* i.e. intercept
var.cov.matrix <- c()
var.cov.guide <- c()

for (domain in levels(as.factor(wgts.long$domain))) {

  dat <- wgts.long[wgts.long$domain==domain, ]
  
  D <- diag(dat$SE, 16, 16)
  V <- D %*% R %*% D
  
  # store these variance-covariance matrices for subgroup analyses later
  var.cov.matrix <- abind(var.cov.matrix, V)
  var.cov.guide <- cbind(var.cov.guide, domain)
  
  # intercept-only M.A: What is the pooled mean across all my waves?
  rma.ave <- rma.mv(yi = Beta,
                    V = V,
                    data=dat) 
       
        # save
        wgt.avgs <- rbind(wgt.avgs, data.frame(
                                      domain = domain,
                                      beta = as.numeric(rma.ave[["beta"]]), 
                                      se = as.numeric(rma.ave[["se"]]),
                                      ci.low = as.numeric(rma.ave[["ci.lb"]]), 
                                      ci.hi = as.numeric(rma.ave[["ci.ub"]])) )
  
  # include time as moderator...
  # full time period 
  rma.trend.full <- rma.mv(yi = Beta,
                           V = V,
                           mods = ~ year.n,
                           data = dat)
         # save
         wgt.trends <- rbind(wgt.trends, data.frame(
                                           domain=domain,
                                           beta=as.numeric(rma.trend.full[["beta"]][2]),
                                           se=as.numeric(rma.trend.full[["se"]][2]),
                                           ci.low=as.numeric(rma.trend.full[["ci.lb"]][2]),
                                           ci.hi=as.numeric(rma.trend.full[["ci.ub"]][2]),
                                           p=round(as.numeric(rma.trend.full[["pval"]][2]),4)))
         
    # Note: There's so much year-to-year fluctuation with this data, I don't think we should be looking at within-5 year changes. But we could estimate *average* associations within each 5-year window, to average out some of those fluctuations...
         
         for (win in 1:3){
           dat.win <- wgts.long[wgts.long$domain==domain & wgts.long$windows==win & !is.na(wgts.long$windows), ]
           D <- diag(dat.win$SE)
    
            # limit the covariance matrix R to the correct years
            Rsub <- R[2:nrow(R), 2:ncol(R)] # remove 2009 (excluded from 5-y windows)
            if (win==1){
              Rsub <- Rsub[1:5, 1:5]
            } else if  (win==2){
              Rsub <- Rsub[6:10, 6:10]
            } else if  (win==3){
              Rsub <- Rsub[11:15, 11:15]
            }
            # create the variance-covariance matrix
            V <- D %*% Rsub %*% D
            
            rma.ave.win <- rma.mv(yi = Beta, V = V, data=dat.win)
            
            wgt.avg.5ywin <- rbind(wgt.avg.5ywin, data.frame(
                                      domain = domain,
                                      window = win,
                                      beta = as.numeric(rma.ave.win[["beta"]]), 
                                      se = as.numeric(rma.ave.win[["se"]]),
                                      ci.low = as.numeric(rma.ave.win[["ci.lb"]]), 
                                      ci.hi = as.numeric(rma.ave.win[["ci.ub"]])) )
            
           }

}

wgt.avgs[,c(2:5)] <- round(wgt.avgs[,c(2:5)], 2)
wgt.trends[,c(2:5)] <- round(wgt.trends[,c(2:5)], 3)
library(abind)

# save meta-regression output here:
wgt.avgs <- c()
wgt.trends  <- c()
var.cov.matrix <- c()
var.cov.guide <- c()

for (domain in levels(as.factor(coefs.wgts.unadj$domain))) {

  dat <- coefs.wgts.unadj[coefs.wgts.unadj$domain==domain, ]
  
  D <- diag(dat$SE, 16, 16)
  V <- D %*% R %*% D
  
  # store these variance-covariance matrices for subgroup analyses later
  var.cov.matrix <- abind(var.cov.matrix, V)
  var.cov.guide <- cbind(var.cov.guide, domain)
  
  # intercept-only M.A: What is the pooled mean across all my waves?
  rma.ave <- rma.mv(yi = Beta,
                    V = V,
                    data=dat) 
       
        # save
        wgt.avgs <- rbind(wgt.avgs, data.frame(
                                      domain = domain,
                                      beta = as.numeric(rma.ave[["beta"]]), 
                                      se = as.numeric(rma.ave[["se"]]),
                                      ci.low = as.numeric(rma.ave[["ci.lb"]]), 
                                      ci.hi = as.numeric(rma.ave[["ci.ub"]])) )
  
  # include time as moderator...
  # full time period 
  rma.trend.full <- rma.mv(yi = Beta,
                           V = V,
                           mods = ~ year.x,
                           data = dat)
         # save
         wgt.trends <- rbind(wgt.trends, data.frame(
                                           domain=domain,
                                           beta=as.numeric(rma.trend.full[["beta"]][2]),
                                           se=as.numeric(rma.trend.full[["se"]][2]),
                                           ci.low=as.numeric(rma.trend.full[["ci.lb"]][2]),
                                           ci.hi=as.numeric(rma.trend.full[["ci.ub"]][2]),
                                           p=round(as.numeric(rma.trend.full[["pval"]][2]),4)))

}

wgt.avgs[,c(2:5)] <- round(wgt.avgs[,c(2:5)], 2)
wgt.trends[,c(2:5)] <- round(wgt.trends[,c(2:5)], 3)

– by demographic group

# step 1. run the adjusted model (all subdomains predicting gen life happiness) within each subgroup
# TAKES ~1-2 MINS

wgts.bygroup <- c() 

for (group in c("Female", "Male", "10-12", "13-15", "high.inc",  "low.inc" , "mid.inc")){
 
 for (year.x in sort(unique(usoc$int.year.sched)) ){

     # limit dataset to a specific year
  xs <- usoc[usoc$int.year.sched==year.x ,]
  xs <- xs[!is.na(xs$h.school.c) & !is.na(xs$h.schoolwork.c) & !is.na(xs$h.friends.c) & !is.na(xs$h.fam.c) & !is.na(xs$h.appear.c) & !is.na(xs$h.life.c), ]
  
    usoc.svy <- svydesign(id=~psu + hidp,
                        strata=~strata, 
                        weights=~wgt.rescaled, 
                        data=xs,
                        nest=TRUE)
    options(survey.lonely.psu = "adjust") 
    
    # limit cross-sectional survey data to group
    if (group=="Female"|group=="Male"){
    tmp <- usoc.svy$variables$sex_dv == group   
     } else if (group=="10-12"|group=="13-15") {
    tmp <- usoc.svy$variables$age.group == group
     } else if (str_detect(group, "inc")) {
    tmp <- usoc.svy$variables$income.groups == group
     }
    
    usoc.svg.group <- subset(usoc.svy, tmp)
    options(survey.lonely.psu = "adjust") 
    
    # find relative influence of each aspect of life, for THIS group, in this year.
    group.glm <- svyglm(formula = h.life.c ~ h.school.c + h.schoolwork.c
                    + h.friends.c + h.fam.c + h.appear.c,
                    design = usoc.svg.group)
    
    coef <- as.data.frame(summary(group.glm)[["coefficients"]])
  
    wgts.bygroup <- rbind(wgts.bygroup, data.frame(
                                              year = year.x,
                                              group = group,
                                              n = length(group.glm$effects),
                                              school.B = coef$Estimate[rownames(coef)=="h.school.c"],
                                              school.SE = coef$`Std. Error`[rownames(coef)=="h.school.c"],
                                              schoolwork.B = coef$Estimate[rownames(coef)=="h.schoolwork.c"],
                                              schoolwork.SE = coef$`Std. Error`[rownames(coef)=="h.schoolwork.c"],
                                              fam.B = coef$Estimate[rownames(coef)=="h.fam.c"],
                                              fam.SE = coef$`Std. Error`[rownames(coef)=="h.fam.c"],
                                              friend.B = coef$Estimate[rownames(coef)=="h.friends.c"],
                                              friend.SE = coef$`Std. Error`[rownames(coef)=="h.friends.c"],
                                              appear.B = coef$Estimate[rownames(coef)=="h.appear.c"],
                                              appear.SE = coef$`Std. Error`[rownames(coef)=="h.appear.c"]))
 }
}

# re-structure to long-format data
long.wgts <- wgts.bygroup %>%
  dplyr::select(year, group, n, school.B, schoolwork.B, friend.B, fam.B, appear.B)%>%
  gather(key = "domain", value="Beta", -c(year, group, n))
long.se <- wgts.bygroup %>%
  dplyr::select(year, group, n, school.SE, schoolwork.SE, friend.SE, fam.SE, appear.SE)%>%
  gather(key = "domain", value="SE", -c(year, group, n))
group.wgts.long <- cbind(long.wgts, long.se[,"SE"])
names(group.wgts.long)[6] <- "SE"

group.wgts.long$`Happiness with...` <- factor(group.wgts.long$domain, 
                                   levels=c("fam.B","friend.B", "school.B", "schoolwork.B", "appear.B" ),
                                   labels=c( "Family" , "Friends", 
                                             "School", "Schoolwork",
                                             "Appearance" ))
group.wgts.long$year.n <- group.wgts.long$year-2009



# step 2 
# input group-specific estimates into a meta-analysis to estimate 
#(i)  the average association estimates for that group and 
#(ii) see the association has changed over time for either group 
group.B.ave <- c()
group.B.5yave <- c()
group.B.change <- c()

for (group in levels(as.factor(group.wgts.long$group))) {
  for (domain in levels(as.factor(group.wgts.long$domain))) {
  
  dat <- group.wgts.long[group.wgts.long$domain==domain & group.wgts.long$group==group, ]
  
  D <- diag(dat$SE, 16, 16)
  V <- D %*% R %*% D
  
  # intercept-only M.A: What is the pooled estimate across all years?
  rma.ave <- rma.mv(yi = Beta,
                    V = V,
                    data=dat) 
       
        # save
        group.B.ave <- rbind(group.B.ave, data.frame(
                                      domain = domain,
                                      group = group,
                                      beta = as.numeric(rma.ave[["beta"]]), 
                                      se = as.numeric(rma.ave[["se"]]),
                                      ci.low = as.numeric(rma.ave[["ci.lb"]]), 
                                      ci.hi = as.numeric(rma.ave[["ci.ub"]])) )
        
  # average for last 5 years only
  dat.lim <- dat[dat$year>=2020,]
  
  D.lim <- diag(dat.lim$SE)
  R.lim <- R[12:16, 12:16]
  
  V.lim <- D.lim %*% R.lim %*% D.lim
  
  # intercept-only M.A: What is the pooled estimate across these 5 years?
  rma.5yave <- rma.mv(yi = Beta,
                    V = V.lim,
                    data=dat.lim)
  
  # save
        group.B.5yave <- rbind(group.B.5yave, data.frame(
                                      domain = domain,
                                      group = group,
                                      beta = as.numeric(rma.5yave[["beta"]]), 
                                      se = as.numeric(rma.5yave[["se"]]),
                                      ci.low = as.numeric(rma.5yave[["ci.lb"]]), 
                                      ci.hi = as.numeric(rma.5yave[["ci.ub"]])) )
  
  # include time as moderator to see if things have changed significantly for that group
  # full time period 
  rma.trend.full <- rma.mv(yi = Beta,
                           V = V,
                           mods = ~ year.n,
                           data = dat)
         # save
         group.B.change <- rbind(group.B.change, data.frame(
                                           domain=domain,
                                           group=group,
                                           beta=as.numeric(rma.trend.full[["beta"]][2]),
                                           se=as.numeric(rma.trend.full[["se"]][2]),
                                           ci.low=as.numeric(rma.trend.full[["ci.lb"]][2]),
                                           ci.hi=as.numeric(rma.trend.full[["ci.ub"]][2]),
                                           p=round(as.numeric(rma.trend.full[["pval"]][2]),4)))
         
}
}



save(group.wgts.long, group.B.ave, group.B.5yave, group.B.change,
     file="/Users/niamhdooley/Library/CloudStorage/OneDrive-RoyalCollegeofSurgeonsinIreland/DOROTHY CO-FUND/WP2-Understanding Society/Project A. Targets for intervention in life satisfaction/R outputs/relat.wgts.groups.Rdata")


# extract table of Ns per year
Ns <- data.frame(year = wgts.bygroup$year[wgts.bygroup$group=="Female"],
          Females = wgts.bygroup$n[wgts.bygroup$group=="Female"],
          Males = wgts.bygroup$n[wgts.bygroup$group=="Male"],
          `10-12 years` =  wgts.bygroup$n[wgts.bygroup$group=="10-12"],
          `13-15 years` =  wgts.bygroup$n[wgts.bygroup$group=="13-15"],
          `High income` = wgts.bygroup$n[wgts.bygroup$group=="high.inc"],
          `Middle income` = wgts.bygroup$n[wgts.bygroup$group=="mid.inc"],
          `Low income` = wgts.bygroup$n[wgts.bygroup$group=="low.inc"]
          )
load("/Users/niamhdooley/Library/CloudStorage/OneDrive-RoyalCollegeofSurgeonsinIreland/DOROTHY CO-FUND/WP2-Understanding Society/Project A. Targets for intervention in life satisfaction/R outputs/relat.wgts.groups.Rdata")
# a different approach: run one rma() per group factor (e.g. sex) and include an interaction between sex and time
# see if your function metareg.timeXgroup() can be used for this...


# prepare the dataset of betas for the function
group.wgts.long$year.x <- group.wgts.long$year
group.wgts.long$group.factor <- factor(group.wgts.long$group, levels=c("10-12","13-15",
                                                                       "Female" , "Male" ,
                                                                       "high.inc", "mid.inc","low.inc"),
                                       labels=c("age", "age", "sex", "sex", "income", "income", "income"))
group.wgts.long$dvlist <- factor(group.wgts.long$domain, levels=c("school.B","schoolwork.B","fam.B", "friend.B","appear.B"), labels=c("h.school.c", "h.schoolwork.c","h.fam.c",  "h.friends.c", "h.appear.c"))
group.wgts.long$mean <- group.wgts.long$Beta
group.wgts.long$se <- group.wgts.long$SE


# limit to one group factor (CHECK metareg.timeXgroup() FUNCTION TO SEE WHY NOT WORKING (VAR-COVAR MATRIX))
df = group.wgts.long[group.wgts.long$group.factor=="sex",]
betas.sexdiffs <- metareg.timeXgroup(df, "full")

df = group.wgts.long[group.wgts.long$group.factor=="age",]
betas.agediffs <- metareg.timeXgroup(df, "full")

df = group.wgts.long[group.wgts.long$group.factor=="income",]
betas.incdiffs <- metareg.timeXgroup(df, "full")

# pretty sure reference groups are: females, 10-12 yo, high income -- see plots for proof

Adapt summary below The plots below show that there are no strong group differences in B-estimates (how sub-domains relate to general life happiness), nor in the change in those association over time (for example, appearance B increases in all groups)

The relative importance of family was the only domain where there was a significant (p<.05) moderation. Family had weaker associations with life satisfaction for males compared to females (but p = .04) and for older compared to younger kids (p = .01). We do not see the same patterns when using SDQ tot as the outcome.

dplot <- group.wgts.long
 dplot$group <- factor(dplot$group, levels=c("Female", "Male", "10-12", "13-15", "high.inc", "mid.inc","low.inc"))

ggplot(data=dplot[dplot$group=="Male" | dplot$group=="Female", ], 
               aes(x=year, y=Beta, group=group))+
  geom_line(aes(colour=group), size=1)+
  geom_ribbon(aes(ymin=Beta-2*SE, ymax=Beta+2*SE, fill=group),alpha=0.2)+
  facet_grid(cols=vars(`Happiness with...`))+
  theme_minimal()+
  #scale_y_continuous(breaks=c(1,2), minor_breaks = c(0.5, 1.5,2.5), 
  #                   limits = c(0.3,2.6), name = "\nHappiness (-3 to +3)")+
  scale_x_continuous(breaks=seq(2010,2024,2),  limits = c(2009,2024), name = "")+
  #scale_shape_manual(values=c(3,15))+
  scale_colour_manual(values=c("darkorange2", "turquoise3"))+
  scale_fill_manual(values=c( "darkorange2", "turquoise3"))+
  theme(axis.text.x = element_text(angle=60, hjust = 1, size=6))

ggplot(data=dplot[dplot$group=="10-12" | dplot$group=="13-15", ], 
               aes(x=year, y=Beta, group=group))+
  geom_line(aes(colour=group), size=1)+
  geom_ribbon(aes(ymin=Beta-2*SE, ymax=Beta+2*SE, fill=group),alpha=0.2)+
  facet_grid(cols=vars(`Happiness with...`))+
  theme_minimal()+
  #scale_y_continuous(breaks=c(1,2), minor_breaks = c(0.5, 1.5,2.5), 
  #                   limits = c(0.3,2.6), name = "\nHappiness (-3 to +3)")+
  scale_x_continuous(breaks=seq(2010,2024,2),  limits = c(2009,2024), name = "")+
  #scale_shape_manual(values=c(3,15))+
  scale_colour_manual(values=c("olivedrab3", "darkseagreen4"))+
  scale_fill_manual(values=c("olivedrab3", "darkseagreen4"))+
  theme(axis.text.x = element_text(angle=60, hjust = 1, size=6))

# make middle income go in the middle!!

ggplot(data=dplot[str_detect(dplot$group, "inc"), ], 
               aes(x=year, y=Beta, group=group))+
  geom_line(aes(colour=group), size=1)+
  geom_ribbon(aes(ymin=Beta-2*SE, ymax=Beta+2*SE, fill=group),alpha=0.2)+
  facet_grid(cols=vars(`Happiness with...`))+
  theme_minimal()+
  #scale_y_continuous(breaks=c(1,2), minor_breaks = c(0.5, 1.5,2.5), 
  #                   limits = c(0.3,2.6), name = "\nHappiness (-3 to +3)")+
  scale_x_continuous(breaks=seq(2010,2024,2),  limits = c(2009,2024), name = "")+
  #scale_shape_manual(values=c(3,15))+
  scale_colour_manual(values=c("darkslateblue","plum4","thistle" ))+
  scale_fill_manual(values=c( "darkslateblue","plum4","thistle" ))+
  theme(axis.text.x = element_text(angle=60, hjust = 1, size=6))

Further take-aways: - these association estimates are very unstable. They fluctuate greatly from year to year, which makes any group difference unlikely to be detected. - but all we can conclude from this data is that there are no significant differences (that can be detected) in the influence of each area of life on general life happiness. - the beta estimates for each subdomain are so remarkably similar across groups, that it actyally makes me think this is a statistical similarity rather than actual “influence” of each domain. i.e. school & schoolwork will be simmilarly ranked, so they are downweighted in tandem. Family & appearance are the most “independent” or different constructs of the 5, so they “show up”. Try and phrase this in a more scientific way for the paper.

But are we more interested in the order of aspects of life, for different subgroups?

#  averages over all 16 yrs
group.B.ave$domain.nice <- str_remove_all(group.B.ave$domain, ".B")

ggplot(data=group.B.ave[str_detect(group.B.ave$group, "-1"),], 
       aes(x= reorder(domain.nice,-beta), y=beta, ymin=ci.low, ymax=ci.hi, fill=domain.nice))+
  geom_col()+
  geom_errorbar(width=0)+
  labs(x="Subdomains of life", y="Association with life satisfaction", title= "Split by age-group")+
  facet_grid(~group)+
  theme(axis.text.x = element_text(angle=30, size=9, hjust=1),
        legend.position = "none")

ggplot(data=group.B.ave[str_detect(group.B.ave$group, "ale"),], 
       aes(x= reorder(domain.nice,-beta), y=beta, ymin=ci.low, ymax=ci.hi, fill=domain.nice))+
  geom_col()+
  geom_errorbar(width=0)+
  labs(x="Subdomains of life", y="Association with life satisfaction", title= "Split by sex")+
  facet_grid(~group)+
  theme(axis.text.x = element_text(angle=30, size=9, hjust=1),
        legend.position = "none")

ggplot(data=group.B.ave[str_detect(group.B.ave$group, "inc"),], 
       aes(x= reorder(domain.nice,-beta), y=beta, ymin=ci.low, ymax=ci.hi, fill=domain.nice))+
  geom_col()+
  geom_errorbar(width=0)+
  labs(x="Subdomains of life", y="Association with life satisfaction", title= "Split by hsd income")+
  facet_grid(~group)+
  theme(axis.text.x = element_text(angle=30, size=9, hjust=1),
        legend.position = "none")

# If we limit data to the last 5 years?

# average associational strengths in last 5 yrs

group.B.5yave$domain.nice <- str_remove_all(group.B.5yave$domain, ".B")

ggplot(data=group.B.5yave[str_detect(group.B.5yave$group, "-1"),], 
       aes(x= reorder(domain.nice,-beta), y=beta, ymin=ci.low, ymax=ci.hi, fill=domain.nice))+
  geom_col()+
  geom_errorbar(width=0)+
  labs(x="Subdomains of life", y="Association with life satisfaction", title= "Split by age-group")+
  facet_grid(~group)+
  theme(axis.text.x = element_text(angle=30, size=9, hjust=1),
        legend.position = "none")

ggplot(data=group.B.5yave[str_detect(group.B.5yave$group, "ale"),], 
       aes(x= reorder(domain.nice,-beta), y=beta, ymin=ci.low, ymax=ci.hi, fill=domain.nice))+
  geom_col()+
  geom_errorbar(width=0)+
  labs(x="Subdomains of life", y="Association with life satisfaction", title= "Split by sex")+
  facet_grid(~group)+
  theme(axis.text.x = element_text(angle=30, size=9, hjust=1),
        legend.position = "none")

ggplot(data=group.B.5yave[str_detect(group.B.5yave$group, "inc"),], 
       aes(x= reorder(domain.nice,-beta), y=beta, ymin=ci.low, ymax=ci.hi, fill=domain.nice))+
  geom_col()+
  geom_errorbar(width=0)+
  labs(x="Subdomains of life", y="Association with life satisfaction", title= "Split by hsd income")+
  facet_grid(~group)+
  theme(axis.text.x = element_text(angle=30, size=9, hjust=1),
        legend.position = "none")

When we had statistically looked at the beta estimate for group, there was no significant change over time in any group differences in associational strength between each sub-domain and general life satisfaction. Sensitivity analysis with SDQ only showed 1 change over time: the association between family and life happiness growing in the older kids more than the younger kids (but only p = .03)

The association between subdomains and genral life happiness may be so high that there is not much room for moderation by group. But when we replace the life happiness item with SDQ total, we also don’t see much difference by sex.

Which groups and which domains showed a significant change over the 16 year time period?

ordered.df <- group.B.change[order(group.B.change$p),]

kable(ordered.df[1:10,], escape=F)%>% 
  kableExtra::kable_styling(full_width = F, font_size = 15)
domain group beta se ci.low ci.hi p
16 appear.B high.inc 0.0099132 0.0026057 0.0048061 0.0150202 0.0001
6 appear.B 13-15 0.0085061 0.0024330 0.0037374 0.0132748 0.0005
11 appear.B Female 0.0079901 0.0023101 0.0034624 0.0125177 0.0005
1 appear.B 10-12 0.0086877 0.0025798 0.0036314 0.0137439 0.0008
26 appear.B Male 0.0079438 0.0027543 0.0025455 0.0133420 0.0039
21 appear.B low.inc 0.0084731 0.0030817 0.0024330 0.0145131 0.0060
31 appear.B mid.inc 0.0082887 0.0030383 0.0023337 0.0142436 0.0064
8 friend.B 13-15 -0.0088178 0.0034441 -0.0155681 -0.0020675 0.0105
13 friend.B Female -0.0084844 0.0033168 -0.0149852 -0.0019836 0.0105
12 fam.B Female 0.0085772 0.0036735 0.0013772 0.0157772 0.0196

All groups showed a significant increase in the relative “weighting” of appearance on general life satisfaction (here’s the groups in order of that change): - high income kids (B = 0.011) - 13-15 year olds (B = 0.009) - 10-12 year olds (B = 0.009) - Females (B = 0.008) - Males (B = 0.008) - Low income kids (B = 0.009), p = .007 - Mid income kids (B = 0.007), p = .025

Then there were borderline sig decreases in relative association between friends & general life happiness: - females (B = -0.007) - 13-15 year olds (B = -0.009)

Partial & bivariate correlations (-1, 1)

data4cor <- subset(usoc, select=c(h.life, h.appear, h.school, h.schoolwork, h.friends, h.fam))
data4cor <- data4cor[complete.cases(data4cor),]

names(data4cor) <- c("Life as whole", "Appearance", "School", "Schoolwork", "Friends", "Family")

# compute partial correlations
pc  <- pcor(data4cor)
pc_matrix <- pc$estimate

# convert to edge list
edges <- pc_matrix %>%
  as.data.frame() %>%
  rownames_to_column("var1") %>%
  pivot_longer(-var1, names_to = "var2", values_to = "partial_r") %>%
  filter(var1 < var2)

# Define the other variables (in any order you prefer)
vars <- c("Life as whole", "Appearance", "School", "Schoolwork", "Friends", "Family")
others <- vars[vars != "Life as whole"]

# Create semicircle layout for the lower nodes
theta <- seq(-pi/6, -5*pi/6, length.out = length(others))  # wide, smooth arc

nodes <- data.frame(
  name = vars,
  x = c(0,                  # h.life centred in middle
        cos(theta)),        # other variables on arc
  y = c(0.1,                  # h.life
        -0.1 + 5*sin(theta))  # increase curvature for bottom row of nodes
)

g <- graph_from_data_frame(edges, directed = FALSE, vertices = nodes)

# Identify edges connected to "h.life"
connected_to_hlife <- incident(g, "Life as whole", mode = "all")

# Create an edge color vector for all edges
edge_cols <- rep("grey70", ecount(g))
edge_cols[connected_to_hlife] <- "black"

E(g)$edge_color <- edge_cols

ggraph(g, layout = "manual", x = x, y = y) +
  geom_edge_link(aes(width = partial_r,  colour= edge_color)) +
  #geom_node_point(size = 12, colour = "white") +
  geom_node_label(aes(label = name, fill=name), size =4, label.r = unit(7, "pt"),
                  label.padding = unit(6, "pt")) +
  scale_edge_width(limits = c(0.01,   0.5), # partial correlation values
                   range =  c(0.1, 5)) + # line thickness values
  scale_fill_manual(values=c("#E78AC3FF" ,"#8DA0CBFF", "#FC8D62FF",  "lightgrey","#66C2A5FF","#A6D854FF" ))+
  scale_edge_colour_manual(values=c("black","grey80"))+
  #scale_edge_colour_gradient2(low = "red", mid = "grey80", high = "blue") +
   theme_void()+
   theme(legend.position = "none",
         plot.background = element_rect(fill="white"))

#print(plot)


ggsave(paste0("/Users/niamhdooley/Library/CloudStorage/OneDrive-RoyalCollegeofSurgeonsinIreland/DOROTHY CO-FUND/WP2-Understanding Society/Project A. Targets for intervention in life satisfaction/R outputs/networkplots/avg_fullperiod.tiff"), units="in", width=8, height=7, dpi=600, compression = 'lzw')
plot_list <- vector("list", length = 3)


# for (YEAR in sort(unique(usoc$int.year.sched))){
for (window in sort(unique(usoc$time.window))) {

# select life satis data for 1 year only (no NAs)
data4cor <- subset(usoc[usoc$time.window==window,], select=c(h.life, h.appear, h.school, h.schoolwork, h.friends, h.fam))

data4cor <- data4cor[complete.cases(data4cor),]

# compute partial correlations
pc  <- pcor(data4cor)
pc_matrix <- pc$estimate

# convert to edge list
edges <- pc_matrix %>%
  as.data.frame() %>%
  rownames_to_column("var1") %>%
  pivot_longer(-var1, names_to = "var2", values_to = "partial_r") %>%
  filter(var1 < var2)

# Define the other variables (in any order you prefer)
vars <- c("h.life", "h.appear" , "h.schoolwork","h.school", "h.friends", "h.fam" )
others <- vars[vars != "h.life"]

# Create semicircle layout for the lower nodes
theta <- seq(-pi/6, -5*pi/6, length.out = length(others))  # wide, smooth arc

nodes <- data.frame(
  name = vars,
  x = c(0,                  # h.life at centre top
        cos(theta)),        # other variables on arc
  y = c(0.8,                  # h.life
        -1 + 7*sin(theta))  # increase curvature for bottom row of nodes
)

g <- graph_from_data_frame(edges, directed = FALSE, vertices = nodes)

# Identify edges connected to "h.life"
connected_to_hlife <- incident(g, "h.life", mode = "all")

# Create an edge color vector for all edges
edge_cols <- rep("grey70", ecount(g))
edge_cols[connected_to_hlife] <- "black"

E(g)$edge_color <- edge_cols

plot_list[[as.numeric(window)]] <- ggraph(g, layout = "manual", x = x, y = y) +
  geom_edge_link(aes(width = partial_r,  colour= edge_color)) +
  #geom_node_point(size = 12, colour = "white") +
  geom_node_label(aes(label = name, fill=name), size =4, label.r = unit(7, "pt"),
                  label.padding = unit(6, "pt")) +
  scale_edge_width(limits = c(0.05,   0.5), # partial correlation values
                   range =  c(0.1, 4)) + # line thickness values
  scale_fill_manual(values=c("#E78AC3FF" ,"#8DA0CBFF", "#FC8D62FF",  "lightgrey","#66C2A5FF","#A6D854FF" ))+
  scale_edge_colour_manual(values=c("black","grey80"))+
  #scale_edge_colour_gradient2(low = "red", mid = "grey80", high = "blue") +
  labs(title=paste("Time window:", window))+
   theme_void()+
   theme(legend.position = "none",
         plot.background = element_rect(fill="white"))
#print(plot)


}

ggarrange(plot_list[[1]], plot_list[[2]], plot_list[[3]], nrow=1, ncol=3)

ggsave(paste0("/Users/niamhdooley/Library/CloudStorage/OneDrive-RoyalCollegeofSurgeonsinIreland/DOROTHY CO-FUND/WP2-Understanding Society/Project A. Targets for intervention in life satisfaction/R outputs/networkplots/3windows.tiff"), units="in", width=20, height=5, dpi=600, compression = 'lzw')
library(ppcor)
library(reshape2)

# save correlation between happiness in each domain & general life happiness
cortbl <- data.frame(year = sort(unique(usoc$int.year.sched)), 
                      r.sch = NA,
                      r.schwk = NA,
                      r.fam = NA,
                      r.frnd = NA,
                      r.app = NA,
                  
                      p.sch = NA,
                      p.schwk = NA,
                      p.fam = NA,
                      p.frnd = NA,
                      p.app = NA)


for (y in sort(unique(usoc$int.year.sched))){
  
# pearson's bivariate correlations
 cortbl$r.sch[cortbl$year==y] <- cor(usoc$h.life[usoc$int.year.sched==y], usoc$h.school[usoc$int.year.sched==y],use="complete.obs")
 cortbl$r.schwk[cortbl$year==y] <- cor(usoc$h.life[usoc$int.year.sched==y], usoc$h.schoolwork[usoc$int.year.sched==y],use="complete.obs")
 cortbl$r.fam[cortbl$year==y] <- cor(usoc$h.life[usoc$int.year.sched==y], usoc$h.fam[usoc$int.year.sched==y],use="complete.obs")
 cortbl$r.frnd[cortbl$year==y] <- cor(usoc$h.life[usoc$int.year.sched==y], usoc$h.friends[usoc$int.year.sched==y],use="complete.obs")
 cortbl$r.app[cortbl$year==y] <- cor(usoc$h.life[usoc$int.year.sched==y], usoc$h.appear[usoc$int.year.sched==y],use="complete.obs")
  
 # partial correlations
 p <- pcor(na.omit(usoc[usoc$int.year.sched==y,
                        c("h.life", "h.school", "h.schoolwork", "h.fam", "h.friends", "h.appear")]))$estimate
 p2 <- p
 p2[lower.tri(p)] <- NA

 p3 <- melt(p2, na.rm=T)
 plife <- p3[p3$value!=1 & p3$Var1=="h.life",]
 
 cortbl$p.sch[cortbl$year==y] <- plife$value[plife$Var2=="h.school"]
 cortbl$p.schwk[cortbl$year==y] <- plife$value[plife$Var2=="h.schoolwork"]
 cortbl$p.fam[cortbl$year==y] <- plife$value[plife$Var2=="h.fam"]
 cortbl$p.frnd[cortbl$year==y] <- plife$value[plife$Var2=="h.friends"]
 cortbl$p.app[cortbl$year==y] <- plife$value[plife$Var2=="h.appear"]
}

# plot these estimates as barchart

long.cor <- cortbl %>%
  dplyr::select(year, r.sch,  r.schwk ,r.fam ,r.frnd , r.app)%>%
  gather(key = "domain", value="corr", -year)

long.partcor <- cortbl %>%
  dplyr::select(year, p.sch,  p.schwk ,p.fam ,p.frnd , p.app)%>%
  gather(key = "domain", value="partialcorr", -year)

long.cor <- cbind(long.cor, long.partcor[,"partialcorr"])
names(long.cor)[str_detect(names(long.cor), "partialcorr")] <- "partialcorr"

long.cor$`Happiness with...` <- factor(long.cor$domain, 
                                   levels=c( "r.fam" ,"r.frnd" ,"r.sch",  "r.schwk" , "r.app"),
                                   labels=c( "Family" , "Friends", 
                                             "School", "Schoolwork",
                                             "Appearance" ))
# bivariate correlations
ggplot(data=long.cor, aes(x=year, y=corr))+
  geom_col(aes(fill=`Happiness with...`), alpha=0.7)+
  geom_smooth(aes(x=year, y=corr), method="lm", formula=y~poly(x,2), colour="black", se=F)+
  geom_smooth(aes(x=year, y=corr), colour="grey40", se=F)+
  labs(y="Association with general life happiness (corr)\n", x="\nSurvey year", title="Bivariate correlations")+
  facet_grid(~`Happiness with...`)+
  #scale_y_continuous(limits=c(0, 0.5))+
  scale_x_continuous(breaks= seq(2010,2024,2),  limits = c(2008,2025), name = "")+
  scale_fill_manual(values=cols5)+
  scale_colour_manual(values=cols5)+
  theme_minimal()+
  theme(axis.text.x = element_text(size=7, angle=60, hjust=1, vjust = 1),
        panel.grid.minor.x = element_blank(),
        panel.grid.minor.y = element_blank())
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

# partial correlations
ggplot(data=long.cor, aes(x=year, y=partialcorr))+
  geom_col(aes(fill=`Happiness with...`), alpha=0.7)+
  geom_smooth(aes(x=year, y=partialcorr), method="lm", formula=y~poly(x,2), colour="black", se=F)+
  geom_smooth(aes(x=year, y=partialcorr), colour="grey40", se=F)+
  labs(y="Association with general life happiness (pcorr)\n", x="\nSurvey year", title="Partial correlations")+
  facet_grid(~`Happiness with...`)+
  #scale_y_continuous(limits=c(0, 0.5))+
  scale_x_continuous(breaks= seq(2010,2024,2),  limits = c(2008,2025), name = "")+
  scale_fill_manual(values=cols5)+
  scale_colour_manual(values=cols5)+
  theme_minimal()+
  theme(axis.text.x = element_text(size=7, angle=60, hjust=1, vjust = 1),
        panel.grid.minor.x = element_blank(),
        panel.grid.minor.y = element_blank())
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

# note: these partial correlations can't be compared directly with results of the svyglm

# plot network diagram for connection between domains

You need to think about what this means: - the bivariate correlation between all subdomains and happiness with life in general is increasing over time…. these 5 domain have become more important? What hasnt? Or all are subject to higher scores (i.e. satisfacation with everything is decreasing) -

Sensitivity analyses

1. Representativeness checks

# 1. PLOT THE Ns (AGAIN) TO SUPPORT OVERALL ATTRITION 
n_year <- usoc %>%
  filter(!is.na(h.life.c)) %>%
  group_by(int.year.sched) %>%
  summarise(n = n_distinct(pidp), .groups = "drop")

ggplot(n_year, aes(x = int.year.sched, y = n)) +
  geom_col(fill = "#4477AA", alpha = 0.85) +
  geom_text(aes(label = n), vjust = -0.4, size = 3) +
  scale_x_continuous(breaks = seq(2009, 2024, 2)) +
  labs(title = "Fig 1. Sample size by year",
       subtitle = "N with complete life satisfaction data",
       x = "Year", y = "N participants") +
  theme_classic(base_size = 12) +
  theme(plot.title = element_text(face = "bold"))

#  2. VISUALISE THE CHANGES IN DEMOGRAPHY

# --- 2a. Age distribution ---
age_year <- usoc %>%
  group_by(int.year.sched, dvage) %>%
  summarise(n = n_distinct(pidp), .groups = "drop") %>%
  group_by(int.year.sched) %>%
  mutate(prop = n / sum(n))

fig2a <- ggplot(age_year, aes(x = int.year.sched, y = prop, fill = dvage)) +
  geom_area(alpha = 0.85, colour = "white", linewidth = 0.3) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_brewer(palette = "Blues", name = "Age") +
  scale_x_continuous(breaks = seq(2009, 2024, 2)) +
  labs(title = "Age composition", x = "Year", y = "% of sample") +
  theme_classic(base_size = 11)

# --- 2b. Sex distribution ---
sex_year <- usoc %>%
  filter(!is.na(sex.bin)) %>%
  group_by(int.year.sched, sex.bin) %>%
  summarise(n = n_distinct(pidp), .groups = "drop") %>%
  group_by(int.year.sched) %>%
  mutate(prop = n / sum(n))

fig2b <- ggplot(sex_year, aes(x = int.year.sched, y = prop, fill = sex.bin)) +
  geom_area(alpha = 0.8, colour = "white", linewidth = 0.3) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_manual(values = c("Male" = "#4477AA", "Female" = "#EE6677"), name = "Sex") +
  scale_x_continuous(breaks = seq(2009, 2024, 2)) +
  labs(title = "Sex composition", x = "Year", y = "% of sample") +
  theme_classic(base_size = 11)

# --- 2c. Ethnicity distribution ---
eth_year <- usoc %>%
  filter(!is.na(ethnicity)) %>%
  group_by(int.year.sched, ethnicity) %>%
  summarise(n = n_distinct(pidp), .groups = "drop") %>%
  group_by(int.year.sched) %>%
  mutate(prop = n / sum(n))

fig2c <- ggplot(eth_year, aes(x = int.year.sched, y = prop, fill = ethnicity)) +
  geom_area(alpha = 0.85, colour = "white", linewidth = 0.3) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_brewer(palette = "Set2", name = "Ethnicity") +
  scale_x_continuous(breaks = seq(2009, 2024, 2)) +
  labs(title = "Ethnicity composition", x = "Year", y = "% of sample") +
  theme_classic(base_size = 11) +
  theme(legend.text = element_text(size = 8),
        legend.position = "right",
        axis.text.x = element_text(angle = 30, hjust = 1))


# --- 2d. Income (mean equivalised hsd income by year; capped at 8000pm for visualisation) ---
inc_year <- usoc %>%
  filter(!is.na(equivinc.capped)) %>%
  group_by(int.year.sched) %>%
  summarise(mean_inc  = mean(equivinc.capped, na.rm = TRUE),
            se_inc    = sd(equivinc.capped, na.rm = TRUE) / sqrt(n()),
            .groups   = "drop") %>%
  mutate(lo = mean_inc - 1.96 * se_inc,
         hi = mean_inc + 1.96 * se_inc)

fig2d <- ggplot(inc_year, aes(x = int.year.sched, y = mean_inc)) +
  geom_ribbon(aes(ymin = lo, ymax = hi), fill = "#AABB99", alpha = 0.4) +
  geom_line(colour = "#446633", linewidth = 1) +
  geom_point(colour = "#446633", size = 2) +
  scale_x_continuous(breaks = seq(2009, 2024, 2)) +
  labs(title = "Household income (mean equiv.)",
       x = "Year", y = "£ per month (equivalised)") +
  theme_classic(base_size = 11)

fig2 <- ggarrange(fig2a, fig2b, fig2c, fig2d, ncol = 2, nrow = 2,
                  labels = c("A", "B", "C", "D"))
fig2

ggsave(paste0(path,"Project A. Targets for intervention in life satisfaction/R outputs/sample_composition.tiff"), units="in", width=9, height=10, dpi=600, compression = 'lzw')
eth_year <- usoc %>%
  filter(!is.na(ethnicity)) %>%
  group_by(int.year.sched, ethnicity) %>%
  summarise(n = n_distinct(pidp), .groups = "drop") %>%
  group_by(int.year.sched) %>%
  mutate(prop = n / sum(n))

fig1 <- ggplot(eth_year, aes(x = int.year.sched, y = prop, fill = ethnicity)) +
  geom_area(alpha = 0.85, colour = "white", linewidth = 0.3) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_brewer(palette = "Set2", name = "Ethnicity") +
  scale_x_continuous(breaks = seq(2009, 2024, 2)) +
  labs(x = "Year", y = "% of sample") +
  theme_classic(base_size = 10) +
  theme(legend.text = element_text(size = 9),
        axis.text.x = element_text(angle = 30, hjust = 1))

# weighted by youth weight
eth_weighted1 <- usoc %>%
  filter(!is.na(ethnicity), !is.na(wgt.rescaled), wgt.rescaled > 0) %>%
  group_by(int.year.sched, ethnicity) %>%
  summarise(wgt_n = sum(wgt.rescaled), .groups = "drop") %>%
  group_by(int.year.sched) %>%
  mutate(prop_wtd = wgt_n / sum(wgt_n))

fig2<-ggplot(eth_weighted1, aes(x = int.year.sched, y = prop_wtd, fill = ethnicity)) +
  geom_area(alpha = 0.85, colour = "white", linewidth = 0.3) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_brewer(palette = "Set2", name = "Ethnicity") +
  scale_x_continuous(breaks = seq(2009, 2024, 2)) +
  labs(
       x = "Year", y = "% of sample (weighted)") +
  theme_classic(base_size = 10)+
  theme(legend.text = element_text(size = 9),
        axis.text.x = element_text(angle = 30, hjust = 1))

fig <- ggarrange(fig1, fig2,  ncol = 2, nrow = 1,
                  labels = c("Unweighted", "Weighted"), common.legend = T, legend = "right")
fig <- annotate_figure(fig, top = text_grob("Ethnic diversity over time",
                                               face = "bold", size = 13))
fig

We can see that the % of minority ethnicities “peak” around 2015 and 2023 around the times of IEM sample boosting. The weights seem to adjust for that design-related bias. Even with the weighting, the proportion of ethnic minorities (all others not British/Irish) rise over time, and rise steeply from 2021.

The increase in proportion of ethnic minorities reflects census data in the UK, at least from the late 2011 to 2021: https://www.bbc.co.uk/bitesize/guides/z334nbk/revision/5

2021 was the most recent census. The next UK census will be in 2031.

# 3a. Mean life satisfaction by year 
life_year <- usoc %>%
  filter(!is.na(h.life.c)) %>%
  group_by(int.year.sched) %>%
  summarise(mean_life = mean(h.life.c, na.rm = TRUE),
            se_life   = sd(h.life.c, na.rm = TRUE) / sqrt(n()),
            .groups   = "drop") %>%
  mutate(lo = mean_life - 1.96 * se_life,
         hi = mean_life + 1.96 * se_life)

fig3a <- ggplot(life_year, aes(x = int.year.sched, y = mean_life)) +
  geom_ribbon(aes(ymin = lo, ymax = hi), fill = "#E78AC3", alpha = 0.35) +
  geom_line(colour = "#C6007E", linewidth = 1) +
  geom_point(colour = "#C6007E", size = 2) +
  scale_x_continuous(breaks = seq(2009, 2024, 2)) +
  labs(title = "Mean life satisfaction over time",
       x = "Year", y = "Mean h.life.c (centred)") +
  theme_classic(base_size = 11)

# 3b. Stacked proportions of response categories 
# h.life.c is the centred version (-3 to +3); use the raw response for categories
# The raw variable is h.life (1–7 scale) or the centred version with integer values
life_dist <- usoc %>%
  filter(!is.na(h.life.c)) %>%
  mutate(response = factor(h.life.c,
                           levels = sort(unique(h.life.c)),
                           labels = as.character(sort(unique(h.life.c))))) %>%
  group_by(int.year.sched, response) %>%
  summarise(n = n(), .groups = "drop") %>%
  group_by(int.year.sched) %>%
  mutate(prop = n / sum(n))

fig3b <- ggplot(life_dist, aes(x = int.year.sched, y = prop, fill = response)) +
  geom_area(alpha = 0.85, colour = "white", linewidth = 0.2) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_brewer(palette = "RdYlGn", name = "Response\n(–3 to +3)",
                    direction = 1) +
  scale_x_continuous(breaks = seq(2009, 2024, 2), minor_breaks = seq(2010, 2024, 2)) +
  labs(title = "Response distribution over time",
       x = "Year", y = "% of sample") +
  theme_classic(base_size = 11) +
  theme(legend.text = element_text(size = 8))

ggsave(paste0(path, "Project A. Targets for intervention in life satisfaction/R outputs/lifesatis_unwgtd_distrib_overtime.png"), fig3b,   width = 6, height = 6, dpi = 350)

# 3c. % at lowest response (most unhappy = –3)
# This directly addresses whether floor effects / zero-inflation are growing
life_floor <- usoc %>%
  filter(!is.na(h.life.c)) %>%
  group_by(int.year.sched) %>%
  summarise(prop_floor = mean(h.life.c == min(h.life.c, na.rm = TRUE), na.rm = TRUE),
            .groups    = "drop")

fig3c <- ggplot(life_floor, aes(x = int.year.sched, y = prop_floor)) +
  geom_col(fill = "#AA3333", alpha = 0.8) +
  geom_smooth(method = "lm", se = FALSE, colour = "#AA3333",
              linewidth = 0.8, linetype = "dashed") +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_x_continuous(breaks = seq(2009, 2024, 2)) +
  labs(title = "% selecting lowest response (most unhappy)",
       subtitle = "Rising trend suggesting floor-effect growth, not just mean shift",
       x = "Year", y = "% of sample") +
  theme_classic(base_size = 11)

fig3 <- ggarrange(fig3a, fig3b, fig3c, ncol = 3, labels = c("A", "B", "C"),
                  widths = c(1, 1.2, 1))
## `geom_smooth()` using formula = 'y ~ x'
fig3 <- annotate_figure(fig3, top = text_grob(
  "Fig 3. Life satisfaction over time", face = "bold", size = 13))


print(fig3)

#  4. DEFINE ATTRITION & VISUALISE RATE 
# "Attrition" = a participant who was age-eligible for the next wave (age < 15)
# but did NOT appear in that next wave.
# We identify this by checking, for each pidp x wave observation (where age < 15),
# whether that pidp appears in the immediately following wave.


usoc_sorted <- usoc %>%
  arrange(pidp, wave.n)

# For each participant, list of waves they appeared in
wave_presence <- usoc_sorted %>%
  dplyr::select(pidp, wave.n, dvage.n) %>%
  distinct()

# create atttrition indicator at participant-wave level
wave_presence <- wave_presence %>%
  group_by(pidp) %>%
  arrange(wave.n) %>%
  mutate(
    next_wave      = wave.n + 1,
    appeared_next  = next_wave %in% wave.n,         # did they come back?
    age_eligible   = dvage.n < 15,                  # still young enough to return?
    attrited       = age_eligible & !appeared_next  # dropped out while still eligible
  ) %>%
  ungroup()

# Merge back to get year info
wave_presence <- wave_presence %>%
  left_join(usoc %>% 
              dplyr::select(pidp, wave.n, int.year.sched) %>% 
              distinct(), by = c("pidp", "wave.n"))

# attrition rate by yr (among those still age-eligible)
att_year <- wave_presence %>%
  filter(age_eligible) %>%
  group_by(int.year.sched) %>%
  summarise(n_eligible  = n(),
            n_attrited  = sum(attrited, na.rm = TRUE),
            att_rate    = n_attrited / n_eligible,
            .groups     = "drop")

ggplot(att_year[att_year$int.year.sched<2024,], aes(x = int.year.sched, y = att_rate)) +
  geom_col(fill = "#BB5522", alpha = 0.8) +
  geom_text(aes(label = paste0(round(att_rate * 100, 1), "%")), vjust = -0.4, size = 3) +
  scale_y_continuous(labels = scales::percent_format(), limits = c(0, 1)) +
  scale_x_continuous(breaks = seq(2009, 2024, 2)) +
  labs(title = "Year-to-year attrition rate",
       subtitle = "Among participants still eligible (age < 15) in each year",
       x = "Year", y = "Attrition rate") +
  theme_classic(base_size = 12) +
  theme(plot.title = element_text(face = "bold"))

ggsave(paste0(path, "Project A. Targets for intervention in life satisfaction/R outputs/overall_attrition.tiff"), units="in", width=8, height=6, dpi=600, compression = 'lzw')



# 5. LOGISTIC REGRESSION: PREDICTORS OF ATTRITION

# Predictors: age, sex, ethnicity, income, country, life satisfaction

# create analytic dataset (one row per eligible participant-wave)
model_df <- wave_presence %>%
  filter(age_eligible) %>%
  left_join(
    usoc %>%
      dplyr::select(pidp, wave.n, sex.bin, ethnicity, country, equivinc.capped,
             h.life.c) %>%
      distinct(),
    by = c("pidp", "wave.n")
  ) %>%
  mutate(
    attrited_01 = as.integer(attrited),
    # Scale continuous predictors for comparability
    age_z       = scale(dvage.n)[, 1],
    year_c      = scale(int.year.sched, scale=F), # centre year ~2014
    inc_z       = scale(equivinc.capped)[, 1],
    life_z      = scale(h.life.c)[, 1]
  ) %>%
  filter(!is.na(attrited_01), !is.na(sex.bin), !is.na(ethnicity))

# Two models:
#   mod_base — full sample; life satisfaction is a key predictor alongside demographics
#   mod_int — full sample; added intercation between time and life satisfaction

mod_base <- glm(attrited_01 ~ age_z + sex.bin + ethnicity + country + inc_z + life_z,
                data   = model_df,
                family = binomial(link = "logit"))

mod_int <- glm(attrited_01 ~ age_z + sex.bin + ethnicity + country + inc_z + life_z*year_c,
                data   = model_df,
                family = binomial(link = "logit"))

# print results of main model
cat("\n--- Main model (life satisfaction + demographics) ---\n")
## 
## --- Main model (life satisfaction + demographics) ---
print(summary(mod_base))
## 
## Call:
## glm(formula = attrited_01 ~ age_z + sex.bin + ethnicity + country + 
##     inc_z + life_z, family = binomial(link = "logit"), data = model_df)
## 
## Coefficients:
##                                     Estimate Std. Error z value Pr(>|z|)    
## (Intercept)                         -0.89770    0.01905 -47.125  < 2e-16 ***
## age_z                                0.06453    0.01121   5.759 8.47e-09 ***
## sex.binMale                          0.05657    0.02224   2.543  0.01099 *  
## ethnicityAny other white background  0.37656    0.07854   4.794 1.63e-06 ***
## ethnicitySouth or East Asian         0.38224    0.03360  11.375  < 2e-16 ***
## ethnicityAfrican or Caribbean        0.68029    0.05022  13.547  < 2e-16 ***
## ethnicityMixed background            0.22875    0.04935   4.635 3.56e-06 ***
## ethnicityOther                       0.41224    0.07118   5.791 6.99e-09 ***
## countryWales                         0.13370    0.05070   2.637  0.00836 ** 
## countryScotland                      0.01855    0.04215   0.440  0.65980    
## countryNorthern Ireland              0.04578    0.04813   0.951  0.34158    
## inc_z                                0.06084    0.01114   5.463 4.68e-08 ***
## life_z                              -0.05230    0.01112  -4.703 2.57e-06 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 47211  on 37517  degrees of freedom
## Residual deviance: 46832  on 37505  degrees of freedom
##   (549 observations deleted due to missingness)
## AIC: 46858
## 
## Number of Fisher Scoring iterations: 4
or_base <- clean_labels(extract_ors(mod_base, "Main model"))
or_int <- clean_labels(extract_ors(mod_int, "Interaction model"))

# just plot predictors of attrition from or_base main effects model
ggplot(or_base, aes(x = or, y = reorder(term, or),
                             colour = sig)) +
  geom_vline(xintercept = 1, linetype = "dashed", colour = "grey50") +
  geom_errorbarh(aes(xmin = lo, xmax = hi), height = 0.3, linewidth = 0.7) +
  geom_point(size = 3.5) +
  scale_colour_manual(values = c("p < .05" = "#BB5522", "ns" = "#888888"), name = NULL) +
  scale_shape_manual(values  = c("Life satisfaction" = 18, "Other" = 16), guide = "none") +
  scale_x_log10() +
  labs(title    = "Predictors of attrition (OR, 95% CI)",
       subtitle = paste0("Analytic sample (n = ", nrow(model_df[!is.na(model_df$attrited_01),]), ").\n",
                         "Outcome = dropped out of next wave while still eligible (age < 15).\n",
                         "Continuous predictors standardised. "),
       x = "Odds Ratio (log scale) ±95% CI", y = NULL) +
  theme_classic(base_size = 12) +
  theme(plot.title    = element_text(face = "bold"),
        legend.position = "bottom")
## Warning: `geom_errobarh()` was deprecated in ggplot2 4.0.0.
## ℹ Please use the `orientation` argument of `geom_errorbar()` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## `height` was translated to `width`.

ggsave(paste0(path, "Project A. Targets for intervention in life satisfaction/R outputs/predictors_attrition.tiff"), units="in", width=8, height=6, dpi=600, compression = 'lzw')
## `height` was translated to `width`.
ggplot(or_int, aes(x = or, y = reorder(term, or),
                             colour = sig)) +
  geom_vline(xintercept = 1, linetype = "dashed", colour = "grey50") +
  geom_errorbarh(aes(xmin = lo, xmax = hi), height = 0.3, linewidth = 0.7) +
  geom_point(size = 3.5) +
  scale_colour_manual(values = c("p < .05" = "#BB5522", "ns" = "#888888"), name = NULL) +
  scale_shape_manual(values  = c("Life satisfaction" = 18, "Other" = 16), guide = "none") +
  scale_x_log10() +
  labs(title    = "Predictors of attrition (OR, 95% CI)",
       subtitle = paste0("Analytic sample (n = ", nrow(model_df[!is.na(model_df$attrited_01),]), ").\n",
                         "Outcome = dropped out of next wave while still eligible (age < 15).\n",
                         "Continuous predictors standardised. "),
       x = "Odds Ratio (log scale) ±95% CI", y = NULL) +
  theme_classic(base_size = 12) +
  theme(plot.title    = element_text(face = "bold"),
        legend.position = "bottom")
## `height` was translated to `width`.

#  6. LIFE SATISFACTION AS PREDICTOR OF ATTRITION – predicted probabilities
#
# Predicted probability of attrition across the life satisfaction range,
# holding all other predictors constant..

life_vals <- model_df$h.life.c
life_z_seq <- seq(min(scale(life_vals)[,1], na.rm = TRUE),
                  max(scale(life_vals)[,1], na.rm = TRUE), length.out = 100)

newdat_life <- data.frame(
  life_z    = life_z_seq,
  age_z     = 0,
  sex.bin     = factor("Female", levels = c("Male", "Female")),
  ethnicity = levels(usoc$ethnicity)[1],
  country   = levels(factor(model_df$country))[1],
  inc_z     = 0
)

# Get predicted probabilities with proper 95% CI via se.fit
pred_life      <- predict(mod_base, newdata = newdat_life, type = "link", se.fit = TRUE)
newdat_life$pred_prob <- plogis(pred_life$fit)
newdat_life$lo        <- plogis(pred_life$fit - 1.96 * pred_life$se.fit)
newdat_life$hi        <- plogis(pred_life$fit + 1.96 * pred_life$se.fit)

# Back-transform z-score to raw h.life.c for axis
life_mean <- mean(life_vals, na.rm = TRUE)
life_sd   <- sd(life_vals,   na.rm = TRUE)
newdat_life$life_raw <- life_z_seq * life_sd + life_mean

ggplot(newdat_life, aes(x = life_raw, y = pred_prob)) +
  geom_ribbon(aes(ymin = lo, ymax = hi), fill = "#E78AC3", alpha = 0.3) +
  geom_line(colour = "#C6007E", linewidth = 1.2) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_x_continuous(breaks = sort(unique(round(life_vals)))) +
  labs(title    = "Fig 6. Predicted probability of attrition by life satisfaction score",
       subtitle = "Other predictors held at mean/modal value. Shaded = 95% CI.",
       x        = "Life satisfaction (h.life.c, centred)",
       y        = "Predicted probability of attrition") +
  theme_classic(base_size = 12) +
  theme(plot.title = element_text(face = "bold"))

# Fig 6. shows those with lower life satisfaction are more likely to attrit. The adjusted difference in probability of attriiton isnt massive though: ~6% difference between those at extreme ends of the satisfaction spectrum.

2. SDQ as alternative to Life satisfaction

SDQ as correlate of satisfaction with aspects of life

sdq.coefs.wgts <- c() # data frame to store B coef and SEs of domain onto SDQ total, for each wave of data


 for (year.x in sort(unique(usoc$int.year.sched)) ){

  # extract cross-sec data for wave x
  xs <- usoc[usoc$int.year.sched==year.x,]

  # exclude participants with missing data on any life satis var OR the SDQ (note: will remove many participants as only done every 2nd wave)
  xs <- xs[!is.na(xs$ypsdqtd_dv) & !is.na(xs$h.school.c) & !is.na(xs$h.schoolwork.c) & !is.na(xs$h.friends.c) & !is.na(xs$h.fam.c) & !is.na(xs$h.appear.c), ]
  
  # set svy design for this wave
  usoc.svy <- svydesign(id=~psu + hidp, 
                        strata=~strata, 
                        weights=~wgt.rescaled, 
                        data=xs,
                        nest=TRUE)
  
  options(survey.lonely.psu = "adjust") # tells the survey package to handle singleton PSUs by scaling their variance estimates
  
  svyglm1 <- svyglm(formula = ypsdqtd_dv ~ h.school.c + h.schoolwork.c + h.friends.c + h.fam.c + h.appear.c,
          design = usoc.svy)
  
  x= as.data.frame(summary(svyglm1)[["coefficients"]])
  
  sdq.coefs.wgts <- rbind(sdq.coefs.wgts, c(as.numeric(coef(svyglm1)), # betas
                                    as.numeric(x[,2])) ) # SEs
 }  



sdq.coefs.wgts <- cbind(sort(unique(usoc$int.year.sched)), as.data.frame(round(sdq.coefs.wgts,4)))

names(sdq.coefs.wgts) <- c("year", "B.intercept", "B.school", "B.schoolwork", "B.friends", "B.family", "B.appearance",
                       "SE.intercept", "SE.school", "SE.schoolwork", "SE.friends", "SE.family", "SE.appearance")


# re-structure to long-format data
long.wgts <- sdq.coefs.wgts %>%
  dplyr::select(year, B.school, B.schoolwork, B.friends, B.family, B.appearance)%>%
  gather(key = "domain", value="Beta", -year)
long.se <- sdq.coefs.wgts %>%
  dplyr::select(year, SE.school, SE.schoolwork, SE.friends, SE.family, SE.appearance)%>%
  gather(key = "domain", value="SE", -year)

sdq.wgts.long <- cbind(long.wgts, long.se[,"SE"])
names(sdq.wgts.long)[4] <- "SE"
sdq.wgts.long$year.n <- as.numeric(sdq.wgts.long$year)-2009

sdq.wgts.long$`Happiness with...` <- factor(sdq.wgts.long$domain, 
                                   levels=c( "B.family" , "B.friends", 
                                             "B.school", "B.schoolwork",
                                             "B.appearance" ),
                                   labels=c( "Family" , "Friends", 
                                             "School", "Schoolwork",
                                             "Appearance" ))
# save meta-regression output here:
sdq.wgt.avgs <- c()
sdq.wgt.trends  <- c()
#wgt.trends.5ywin  <- c()

library(metafor)

for (domain in levels(as.factor(sdq.wgts.long$domain))) {

  dat <- sdq.wgts.long[sdq.wgts.long$domain==domain, ]
  
  D <- diag(dat$SE, 16, 16)
  V <- D %*% R %*% D
  
  # intercept-only M.A: What is the pooled mean across all my waves?
  rma.ave <- rma.mv(yi = Beta,
                    V = V,
                    data=dat) 
       
        # save
        sdq.wgt.avgs <- rbind(sdq.wgt.avgs, data.frame(
                                      domain = domain,
                                      beta = as.numeric(rma.ave[["beta"]]), 
                                      se = as.numeric(rma.ave[["se"]]),
                                      ci.low = as.numeric(rma.ave[["ci.lb"]]), 
                                      ci.hi = as.numeric(rma.ave[["ci.ub"]])) )
  
  # include time as moderator...
  # full time period (waves 1-14)
  rma.trend.full <- rma.mv(yi = Beta,
                           V = V,
                           mods = ~ year.n,
                           data = dat)
         # save
         sdq.wgt.trends <- rbind(sdq.wgt.trends, data.frame(
                                           domain=domain,
                                           beta=as.numeric(rma.trend.full[["beta"]][2]),
                                           se=as.numeric(rma.trend.full[["se"]][2]),
                                           ci.low=as.numeric(rma.trend.full[["ci.lb"]][2]),
                                           ci.hi=as.numeric(rma.trend.full[["ci.ub"]][2]),
                                           p=round(as.numeric(rma.trend.full[["pval"]][2]),4)))
         
    # Note: no analysis within 5-year windows. There's so much year-to-year fluctuation with this data, I don't think we should be looking at within-5 year changes. Perhaps we could show *average* associations within each 5-year window, to average out some of those fluctuations.

}

sdq.wgt.trends[,c(2:6)] <- round(sdq.wgt.trends[,c(2:6)], 3)
# bar chart
ggplot(data=sdq.wgts.long, aes(x=year, y=Beta))+
  geom_col(aes(fill=`Happiness with...`), alpha=0.5)+
  geom_errorbar(aes(ymin=Beta-SE, ymax=Beta+SE, colour=`Happiness with...`), width=0)+
  geom_smooth(aes(x=year, y=Beta), method="lm", formula = y~x, colour="black", se=T, size=0.8)+
  geom_smooth(aes(x=year, y=Beta), method="loess",  colour="grey50", se=F, size=0.8)+
  labs(y="Adjusted association with SDQ total (B ± 1 
       SE)\n", x="\nSurvey year")+
  facet_grid(~`Happiness with...`)+
  scale_x_continuous(breaks= seq(2010,2024,2),  limits = c(2008,2025), name = "")+
  coord_cartesian(ylim=c(-2.0, 0))+
  scale_fill_manual(values=cols5)+
  scale_colour_manual(values=cols5)+
  theme_minimal()+
  theme(axis.text.x = element_text(size=8, angle=60, hjust=1, vjust = 1),
        #panel.grid.major.x = element_blank(),
        panel.grid.minor.x = element_blank(),
        panel.grid.minor.y = element_blank(),
        legend.position="none")

ggsave(paste0(path,"Project A. Targets for intervention in life satisfaction/R outputs/weights_over_time_wSDQ.tiff"), units="in", width=10, height=5, dpi=600, compression = 'lzw')


# lots of year-to-year fluctuation-- what if we averaged in 5-year segments?
sdq.wgts.long$windows <-  cut(sdq.wgts.long$year, breaks=c(2009, 2014, 2019, 2025), labels=c(1, 2, 3))

  
# plot a bar for each 5-yr window
 sdq.wgts.long.win <- sdq.wgts.long %>%
  group_by(windows, `Happiness with...`) %>%
  summarise(m=mean(Beta),
            se=mean(SE)) # questionable average of SE
 
ggplot(data=sdq.wgts.long.win[!is.na(sdq.wgts.long.win$windows),], aes(x=windows, y=m))+
  geom_col(aes(fill=`Happiness with...`), alpha=0.5)+
  geom_errorbar(aes(ymin=m-se, ymax=m+se, colour=`Happiness with...`), width=0)+
  labs(y="Adjusted association with SDQ total (B ± 1 SE)\n", x="\n5-year Windows")+
  facet_grid(~`Happiness with...`)+
  #scale_x_continuous(breaks= seq(2010,2024,2),  limits = c(2008,2025), name = "")+
  coord_cartesian(ylim=c(-2.0, 0))+
  scale_fill_manual(values=cols5)+
  scale_colour_manual(values=cols5)+
  theme_minimal()+
  theme(axis.text.x = element_text(size=8, hjust=1, vjust = 1),
        #panel.grid.major.x = element_blank(),
        panel.grid.minor.x = element_blank(),
        panel.grid.minor.y = element_blank(),
        legend.position="none")

3. Removing the COVID years from analyses

Training

Online training videos: https://open.essex.ac.uk/course/view.php?id=221

Support forum: https://iserredex.essex.ac.uk/support/projects/support