packages <- c("knitr","ggplot2","jsonlite","readxl")
missing <- packages[!vapply(packages,requireNamespace,logical(1),quietly=TRUE)]
if(length(missing))stop("Install missing packages in the Console: ",paste(missing,collapse=", "),call.=FALSE)
# No setwd() and no root.dir override: keep the QMD in your cortisol folder.
if(!exists("params"))params<-list(workbook_file="LIFE_RESIST_outputs/LIFE_RESIST_Merged_Baseline.xlsx",
data_file="LIFE_RESIST_outputs/LIFE_RESIST_Merged_Baseline.csv",output_dir="LIFE_RESIST_Within_Diagnosis_outputs")
if(!file.exists(params$data_file) && !file.exists(params$workbook_file))
stop("Extract LIFE_RESIST_outputs beside this QMD; merged input data are missing.",call.=FALSE)
D<-if(file.exists(params$workbook_file))as.data.frame(readxl::read_excel(params$workbook_file,sheet="Merged baseline")) else
read.csv(params$data_file,stringsAsFactors=FALSE,check.names=FALSE,na.strings=c("","NA"))
required<-c("participant_key","study","sex","current_mdd_source","antidepressant_group_source","phq9_raw",
"age","bmi",paste0("c",1:5,"_nmol_l"),paste0("t",1:5,"_hours"),"dex_ic50","pred_ic50")
if(length(setdiff(required,names(D))))stop("Missing merged fields: ",paste(setdiff(required,names(D)),collapse=", "))
if(anyDuplicated(D$participant_key))stop("Duplicate baseline participant keys.")
dir.create(params$output_dir,recursive=TRUE,showWarnings=FALSE)
out<-function(x)file.path(params$output_dir,x)
as_num<-function(x)suppressWarnings(as.numeric(as.character(x)))
for(v in setdiff(required,c("participant_key","study","sex")))D[[v]]<-as_num(D[[v]])
D$eligible_pooled<-D$sex %in% c("Men","Women")
D$healthy_pooled<-D$eligible_pooled & D$study=="RESIST" & !is.na(D$antidepressant_group_source) & D$antidepressant_group_source==0
D$flag_life_current0_phq_gt7<-D$study=="LIFE" & !is.na(D$current_mdd_source) & D$current_mdd_source==0 & !is.na(D$phq9_raw) & D$phq9_raw>7
stopifnot(!any(D$healthy_pooled & D$study=="LIFE"))
write.csv(D[D$flag_life_current0_phq_gt7,,drop=FALSE],out("LIFE_Diagnostic_Review.csv"),row.names=FALSE,na="")Cortisol profiles, within diagnosis sex differences and power
Version v1.5.0 and scope
Women-versus-men endpoint comparisons are performed within verified controls and within current depression. At each of five saliva sampling occasions, controls are also compared with depression separately within men and within women. There are no overall sex comparisons pooling diagnoses. A new publication chunk adds sex-by-diagnosis interaction contrasts and overall controls-versus-depression comparisons, with numbered main and supplementary outputs. Cohorts are pooled within diagnosis. All P values are unadjusted, with no FDR or other multiplicity correction. Prior versions are retained in Git.
Welch tests compare log waking cortisol, log AUCg and log IC50; effects are women/men geometric-mean ratios. CAR and diurnal log slope use signed values and women-minus-men differences. Report means ± SEM, observed n, effects, 95% CIs and two-sided P values. At least three observations per sex are required. Missing values are not imputed. LIFE current_mdd=0 records remain unverified and outside both diagnostic groups. Current GR measurements come from RESIST only.
Power planning uses two-sided alpha 0.05 and no multiplicity correction. The minimum integer sample above 85% and a 90% design target are calculated per endpoint and diagnosis, retaining pilot sex-specific SDs on the testing scale. Balanced recruitment is primary; the current diagnostic sex ratio is a separate scenario. Counts represent usable results per endpoint, not just enrolled people. The noncentral-t/Satterthwaite Welch approximation is conditional on the assumed true effect. Current pilot effects are uncertain: near-zero effects can yield impractically large counts. Half-pilot-effect sensitivity and standardised d=0.2, 0.3, 0.5 and 0.8 scenarios are supplied. No retrospective observed-power assessment is used to interpret current P values.
Sampling-point tests use positive cortisol values on natural-log scales, reporting women/men or depression/controls geometric-mean ratios and 95% CIs. The two separate diagnostic profiles show arithmetic mean ± SEM of these positive values, with exact unadjusted P values and available n at each occasion. Zero values are excluded, not imputed. Between-diagnosis contrasts are unadjusted for cohort: controls are RESIST-only and depression spans LIFE and RESIST. Pointwise tests do not test a repeated-measures trajectory. Waking tests duplicate the waking endpoint contrasts, not independent evidence.
Salivary cortisol is nmol/L; CAR is +30 minus waking. Slope uses log cortisol at actual waking/afternoon/late times. AUCg integrates all five actual sample times and spans differing LIFE and RESIST observation windows, not a standard 24-hour period. IC50 units and curve-fit quality need verification. DEX and PRED remain separate assays. These within-diagnosis pooled comparisons do not identify sex mechanisms independent of cohort composition, medication or reproductive status. R code has not been executed in the preparation environment.
Publication panels and tables place controls on the left and depression on the right, with men and women within each panel. Matching axes share the same scales. Social, demographic and clinical characteristics use mean ± SD (n) or n/N (%), with unadjusted Welch/Fisher comparisons. A separate colour-coded cohort report compares LIFE and RESIST within source-defined current depression and retains a coded membership roster, including excluded and placeholder records. Study- specific raw symptom scores and education measures are not equated.
Setup and data
Recalculate outcomes
C<-as.matrix(D[,paste0("c",1:5,"_nmol_l")]);T<-as.matrix(D[,paste0("t",1:5,"_hours")])
storage.mode(C)<-storage.mode(T)<-"double";C[!is.finite(C)|C<0]<-NA_real_
D[,paste0("c",1:5,"_nmol_l")]<-C
auc<-function(conc,hours)if(any(!is.finite(c(conc,hours)))||any(diff(hours)<=0))NA_real_ else sum((head(conc,-1)+tail(conc,-1))/2*diff(hours))
slope<-function(conc,hours)if(any(!is.finite(c(conc,hours)))||any(conc<=0)||any(diff(hours)<=0))NA_real_ else unname(coef(lm(log(conc)~hours))[2])
D$cort_waking<-C[,1];D$car<-C[,2]-C[,1]
D$slope<-vapply(seq_len(nrow(D)),function(i)slope(C[i,c(1,4,5)],T[i,c(1,4,5)]),numeric(1))
D$aucg_observed<-vapply(seq_len(nrow(D)),function(i)auc(C[i,],T[i,]),numeric(1))
D$observation_hours<-T[,5]-T[,1];D$observation_hours[D$observation_hours<=0]<-NA_real_
D$time_weighted_cortisol<-D$aucg_observed/D$observation_hours;D$wake_hour<-T[,1]
for(v in c("dex_ic50","pred_ic50"))D[[v]][D[[v]]<0 & !is.na(D[[v]])]<-NA_real_
endpoints<-data.frame(variable=c("cort_waking","car","slope","aucg_observed","dex_ic50","pred_ic50","time_weighted_cortisol"),
measure=c("Waking cortisol","Cortisol awakening response","Diurnal log slope","Observed-window AUCg","Dexamethasone IC50","Prednisolone IC50","Time-weighted cortisol"),
unit=c("nmol/L","nmol/L","ln(nmol/L)/h","nmol/L × h","source assay units","source assay units","nmol/L"),
scale=c("log","raw","raw","log","log","log","log"),domain=c(rep("primary",5),rep("supplementary",2)))
smry<-function(x){x<-x[is.finite(x)];list(n=length(x),mean=if(length(x))mean(x)else NA_real_,sem=if(length(x)>1)sd(x)/sqrt(length(x))else NA_real_)}
fmt<-function(x){a<-smry(x);if(a$n<2)paste("n =",a$n)else sprintf("%.3g ± %.3g (%d)",a$mean,a$sem,a$n)}Uncorrected comparisons
D$depression_group<-D$eligible_pooled & ((D$study=="LIFE" & !is.na(D$current_mdd_source) & D$current_mdd_source==1) | (D$study=="RESIST" & D$antidepressant_group_source %in% c(1,2)))
D$healthy_group<-D$healthy_pooled
H<-D[D$healthy_group,,drop=FALSE];M<-D[D$depression_group,,drop=FALSE]
sx<-function(d,s)d[d$sex==s,,drop=FALSE]
specs<-list(
list(title="Sex within controls",g1="Men",g2="Women",a=sx(H,"Men"),b=sx(H,"Women")),
list(title="Sex within depression",g1="Men",g2="Women",a=sx(M,"Men"),b=sx(M,"Women")))
values<-function(d,e){x<-d[[e$variable]];x<-x[is.finite(x)];if(e$scale=="log")x<-x[x>0];x}
compare<-function(spec,e){
a<-values(spec$a,e);b<-values(spec$b,e)
r<-data.frame(comparison=spec$title,group1=spec$g1,group2=spec$g2,variable=e$variable,measure=e$measure,unit=e$unit,scale=e$scale,
n1=length(a),n2=length(b),summary1=fmt(a),summary2=fmt(b),effect=NA_real_,lower=NA_real_,upper=NA_real_,p=NA_real_,status="Not estimable")
if(min(length(a),length(b))<3)return(r)
aa<-if(e$scale=="log")log(a)else a;bb<-if(e$scale=="log")log(b)else b
fit<-tryCatch(t.test(bb,aa,var.equal=FALSE),error=function(e)NULL);if(is.null(fit))return(r)
z<-c(mean(bb)-mean(aa),fit$conf.int[1],fit$conf.int[2]);if(e$scale=="log")z<-exp(z)
r$effect<-z[1];r$lower<-z[2];r$upper<-z[3];r$p<-fit$p.value;r$status<-"Estimated";r
}
tables<-setNames(lapply(specs,function(sp)do.call(rbind,lapply(seq_len(nrow(endpoints)),function(j)compare(sp,endpoints[j,])))),vapply(specs,`[[`,character(1),"title"))
for(title in names(tables))print(knitr::kable(tables[[title]],digits=4,caption=paste(title,"— unadjusted P values")))
Table: Sex within controls — unadjusted P values
|comparison |group1 |group2 |variable |measure |unit |scale | n1| n2|summary1 |summary2 | effect| lower| upper| p|status |
|:-------------------|:------|:------|:----------------------|:---------------------------|:------------------|:-----|--:|--:|:-----------------------|:------------------------|------:|-------:|------:|------:|:---------|
|Sex within controls |Men |Women |cort_waking |Waking cortisol |nmol/L |log | 10| 18|7.47 ± 1.3 (10) |6.66 ± 0.956 (18) | 0.7959| 0.3340| 1.8965| 0.5923|Estimated |
|Sex within controls |Men |Women |car |Cortisol awakening response |nmol/L |raw | 10| 18|2.49 ± 1.14 (10) |3.17 ± 1.12 (18) | 0.6787| -2.6212| 3.9785| 0.6746|Estimated |
|Sex within controls |Men |Women |slope |Diurnal log slope |ln(nmol/L)/h |raw | 9| 16|-0.146 ± 0.035 (9) |-0.14 ± 0.0287 (16) | 0.0066| -0.0884| 0.1016| 0.8854|Estimated |
|Sex within controls |Men |Women |aucg_observed |Observed-window AUCg |nmol/L × h |log | 9| 15|50.5 ± 6.41 (9) |59.9 ± 7.3 (15) | 1.1378| 0.7407| 1.7477| 0.5372|Estimated |
|Sex within controls |Men |Women |dex_ic50 |Dexamethasone IC50 |source assay units |log | 9| 14|2.26e-08 ± 8.11e-09 (9) |1.69e-08 ± 5.61e-09 (14) | 0.8502| 0.3728| 1.9388| 0.6782|Estimated |
|Sex within controls |Men |Women |pred_ic50 |Prednisolone IC50 |source assay units |log | 7| 6|1.26e-07 ± 3.89e-08 (7) |1.32e-07 ± 4.88e-08 (6) | 0.9985| 0.4277| 2.3309| 0.9969|Estimated |
|Sex within controls |Men |Women |time_weighted_cortisol |Time-weighted cortisol |nmol/L |log | 9| 15|3.31 ± 0.412 (9) |3.75 ± 0.473 (15) | 1.0786| 0.7073| 1.6449| 0.7121|Estimated |
Table: Sex within depression — unadjusted P values
|comparison |group1 |group2 |variable |measure |unit |scale | n1| n2|summary1 |summary2 | effect| lower| upper| p|status |
|:---------------------|:------|:------|:----------------------|:---------------------------|:------------------|:-----|--:|--:|:------------------------|:------------------------|-------:|-------:|------:|------:|:---------|
|Sex within depression |Men |Women |cort_waking |Waking cortisol |nmol/L |log | 15| 41|5.69 ± 0.94 (15) |6.87 ± 0.698 (41) | 1.2693| 0.7730| 2.0843| 0.3290|Estimated |
|Sex within depression |Men |Women |car |Cortisol awakening response |nmol/L |raw | 15| 41|1.35 ± 1.3 (15) |2.56 ± 0.795 (41) | 1.2130| -1.9278| 4.3539| 0.4340|Estimated |
|Sex within depression |Men |Women |slope |Diurnal log slope |ln(nmol/L)/h |raw | 14| 37|-0.139 ± 0.0194 (14) |-0.141 ± 0.0122 (37) | -0.0020| -0.0493| 0.0452| 0.9298|Estimated |
|Sex within depression |Men |Women |aucg_observed |Observed-window AUCg |nmol/L × h |log | 14| 37|54.8 ± 7.37 (14) |52.1 ± 5.77 (37) | 0.9227| 0.6240| 1.3646| 0.6749|Estimated |
|Sex within depression |Men |Women |dex_ic50 |Dexamethasone IC50 |source assay units |log | 10| 15|1.55e-07 ± 6.34e-08 (10) |5.53e-08 ± 3.45e-08 (15) | 0.2782| 0.0607| 1.2753| 0.0941|Estimated |
|Sex within depression |Men |Women |pred_ic50 |Prednisolone IC50 |source assay units |log | 5| 11|4.35e-07 ± 1.59e-07 (5) |4.57e-08 ± 9.04e-09 (11) | 0.1192| 0.0228| 0.6224| 0.0189|Estimated |
|Sex within depression |Men |Women |time_weighted_cortisol |Time-weighted cortisol |nmol/L |log | 14| 37|3.43 ± 0.421 (14) |3.96 ± 0.464 (37) | 1.0792| 0.7471| 1.5591| 0.6737|Estimated |
write.csv(do.call(rbind,tables),out("Unadjusted_Group_Comparisons.csv"),row.names=FALSE,na="")
four<-list("HC men"=sx(H,"Men"),"HC women"=sx(H,"Women"),"MDD men"=sx(M,"Men"),"MDD women"=sx(M,"Women"))Comparisons at each saliva sampling occasion
categories<-c("Waking","+30 min","+60 min","Afternoon","Late")
timepoint_endpoints<-data.frame(variable=paste0("c",1:5,"_nmol_l"),measure=categories,unit="nmol/L",scale="log")
timepoint_specs<-c(specs,list(
list(title="Diagnosis within men",g1="Controls",g2="Depression",a=sx(H,"Men"),b=sx(M,"Men")),
list(title="Diagnosis within women",g1="Controls",g2="Depression",a=sx(H,"Women"),b=sx(M,"Women"))))
timepoint_tables<-setNames(lapply(timepoint_specs,function(sp)do.call(rbind,lapply(1:5,function(j)compare(sp,timepoint_endpoints[j,])))),vapply(timepoint_specs,`[[`,character(1),"title"))
write.csv(do.call(rbind,timepoint_tables),out("Cortisol_Timepoint_Comparisons.csv"),row.names=FALSE,na="")
for(title in names(timepoint_tables))print(knitr::kable(timepoint_tables[[title]],digits=4,caption=paste(title,"— raw two-sided P values")))
Table: Sex within controls — raw two-sided P values
|comparison |group1 |group2 |variable |measure |unit |scale | n1| n2|summary1 |summary2 | effect| lower| upper| p|status |
|:-------------------|:------|:------|:---------|:---------|:------|:-----|--:|--:|:----------------|:------------------|------:|------:|------:|------:|:---------|
|Sex within controls |Men |Women |c1_nmol_l |Waking |nmol/L |log | 10| 18|7.47 ± 1.3 (10) |6.66 ± 0.956 (18) | 0.7959| 0.3340| 1.8965| 0.5923|Estimated |
|Sex within controls |Men |Women |c2_nmol_l |+30 min |nmol/L |log | 10| 18|9.96 ± 1.66 (10) |9.84 ± 1.34 (18) | 0.6957| 0.2720| 1.7799| 0.4326|Estimated |
|Sex within controls |Men |Women |c3_nmol_l |+60 min |nmol/L |log | 10| 17|6.03 ± 1.18 (10) |7.83 ± 0.97 (17) | 1.3050| 0.7325| 2.3249| 0.3477|Estimated |
|Sex within controls |Men |Women |c4_nmol_l |Afternoon |nmol/L |log | 9| 17|1.79 ± 0.401 (9) |1.81 ± 0.53 (17) | 0.8021| 0.3426| 1.8778| 0.5940|Estimated |
|Sex within controls |Men |Women |c5_nmol_l |Late |nmol/L |log | 9| 18|0.957 ± 0.29 (9) |0.993 ± 0.388 (18) | 0.7494| 0.3244| 1.7308| 0.4829|Estimated |
Table: Sex within depression — raw two-sided P values
|comparison |group1 |group2 |variable |measure |unit |scale | n1| n2|summary1 |summary2 | effect| lower| upper| p|status |
|:---------------------|:------|:------|:---------|:---------|:------|:-----|--:|--:|:-----------------|:-----------------|------:|------:|------:|------:|:---------|
|Sex within depression |Men |Women |c1_nmol_l |Waking |nmol/L |log | 15| 41|5.69 ± 0.94 (15) |6.87 ± 0.698 (41) | 1.2693| 0.7730| 2.0843| 0.3290|Estimated |
|Sex within depression |Men |Women |c2_nmol_l |+30 min |nmol/L |log | 15| 41|7.03 ± 0.948 (15) |9.43 ± 0.898 (41) | 1.2899| 0.8357| 1.9910| 0.2391|Estimated |
|Sex within depression |Men |Women |c3_nmol_l |+60 min |nmol/L |log | 15| 41|6.07 ± 1.07 (15) |7.82 ± 1.27 (41) | 1.2750| 0.7664| 2.1212| 0.3331|Estimated |
|Sex within depression |Men |Women |c4_nmol_l |Afternoon |nmol/L |log | 14| 40|2.4 ± 0.271 (14) |2.56 ± 0.294 (40) | 0.9195| 0.6410| 1.3190| 0.6391|Estimated |
|Sex within depression |Men |Women |c5_nmol_l |Late |nmol/L |log | 15| 38|1.06 ± 0.578 (15) |1.14 ± 0.183 (38) | 1.5800| 0.8569| 2.9133| 0.1358|Estimated |
Table: Diagnosis within men — raw two-sided P values
|comparison |group1 |group2 |variable |measure |unit |scale | n1| n2|summary1 |summary2 | effect| lower| upper| p|status |
|:--------------------|:--------|:----------|:---------|:---------|:------|:-----|--:|--:|:----------------|:-----------------|------:|------:|------:|------:|:---------|
|Diagnosis within men |Controls |Depression |c1_nmol_l |Waking |nmol/L |log | 10| 15|7.47 ± 1.3 (10) |5.69 ± 0.94 (15) | 0.7560| 0.3515| 1.6264| 0.4527|Estimated |
|Diagnosis within men |Controls |Depression |c2_nmol_l |+30 min |nmol/L |log | 10| 15|9.96 ± 1.66 (10) |7.03 ± 0.948 (15) | 0.6870| 0.3990| 1.1830| 0.1656|Estimated |
|Diagnosis within men |Controls |Depression |c3_nmol_l |+60 min |nmol/L |log | 10| 15|6.03 ± 1.18 (10) |6.07 ± 1.07 (15) | 0.9261| 0.4917| 1.7445| 0.8039|Estimated |
|Diagnosis within men |Controls |Depression |c4_nmol_l |Afternoon |nmol/L |log | 9| 14|1.79 ± 0.401 (9) |2.4 ± 0.271 (14) | 1.5882| 0.7626| 3.3075| 0.1929|Estimated |
|Diagnosis within men |Controls |Depression |c5_nmol_l |Late |nmol/L |log | 9| 15|0.957 ± 0.29 (9) |1.06 ± 0.578 (15) | 0.7058| 0.3209| 1.5526| 0.3672|Estimated |
Table: Diagnosis within women — raw two-sided P values
|comparison |group1 |group2 |variable |measure |unit |scale | n1| n2|summary1 |summary2 | effect| lower| upper| p|status |
|:----------------------|:--------|:----------|:---------|:---------|:------|:-----|--:|--:|:------------------|:-----------------|------:|------:|------:|------:|:---------|
|Diagnosis within women |Controls |Depression |c1_nmol_l |Waking |nmol/L |log | 18| 41|6.66 ± 0.956 (18) |6.87 ± 0.698 (41) | 1.2057| 0.6229| 2.3338| 0.5624|Estimated |
|Diagnosis within women |Controls |Depression |c2_nmol_l |+30 min |nmol/L |log | 18| 41|9.84 ± 1.34 (18) |9.43 ± 0.898 (41) | 1.2737| 0.5218| 3.1091| 0.5777|Estimated |
|Diagnosis within women |Controls |Depression |c3_nmol_l |+60 min |nmol/L |log | 17| 41|7.83 ± 0.97 (17) |7.82 ± 1.27 (41) | 0.9048| 0.5905| 1.3864| 0.6358|Estimated |
|Diagnosis within women |Controls |Depression |c4_nmol_l |Afternoon |nmol/L |log | 17| 40|1.81 ± 0.53 (17) |2.56 ± 0.294 (40) | 1.8206| 0.9924| 3.3400| 0.0527|Estimated |
|Diagnosis within women |Controls |Depression |c5_nmol_l |Late |nmol/L |log | 18| 38|0.993 ± 0.388 (18) |1.14 ± 0.183 (38) | 1.4882| 0.7548| 2.9342| 0.2393|Estimated |
Prospective sample size scenarios
welch_power<-function(nm,nw,delta,sm,sw,alpha=.05){
if(min(nm,nw)<2 || min(sm,sw)<=0)return(NA_real_)
v1<-sm^2/nm;v2<-sw^2/nw;df<-(v1+v2)^2/(v1^2/(nm-1)+v2^2/(nw-1))
nc<-abs(delta)/sqrt(v1+v2);critical<-qt(1-alpha/2,df)
pt(critical,df,ncp=nc,lower.tail=FALSE)+pt(-critical,df,ncp=nc)
}
required_n<-function(delta,sm,sw,target=.90,ratio=1){
if(any(!is.finite(c(delta,sm,sw,ratio))) || min(sm,sw,ratio)<=0 || abs(delta)<1e-15)
return(list(men=NA_real_,women=NA_real_,total=NA_real_,power=NA_real_,status="Undefined for zero effect or invalid SD"))
f<-function(n)welch_power(n,max(2,ceiling(n*ratio)),delta,sm,sw)
lo<-1;hi<-2
while(f(hi)<=target && hi<1e9){lo<-hi;hi<-min(1e9,hi*2)}
if(f(hi)<=target)return(list(men=NA_real_,women=NA_real_,total=NA_real_,power=NA_real_,status="Exceeds search cap"))
while(hi-lo>1){mid<-floor((lo+hi)/2);if(f(mid)>target)hi<-mid else lo<-mid}
nw<-max(2,ceiling(hi*ratio))
stopifnot(f(hi)>target,hi==2 || f(hi-1)<=target)
list(men=hi,women=nw,total=hi+nw,power=f(hi),status="Conditional pilot-based approximation")
}
power_rows<-list()
for(diagnostic in c("Controls","Depression")){
d<-if(diagnostic=="Controls")H else M
ratio<-sum(d$sex=="Women")/sum(d$sex=="Men")
for(j in seq_len(nrow(endpoints))){
e<-endpoints[j,];a<-values(sx(d,"Men"),e);b<-values(sx(d,"Women"),e)
if(min(length(a),length(b))<3)next
if(e$scale=="log"){a<-log(a);b<-log(b)}
delta<-mean(b)-mean(a);sm<-sd(a);sw<-sd(b)
pooled<-sqrt(((length(a)-1)*sm^2+(length(b)-1)*sw^2)/(length(a)+length(b)-2))
for(allocation in c("Balanced men and women","Current diagnostic sex ratio"))for(target in c(.85,.90)){
rr<-if(allocation=="Balanced men and women")1 else ratio
n<-required_n(delta,sm,sw,target,rr);half<-required_n(delta*.5,sm,sw,target,rr)
power_rows[[length(power_rows)+1L]]<-data.frame(diagnostic_group=diagnostic,variable=e$variable,measure=e$measure,analysis_scale=e$scale,
current_men=length(a),current_women=length(b),pilot_delta=delta,pilot_sd_men=sm,pilot_sd_women=sw,
pilot_standardised_difference=delta/pooled,allocation=allocation,women_per_man=rr,target_power=target,alpha=.05,
required_men=n$men,required_women=n$women,required_total=n$total,achieved_power=n$power,
additional_men=max(0,n$men-length(a)),additional_women=max(0,n$women-length(b)),status=n$status,
half_effect_required_men=half$men,half_effect_required_women=half$women,half_effect_required_total=half$total)
}
}
}
power_rows<-do.call(rbind,power_rows)
power_scenarios<-do.call(rbind,lapply(c(.2,.3,.5,.8),function(effect)
do.call(rbind,lapply(c(.85,.90),function(target){n<-required_n(effect,1,1,target)
data.frame(standardised_difference=effect,target_power=target,required_men=n$men,required_women=n$women,required_total=n$total,achieved_power=n$power,alpha=.05)}))))
write.csv(power_rows,out("Sample_Size_by_Parameter.csv"),row.names=FALSE,na="")
write.csv(power_scenarios,out("Standardised_Effect_Scenarios.csv"),row.names=FALSE,na="")
knitr::kable(power_rows[power_rows$allocation=="Balanced men and women" & power_rows$target_power==.9,],digits=4,caption="90% power conditional on current pilot effects; usable observations required")| diagnostic_group | variable | measure | analysis_scale | current_men | current_women | pilot_delta | pilot_sd_men | pilot_sd_women | pilot_standardised_difference | allocation | women_per_man | target_power | alpha | required_men | required_women | required_total | achieved_power | additional_men | additional_women | status | half_effect_required_men | half_effect_required_women | half_effect_required_total | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2 | Controls | cort_waking | Waking cortisol | log | 10 | 18 | -0.2283 | 0.9329 | 1.2710 | -0.1959 | Balanced men and women | 1 | 0.9 | 0.05 | 503 | 503 | 1006 | 0.9003 | 493 | 485 | Conditional pilot-based approximation | 2007 | 2007 | 4014 |
| 6 | Controls | car | Cortisol awakening response | raw | 10 | 18 | 0.6787 | 3.5994 | 4.7481 | 0.1548 | Balanced men and women | 1 | 0.9 | 0.05 | 811 | 811 | 1622 | 0.9000 | 801 | 793 | Conditional pilot-based approximation | 3241 | 3241 | 6482 |
| 10 | Controls | slope | Diurnal log slope | raw | 9 | 16 | 0.0066 | 0.1050 | 0.1146 | 0.0594 | Balanced men and women | 1 | 0.9 | 0.05 | 5812 | 5812 | 11624 | 0.9000 | 5803 | 5796 | Conditional pilot-based approximation | 23242 | 23242 | 46484 |
| 14 | Controls | aucg_observed | Observed-window AUCg | log | 9 | 15 | 0.1291 | 0.4509 | 0.5425 | 0.2525 | Balanced men and women | 1 | 0.9 | 0.05 | 315 | 315 | 630 | 0.9001 | 306 | 300 | Conditional pilot-based approximation | 1257 | 1257 | 2514 |
| 18 | Controls | dex_ic50 | Dexamethasone IC50 | log | 9 | 14 | -0.1623 | 0.9926 | 0.7194 | -0.1946 | Balanced men and women | 1 | 0.9 | 0.05 | 601 | 601 | 1202 | 0.9002 | 592 | 587 | Conditional pilot-based approximation | 2399 | 2399 | 4798 |
| 22 | Controls | pred_ic50 | Prednisolone IC50 | log | 7 | 6 | -0.0015 | 0.6292 | 0.7280 | -0.0022 | Balanced men and women | 1 | 0.9 | 0.05 | 4220608 | 4220608 | 8441216 | 0.9000 | 4220601 | 4220602 | Conditional pilot-based approximation | 16882428 | 16882428 | 33764856 |
| 26 | Controls | time_weighted_cortisol | Time-weighted cortisol | log | 9 | 15 | 0.0757 | 0.4376 | 0.5424 | 0.1494 | Balanced men and women | 1 | 0.9 | 0.05 | 892 | 892 | 1784 | 0.9001 | 883 | 877 | Conditional pilot-based approximation | 3564 | 3564 | 7128 |
| 30 | Depression | cort_waking | Waking cortisol | log | 15 | 41 | 0.2385 | 0.8275 | 0.6818 | 0.3301 | Balanced men and women | 1 | 0.9 | 0.05 | 214 | 214 | 428 | 0.9008 | 199 | 173 | Conditional pilot-based approximation | 851 | 851 | 1702 |
| 34 | Depression | car | Cortisol awakening response | raw | 15 | 41 | 1.2130 | 5.0417 | 5.0936 | 0.2388 | Balanced men and women | 1 | 0.9 | 0.05 | 368 | 368 | 736 | 0.9002 | 353 | 327 | Conditional pilot-based approximation | 1469 | 1469 | 2938 |
| 38 | Depression | slope | Diurnal log slope | raw | 14 | 37 | -0.0020 | 0.0725 | 0.0743 | -0.0276 | Balanced men and women | 1 | 0.9 | 0.05 | 27240 | 27240 | 54480 | 0.9000 | 27226 | 27203 | Conditional pilot-based approximation | 108954 | 108954 | 217908 |
| 42 | Depression | aucg_observed | Observed-window AUCg | log | 14 | 37 | -0.0804 | 0.6052 | 0.5977 | -0.1341 | Balanced men and women | 1 | 0.9 | 0.05 | 1177 | 1177 | 2354 | 0.9000 | 1163 | 1140 | Conditional pilot-based approximation | 4705 | 4705 | 9410 |
| 46 | Depression | dex_ic50 | Dexamethasone IC50 | log | 10 | 15 | -1.2796 | 1.8910 | 1.5607 | -0.7537 | Balanced men and women | 1 | 0.9 | 0.05 | 40 | 40 | 80 | 0.9029 | 30 | 25 | Conditional pilot-based approximation | 156 | 156 | 312 |
| 50 | Depression | pred_ic50 | Prednisolone IC50 | log | 5 | 11 | -2.1267 | 1.3439 | 1.1689 | -1.7410 | Balanced men and women | 1 | 0.9 | 0.05 | 9 | 9 | 18 | 0.9186 | 4 | 0 | Conditional pilot-based approximation | 31 | 31 | 62 |
| 54 | Depression | time_weighted_cortisol | Time-weighted cortisol | log | 14 | 37 | 0.0763 | 0.5493 | 0.6243 | 0.1260 | Balanced men and women | 1 | 0.9 | 0.05 | 1251 | 1251 | 2502 | 0.9002 | 1237 | 1214 | Conditional pilot-based approximation | 4998 | 4998 | 9996 |
knitr::kable(power_scenarios,digits=4,caption="Standardised-effect planning scenarios, equal SDs and balanced allocation")| standardised_difference | target_power | required_men | required_women | required_total | achieved_power | alpha |
|---|---|---|---|---|---|---|
| 0.2 | 0.85 | 450 | 450 | 900 | 0.8501 | 0.05 |
| 0.2 | 0.90 | 527 | 527 | 1054 | 0.9004 | 0.05 |
| 0.3 | 0.85 | 201 | 201 | 402 | 0.8509 | 0.05 |
| 0.3 | 0.90 | 235 | 235 | 470 | 0.9007 | 0.05 |
| 0.5 | 0.85 | 73 | 73 | 146 | 0.8510 | 0.05 |
| 0.5 | 0.90 | 86 | 86 | 172 | 0.9032 | 0.05 |
| 0.8 | 0.85 | 30 | 30 | 60 | 0.8614 | 0.05 |
| 0.8 | 0.90 | 34 | 34 | 68 | 0.9015 | 0.05 |
Figures and exports
categories<-c("Waking","+30 min","+60 min","Afternoon","Late")
charts<-list();figures<-character()
save_plot<-function(p,name,w,h){
if(inherits(p,"ggplot"))print(p)else{grid::grid.newpage();grid::grid.draw(p)}
for(ext in c("png","pdf","tiff")){
args<-list(filename=out(paste0(name,".",ext)),plot=p,width=w,height=h,dpi=if(ext=="tiff")600 else 220)
if(ext=="tiff")args$compression<-"lzw"
do.call(ggplot2::ggsave,args)
}
}
profile_specs<-list(Controls=H,Depression=M)
profile_charts<-lapply(names(profile_specs),function(diagnostic){
d<-profile_specs[[diagnostic]]
series<-lapply(c("Men","Women"),function(s){
ss<-lapply(1:5,function(j)smry(values(sx(d,s),timepoint_endpoints[j,])))
list(name=s,mean=vapply(ss,`[[`,numeric(1),"mean"),sem=vapply(ss,`[[`,numeric(1),"sem"),n=vapply(ss,`[[`,integer(1),"n"))
})
list(name=paste0(diagnostic,"_Profile"),title=paste0(diagnostic,": men and women"),categories=categories,series=series,ylabel="Salivary cortisol (nmol/L)",kind="profile",diagnosis=diagnostic)
})
profile_ymax<-max(unlist(lapply(profile_charts,function(ch)unlist(lapply(ch$series,function(z)z$mean+z$sem)))))*1.16
zero_excluded<-sum(vapply(profile_specs,function(d)sum(as.matrix(d[,paste0("c",1:5,"_nmol_l")])==0,na.rm=TRUE),numeric(1)))
format_p<-function(p)ifelse(is.na(p),"NE",ifelse(p<.001,"<0.001",sprintf("%.3f",p)))
profile_grobs<-list()
for(ch in profile_charts){
ch$ymax<-profile_ymax;charts[[length(charts)+1L]]<-ch
pd<-do.call(rbind,lapply(ch$series,function(z)data.frame(sample=1:5,group=z$name,mean=z$mean,sem=z$sem)))
p<-ggplot2::ggplot(pd,ggplot2::aes(sample,mean,colour=group,shape=group,linetype=group,group=group))+
ggplot2::geom_line(linewidth=.8)+ggplot2::geom_point(size=2.5)+ggplot2::geom_errorbar(ggplot2::aes(ymin=mean-sem,ymax=mean+sem),width=.1)+
ggplot2::scale_colour_manual(values=c(Men="#1764A0",Women="#C44E16"))+ggplot2::scale_x_continuous(breaks=1:5,labels=categories)+
ggplot2::coord_cartesian(ylim=c(0,profile_ymax))+ggplot2::labs(title=ch$title,x=NULL,y=ch$ylabel)+
ggplot2::theme_classic(base_size=12)+ggplot2::theme(legend.position="top",legend.title=ggplot2::element_blank())
pp<-timepoint_tables[[paste("Sex within",tolower(ch$diagnosis))]]
tm<-rbind(ch$series[[1]]$n,ch$series[[2]]$n,format_p(pp$p),format_p(timepoint_tables[["Diagnosis within men"]]$p),format_p(timepoint_tables[["Diagnosis within women"]]$p))
rownames(tm)<-c("Men: n","Women: n","Women vs men: P","MDD vs HC, men: P","MDD vs HC, women: P")
# Base grid/gtable are used for a readable table under each profile; no extra plot package is needed.
tg<-gtable::gtable(widths=grid::unit(c(2,rep(1,5)),"null"),heights=grid::unit(rep(1,6),"null"))
cells<-rbind(c("",categories),cbind(rownames(tm),tm))
for(i in 1:6)for(j in 1:6)tg<-gtable::gtable_add_grob(tg,grid::textGrob(cells[i,j],gp=grid::gpar(fontsize=9)),t=i,l=j)
combined<-gtable::gtable(widths=grid::unit(1,"null"),heights=grid::unit(c(6,2.3,1.1),"null"))
combined<-gtable::gtable_add_grob(combined,ggplot2::ggplotGrob(p),t=1,l=1)
combined<-gtable::gtable_add_grob(combined,tg,t=2,l=1)
caption<-paste0("Mean ± SEM; positive values. Unadjusted two-sided Welch tests on log cortisol. HC = controls; MDD = depression.\n",
"Between-diagnosis P values repeat on both graphs. LIFE/RESIST: afternoon 14:00/16:00; late 20:00/bedtime.\n",
"Zero concentrations excluded across both groups: ",zero_excluded,". Comparisons are pointwise, not a trajectory test.")
combined<-gtable::gtable_add_grob(combined,grid::textGrob(caption,gp=grid::gpar(fontsize=9)),t=3,l=1)
profile_grobs[[ch$diagnosis]]<-combined
name<-paste0("Figure_Cortisol_Profile_",ch$diagnosis);save_plot(combined,name,10.6,7.4);figures<-c(figures,name)
}paired<-gtable::gtable(widths=grid::unit(c(1,1),"null"),heights=grid::unit(1,"null"))
paired<-gtable::gtable_add_grob(paired,profile_grobs[["Controls"]],t=1,l=1)
paired<-gtable::gtable_add_grob(paired,profile_grobs[["Depression"]],t=1,l=2)
name<-"Figure_Cortisol_Profile_Side_by_Side";save_plot(paired,name,18,7.4);figures<-c(name,figures)for(domain in c("Cortisol","GR")){
selected<-if(domain=="Cortisol")1:4 else 5:6
points<-means<-annotations<-list()
for(j in selected){
e<-endpoints[j,];ss<-lapply(four,function(d)smry(values(d,e)))
lo<-min(vapply(ss,function(z)z$mean-z$sem,numeric(1)));hi<-max(vapply(ss,function(z)z$mean+z$sem,numeric(1)));pad<-max((hi-lo)*.15,abs(hi)*1e-6,1e-20)
for(k in 1:2){
diagnostic<-c("Controls","Depression")[k];selected_ss<-ss[((k-1)*2+1):(k*2)]
charts[[length(charts)+1L]]<-list(name=paste0(diagnostic,"_",e$variable),title=e$measure,diagnosis=diagnostic,categories=c("Men","Women"),series=list(list(name="Arithmetic mean",mean=vapply(selected_ss,`[[`,numeric(1),"mean"),sem=vapply(selected_ss,`[[`,numeric(1),"sem"),n=vapply(selected_ss,`[[`,integer(1),"n"))),ylabel=e$unit,kind="endpoint",ymin=if(min(vapply(ss,`[[`,numeric(1),"mean"))>0)max(0,lo-pad)else lo-pad,ymax=hi+pad)
}
panel<-paste(e$measure,e$unit,if(e$scale=="log")"log10 display"else"",sep="\n")
transform_y<-function(y)if(e$scale=="log")ifelse(y>0,log10(pmax(y,.Machine$double.xmin)),NA_real_)else y
for(k in 1:4){
label<-names(four)[k];x<-values(four[[k]],e);z<-smry(x);diagnostic<-if(k<=2)"Controls"else"Depression";sex<-c("Men","Women")[(k-1)%%2+1]
points[[length(points)+1L]]<-data.frame(sex=sex,diagnosis=diagnostic,value=transform_y(x),measure=panel)
means[[length(means)+1L]]<-data.frame(sex=sex,diagnosis=diagnostic,value=transform_y(z$mean),lower=transform_y(z$mean-z$sem),upper=transform_y(z$mean+z$sem),measure=panel)
}
for(diagnostic in c("Controls","Depression")){
rr<-tables[[paste("Sex within",tolower(diagnostic))]];rr<-rr[rr$variable==e$variable,]
annotations[[length(annotations)+1L]]<-data.frame(diagnosis=diagnostic,measure=panel,label=paste0("P=",format_p(rr$p),"; n=",rr$n1,"/",rr$n2))
}
}
pd<-do.call(rbind,points);md<-do.call(rbind,means);ad<-do.call(rbind,annotations)
for(z in c("pd","md","ad")){
q<-get(z);q$diagnosis<-factor(q$diagnosis,levels=c("Controls","Depression"));q$measure<-factor(q$measure,levels=unique(md$measure));assign(z,q)
}
pd$sex<-factor(pd$sex,levels=c("Men","Women"));md$sex<-factor(md$sex,levels=c("Men","Women"))
p<-ggplot2::ggplot(pd,ggplot2::aes(sex,value,colour=sex,shape=sex))+ggplot2::geom_jitter(width=.08,height=0,alpha=.6,size=1.5)+ggplot2::geom_errorbar(data=md,ggplot2::aes(ymin=lower,ymax=upper),colour="black",width=.1)+ggplot2::geom_point(data=md,shape=18,colour="black")+
ggplot2::geom_text(data=ad,ggplot2::aes(x=1.5,y=Inf,label=label),inherit.aes=FALSE,vjust=1.2,size=3)+
ggplot2::facet_grid(measure~diagnosis,scales="free_y")+ggplot2::scale_colour_manual(values=c(Men="#1764A0",Women="#C44E16"))+ggplot2::labs(x=NULL,y="Endpoint value",caption="Black diamonds: arithmetic mean ± SEM. Same scale in each parameter row; raw unadjusted within-diagnosis P values.")+ggplot2::theme_classic()+ggplot2::theme(legend.position="none")
name<-paste0("Figure_",domain,"_Side_by_Side");save_plot(p,name,10.6,if(domain=="Cortisol")11.2 else 5.6);figures<-c(figures,name)
}estimates<-do.call(rbind,tables);estimates<-estimates[estimates$variable %in% endpoints$variable[1:6],]
estimates$panel<-paste(estimates$measure,ifelse(estimates$scale=="log","log10 ratio","difference"),sep="\n")
for(v in c("effect","lower","upper")){ix<-estimates$scale=="log";estimates[ix,v]<-log10(estimates[ix,v])}
p<-ggplot2::ggplot(estimates,ggplot2::aes(effect,comparison))+ggplot2::geom_vline(xintercept=0,linetype="dashed",colour="grey")+ggplot2::geom_errorbar(ggplot2::aes(xmin=lower,xmax=upper),orientation="y",width=.1)+ggplot2::geom_point()+ggplot2::facet_wrap(~panel,scales="free_x",ncol=3)+ggplot2::labs(x="Group 2 − group 1 difference or log10 ratio",y=NULL)+ggplot2::theme_classic()
name<-"Figure_Within_Diagnosis_Effects";save_plot(p,name,13,8);figures<-c(figures,name)Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
for 'Group 2 − group 1 difference or log10 ratio' in 'mbcsToSbcs': -
substituted for − (U+2212)
future_n<-unique(ceiling(10^seq(log10(2),7,length.out=160)))
curve_rows<-list()
for(j in 1:6)for(diagnostic in c("Controls","Depression")){
e<-endpoints[j,];r<-power_rows[power_rows$diagnostic_group==diagnostic & power_rows$variable==e$variable & power_rows$allocation=="Balanced men and women" & power_rows$target_power==.9,]
curve_rows[[length(curve_rows)+1L]]<-data.frame(per_sex=future_n,power=vapply(future_n,function(n)welch_power(n,n,r$pilot_delta,r$pilot_sd_men,r$pilot_sd_women),numeric(1)),diagnosis=diagnostic,measure=e$measure)
}
curve_data<-do.call(rbind,curve_rows);curve_data<-curve_data[is.finite(curve_data$power),]
p<-ggplot2::ggplot(curve_data,ggplot2::aes(per_sex,power,colour=diagnosis))+ggplot2::geom_line()+ggplot2::geom_hline(yintercept=c(.85,.9),linetype="dashed",colour="grey")+ggplot2::scale_x_log10()+ggplot2::facet_wrap(~measure,ncol=3)+ggplot2::labs(x="Future usable participants per sex",y="Conditional prospective power")+ggplot2::theme_classic()+ggplot2::theme(legend.position="top")
name<-"Figure_Prospective_Power_Curves";save_plot(p,name,12,7);figures<-c(figures,name)counts<-lapply(list(Controls=H,Depression=M),function(d)list(n=nrow(d),men=sum(d$sex=="Men"),women=sum(d$sex=="Women")))
write.csv(D,out("Group_Analysis_Data.csv"),row.names=FALSE,na="")
jsonlite::write_json(list(analysis_scope="within_diagnosis_timepoints_power_v4",tables=tables,timepoint_tables=timepoint_tables,characteristics=characteristics,publication_tables=publication_tables,power_rows=power_rows,power_scenarios=power_scenarios,charts=charts,figures=figures,counts=counts,version="v1.5.0",multiplicity_correction="none"),out("within_diagnosis_results.json"),dataframe="rows",auto_unbox=TRUE,pretty=TRUE,na="null")
capture.output(sessionInfo(),file=out("sessionInfo.txt"))Numbered main publication and supplementary results
if(!file.exists("LIFE_RESIST_Publication_Helpers.R"))stop("Extract LIFE_RESIST_Publication_Helpers.R beside this QMD.")
source("LIFE_RESIST_Publication_Helpers.R",local=TRUE)
publication<-pub15_build(D,endpoints,tables,timepoint_tables,charts,counts,power_rows,power_scenarios,characteristics,publication_tables)
jsonlite::write_json(publication,out("publication_results.json"),dataframe="rows",auto_unbox=TRUE,pretty=TRUE,na="null")
for(key in c("characteristics_overall","diagnosis_overall","endpoint_interactions","timepoint_interactions"))
write.csv(rows_data(publication[[key]]),out(paste0("Publication_",key,".csv")),row.names=FALSE,na="")
write.csv(rows_data(unlist(publication$diagnosis_by_sex,recursive=FALSE)),out("Publication_diagnosis_by_sex.csv"),row.names=FALSE,na="")
knitr::kable(rows_data(publication$endpoint_interactions),digits=4,caption="Sex by diagnosis interaction contrasts, unadjusted P values")| variable | measure | unit | scale | scope | hc_men_n | hc_women_n | mdd_men_n | mdd_women_n | effect | lower | upper | p | contrast | se | df | t | status |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| cort_waking | Waking cortisol | nmol/L | log | Pooled | 10 | 18 | 15 | 41 | 1.5948 | 0.5989 | 4.2470 | 0.3406 | 0.4667 | 0.4835 | 37.2393 | 0.9653 | Estimated |
| cort_waking | Waking cortisol | nmol/L | log | RESIST | 10 | 18 | 13 | 18 | 1.1746 | 0.4302 | 3.2074 | 0.7478 | 0.1609 | 0.4970 | 40.0651 | 0.3238 | Estimated |
| car | Cortisol awakening response | nmol/L | raw | Pooled | 10 | 18 | 15 | 41 | 0.5344 | -3.9049 | 4.9736 | 0.8098 | 0.5344 | 2.2080 | 48.1265 | 0.2420 | Estimated |
| car | Cortisol awakening response | nmol/L | raw | RESIST | 10 | 18 | 13 | 18 | 0.7535 | -3.7948 | 5.3017 | 0.7407 | 0.7535 | 2.2641 | 49.7443 | 0.3328 | Estimated |
| slope | Diurnal log slope | ln(nmol/L)/h | raw | Pooled | 9 | 16 | 14 | 37 | -0.0086 | -0.1126 | 0.0953 | 0.8658 | -0.0086 | 0.0507 | 27.0952 | -0.1706 | Estimated |
| slope | Diurnal log slope | ln(nmol/L)/h | raw | RESIST | 9 | 16 | 12 | 17 | -0.0254 | -0.1317 | 0.0809 | 0.6287 | -0.0254 | 0.0520 | 29.4048 | -0.4887 | Estimated |
| aucg_observed | Observed-window AUCg | nmol/L × h | log | Pooled | 9 | 15 | 14 | 37 | 0.8110 | 0.4615 | 1.4254 | 0.4576 | -0.2095 | 0.2793 | 41.5508 | -0.7499 | Estimated |
| aucg_observed | Observed-window AUCg | nmol/L × h | log | RESIST | 9 | 15 | 12 | 16 | 0.6276 | 0.3308 | 1.1905 | 0.1494 | -0.4659 | 0.3172 | 41.8379 | -1.4687 | Estimated |
| dex_ic50 | Dexamethasone IC50 | source assay units | log | Pooled | 9 | 14 | 10 | 15 | 0.3272 | 0.0609 | 1.7572 | 0.1832 | -1.1173 | 0.8163 | 25.0977 | -1.3686 | Estimated |
| dex_ic50 | Dexamethasone IC50 | source assay units | log | RESIST | 9 | 14 | 10 | 15 | 0.3272 | 0.0609 | 1.7572 | 0.1832 | -1.1173 | 0.8163 | 25.0977 | -1.3686 | Estimated |
| pred_ic50 | Prednisolone IC50 | source assay units | log | Pooled | 7 | 6 | 5 | 11 | 0.1194 | 0.0208 | 0.6860 | 0.0216 | -2.1252 | 0.7939 | 10.9582 | -2.6768 | Estimated |
| pred_ic50 | Prednisolone IC50 | source assay units | log | RESIST | 7 | 6 | 5 | 11 | 0.1194 | 0.0208 | 0.6860 | 0.0216 | -2.1252 | 0.7939 | 10.9582 | -2.6768 | Estimated |
| time_weighted_cortisol | Time-weighted cortisol | nmol/L | log | Pooled | 9 | 15 | 14 | 37 | 1.0006 | 0.5803 | 1.7250 | 0.9984 | 0.0006 | 0.2702 | 43.3354 | 0.0021 | Estimated |
| time_weighted_cortisol | Time-weighted cortisol | nmol/L | log | RESIST | 9 | 15 | 12 | 16 | 0.7084 | 0.3855 | 1.3018 | 0.2596 | -0.3447 | 0.3018 | 43.6436 | -1.1421 | Estimated |
Render LIFE_RESIST_Publication_Only.qmd to create both numbered Word documents. The main Word file contains controls-versus-depression characteristics and cortisol results. The supplementary file contains sex-stratified comparisons, interaction CIs, RESIST-only interaction sensitivity and the existing power tables.
Social demographic and clinical characteristics and cohort comparability