This RMarkdown document aims to compile the R scripts used in the registered project: “Genetic and environmental aetiology of suicidal and non-suicidal self-harm”
Load the libraries, switch default optimiser to SLSQP, and print version of R and OpenMx used:
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be done before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse);require(knitr);require(kableExtra)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
session_info=sessionInfo()
session_info$R.version$version.string
## [1] "R version 3.6.2 (2019-12-12)"
paste(session_info$otherPkgs$OpenMx$Package,
session_info$otherPkgs$OpenMx$Version)
## [1] "OpenMx 2.17.3"
Load the data, apply exclusion criteria, and clean the data
self_harm_data=read.spss("/Users/kai/OneDrive - King's College London/PhD/TEDS_project/data/427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,x3zygos,sexzyg,u1cage1,u1cage2,sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
#code for binary variables NSSHr1/2, SSHr1/2 for Table 2
#NSSHr1/2
self_harm_data_c <- mutate(self_harm_data_c, NSSHr1 = ifelse(NSSH1==0|NSSH1==1|is.na(NSSH1),NSSH1,1))
self_harm_data_c <- mutate(self_harm_data_c, NSSHr2 = ifelse(NSSH2==0|NSSH2==1|is.na(NSSH2),NSSH2,1))
#SSHr1/2
self_harm_data_c <- mutate(self_harm_data_c, SSHr1 = ifelse(SSH1==0|SSH1==1|is.na(SSH1),SSH1,1))
self_harm_data_c <- mutate(self_harm_data_c, SSHr2 = ifelse(SSH2==0|SSH2==1|is.na(SSH2),SSH2,1))
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
self_harm_data_c$NSSHr1<-mxFactor(self_harm_data_c$NSSHr1, levels=c(0:1) )
self_harm_data_c$NSSHr2<-mxFactor(self_harm_data_c$NSSHr2, levels=c(0:1) )
self_harm_data_c$SSHr1<-mxFactor(self_harm_data_c$SSHr1, levels=c(0:1) )
self_harm_data_c$SSHr2<-mxFactor(self_harm_data_c$SSHr2, levels=c(0:1) )
#variables to be used
useVars <-c('NSSH1', 'SSH1', 'NSSH2', 'SSH2' , 'u1cage1', 'u1cage2', 'sex1','sex2')
# Select Data for Analysis
selfharmdata_subset<-subset(self_harm_data_c, !is.na(x3zygos)&!is.na(u1cage1|u1cage2) &!is.na(sex1&sex2), useVars)
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(u1cage1|u1cage2) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(u1cage1|u1cage2) &!is.na(sex1&sex2), useVars)
mzData <- mutate(mzData, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
mzData <- mutate(mzData, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
dzData <- mutate(dzData, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
dzData <- mutate(dzData, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
Look at prevalence of NSSH and SSH in the full sample, males and females, and mean age. These information form the basis for constructing Table 2
# to reduce missing data, if one cotwin's age data is missing but their cotwin's age data is available, we used their cotwin's available age data as a proxy to their age.
self_harm_data_descriptive<-self_harm_data_c %>%
filter((!is.na(NSSH1)|!is.na(NSSH2)|!is.na(NSSH1)|!is.na(NSSH2)) &
!is.na(u1cage1|u1cage2) & !is.na(sex1&sex2) & !is.na(sexzyg))%>%
mutate(age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))%>%
mutate(age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))%>%
filter(!is.na(age1&age2) &!is.na(sex1&sex2))
# write function to create the table for the full sample, male and female samples:
table_1_fun<-function(X1,X2,X3){
total_NSSH=sum(table(X1)) #total for NSSH
table_NSSH=table(X1)
prop_NSSH=round(prop.table(table(X1))*100,1)
total_SSH=sum(table(X2)) #total for NSSH
table_SSH=table(X2)
prop_SSH=round(prop.table(table(X2))*100,1)
meanage=round(mean(X3,na.rm=T),1)
return(rbind(cbind(total_NSSH,table_NSSH,prop_NSSH),cbind(total_SSH,table_SSH,prop_SSH),meanage))
}
fullsample=table_1_fun(self_harm_data_descriptive$NSSH1,self_harm_data_descriptive$SSH1,self_harm_data_descriptive$u1cage1)
malesample=table_1_fun(self_harm_data_descriptive[self_harm_data_descriptive$sex1==1,]$NSSH1,self_harm_data_descriptive[self_harm_data_descriptive$sex1==1,]$SSH1,self_harm_data_descriptive[self_harm_data_descriptive$sex1==1,]$u1cage1)
femalesample=table_1_fun(self_harm_data_descriptive[self_harm_data_descriptive$sex1==0,]$NSSH1,self_harm_data_descriptive[self_harm_data_descriptive$sex1==0,]$SSH1,self_harm_data_descriptive[self_harm_data_descriptive$sex1==0,]$u1cage1)
final_table<-as.data.frame(cbind(fullsample,malesample,femalesample),row.names=c(rep("NSSH",5),rep("SSH",5),"mean age (years)"))
colnames(final_table)<-c("Total N","N in each group","%",
"Male sample total N","N in each group","%",
"Female sample total N","N in each group","%")
rownames(final_table)<-c("NSSH: No",
"NSSH: Yes, 1-2 times",
"NSSH: Yes, 3-5 times",
"NSSH: Yes, 6-10 times",
"NSSH: Yes, >10 times",
"SSH: No",
"SSH: Yes, 1-2 times",
"SSH: Yes, 3-5 times",
"SSH: Yes, 6-10 times",
"SSH: Yes, >10 times",
"Mean age (Years)")
kableExtra::kable(final_table,digits=c(rep(c(0,0,1),3)),align="c")%>%
kable_styling(font_size = 12)%>%
collapse_rows()
| Total N | N in each group | % | Male sample total N | N in each group | % | Female sample total N | N in each group | % | |
|---|---|---|---|---|---|---|---|---|---|
| NSSH: No | 9063 | 7080 | 78.1 | 3407 | 2887 | 84.7 | 5656 | 4193 | 74.1 |
| NSSH: Yes, 1-2 times | 951 | 10.5 | 295 | 8.7 | 656 | 11.6 | |||
| NSSH: Yes, 3-5 times | 293 | 3.2 | 72 | 2.1 | 221 | 3.9 | |||
| NSSH: Yes, 6-10 times | 195 | 2.2 | 39 | 1.1 | 156 | 2.8 | |||
| NSSH: Yes, >10 times | 544 | 6.0 | 114 | 3.3 | 430 | 7.6 | |||
| SSH: No | 9061 | 8106 | 89.5 | 3143 | 92.3 | 5654 | 4963 | 87.8 | |
| SSH: Yes, 1-2 times | 640 | 7.1 | 180 | 5.3 | 460 | 8.1 | |||
| SSH: Yes, 3-5 times | 144 | 1.6 | 47 | 1.4 | 97 | 1.7 | |||
| SSH: Yes, 6-10 times | 60 | 0.7 | 11 | 0.3 | 49 | 0.9 | |||
| SSH: Yes, >10 times | 111 | 1.2 | 26 | 0.8 | 85 | 1.5 | |||
| Mean age (Years) | 22 | 22 | 22.3 | 22 | 22 | 22.3 | 22 | 22 | 22.2 |
Export the table to an Excel file to be further editted for Table 2 in manuscript. Note that it was named as Table 1 as sheetName, but it is actually represented as Table 2 in our final manuscript:
#xlsx::write.xlsx(final_table, "descriptive_stats.xlsx", sheetName = "Table_1_proportions")
As suggested by reviewers, we further added details about the overlapping of NSSH and SSH in Table 2 using the codes below:
| Full.sample.N | (%) | Male.sample.N | (%) | Female.sample.N | (%) | |
|---|---|---|---|---|---|---|
| Either_or_both | 2057 | 22.7 | 542 | 15.9 | 1515 | 26.8 |
| Both | 881 | 9.7 | 242 | 7.1 | 639 | 11.3 |
| NSSH only | 1102 | 12.2 | 278 | 8.2 | 824 | 14.6 |
| SSH only | 74 | 0.8 | 22 | 0.6 | 52 | 0.9 |
We then run chi-square tests for sex differences in NSSH:
# chi-square test for sex differences
table_chi_sq_NSSH=table(self_harm_data_descriptive$sex1,self_harm_data_descriptive$NSSH1)
chisq.test(table_chi_sq_NSSH) #for NSSH
##
## Pearson's Chi-squared test
##
## data: table_chi_sq_NSSH
## X-squared = 159.18, df = 4, p-value < 2.2e-16
Chi-square test for sex differences in SSH:
table_chi_sq_SSH=table(self_harm_data_descriptive$sex1,self_harm_data_descriptive$SSH1)
chisq.test(table_chi_sq_SSH) # For SSH
##
## Pearson's Chi-squared test
##
## data: table_chi_sq_SSH
## X-squared = 49.76, df = 4, p-value = 4.053e-10
The code below calculates the proportion of MZM, DZM, MZF, DZF, DZOS twins and incomplete twin pairs. It forms part of Table S5 in the Supplementary Material
knitr::opts_knit$set(root.dir = "/Users/kai/OneDrive - King's College London/PhD/TEDS_project/results" )
mzmData <- subset(self_harm_data_descriptive, sexzyg==1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #MZM
dzmData <- subset(self_harm_data_descriptive, sexzyg==2 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #DZM
mzfData <- subset(self_harm_data_descriptive, sexzyg==3 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #MZF
dzfData <- subset(self_harm_data_descriptive, sexzyg==4 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #DZF
dzoData <- subset(self_harm_data_descriptive, sexzyg==5 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #DZO
#for NSSH
mzmcom=table(!is.na(mzmData$NSSH1)&!is.na(mzmData$NSSH2))[2]
dzmcom=table(!is.na(dzmData$NSSH1)&!is.na(dzmData$NSSH2))[2]
mzfcom=table(!is.na(mzfData$NSSH1)&!is.na(mzfData$NSSH2))[2]
dzfcom=table(!is.na(dzfData$NSSH1)&!is.na(dzfData$NSSH2))[2]
dzocom=table(!is.na(dzoData$NSSH1)&!is.na(dzoData$NSSH2))[2]
incom=sum(table(xor(!is.na(mzmData$NSSH1),!is.na(mzmData$NSSH2)))[2],
table(xor(!is.na(dzmData$NSSH1),!is.na(dzmData$NSSH2)))[2],
table(xor(!is.na(mzfData$NSSH1),!is.na(mzfData$NSSH2)))[2],
table(xor(!is.na(dzfData$NSSH1),!is.na(dzfData$NSSH2)))[2],
table(xor(!is.na(dzoData$NSSH1),!is.na(dzoData$NSSH2)))[2])
sumNSSH=sum(sum(mzmcom,dzmcom,mzfcom,dzfcom,dzocom)*2,incom)
NSSH=rbind(mzmcom,dzmcom,mzfcom,dzfcom,dzocom,incom,sumNSSH)
#for SSH
mzmcom=table(!is.na(mzmData$SSH1)&!is.na(mzmData$SSH2))[2]
dzmcom=table(!is.na(dzmData$SSH1)&!is.na(dzmData$SSH2))[2]
mzfcom=table(!is.na(mzfData$SSH1)&!is.na(mzfData$SSH2))[2]
dzfcom=table(!is.na(dzfData$SSH1)&!is.na(dzfData$SSH2))[2]
dzocom=table(!is.na(dzoData$SSH1)&!is.na(dzoData$SSH2))[2]
incom=sum(table(xor(!is.na(mzmData$SSH1),!is.na(mzmData$SSH2)))[2],
table(xor(!is.na(dzmData$SSH1),!is.na(dzmData$SSH2)))[2],
table(xor(!is.na(mzfData$SSH1),!is.na(mzfData$SSH2)))[2],
table(xor(!is.na(dzfData$SSH1),!is.na(dzfData$SSH2)))[2],
table(xor(!is.na(dzoData$SSH1),!is.na(dzoData$SSH2)))[2])
sumSSH=sum(sum(mzmcom,dzmcom,mzfcom,dzfcom,dzocom)*2,incom)
SSH=rbind(mzmcom,dzmcom,mzfcom,dzfcom,dzocom,incom,sumSSH)
table_twin_prop<-as.data.frame(cbind(NSSH,SSH), row.names = c("MZM (pairs)", "DZM (pairs)","MZF (pairs)","DZF (pairs)","DZOS (pairs)","Single twins", "Total number"))
colnames(table_twin_prop)<-c("NSSH","SSH")
knitr::kable(table_twin_prop, align="rcc")%>%
kable_styling(font_size = 12)
| NSSH | SSH | |
|---|---|---|
| MZM (pairs) | 490 | 490 |
| DZM (pairs) | 395 | 394 |
| MZF (pairs) | 984 | 986 |
| DZF (pairs) | 791 | 792 |
| DZOS (pairs) | 1093 | 1094 |
| Single twins | 1557 | 1549 |
| Total number | 9063 | 9061 |
Save the results to the same excel file in sheet 2.
write.xlsx(table_twin_prop,"descriptive_stats.xlsx", sheetName = "Table_2_twins",append = T)
We used the code below to produce descriptive statistics for mental health measures collected at age 16
#redefine self_harm_data_c as this script initially saved as a different file.
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
#recoded cCANN, cSMOK and cALC as they are ordinal variables
#cCANN
self_harm_data_c <- mutate(self_harm_data_c, cCANN = ifelse(is.na(pcbhdrug151)&pcbhdrug121==0,pcbhdrug121,pcbhdrug151))
#cSMOK
self_harm_data_c <- mutate(self_harm_data_c, cSMOK = ifelse(is.na(pcbhdrug091)&pcbhdrug061==0,pcbhdrug061,pcbhdrug091))
#cALC
self_harm_data_c$pcbhdrug051<-self_harm_data_c$pcbhdrug051-1
self_harm_data_c$pcbhdrug052<-self_harm_data_c$pcbhdrug052-1
self_harm_data_c <- mutate(self_harm_data_c, cALC = ifelse(is.na(pcbhdrug051)&pcbhdrug011==0,pcbhdrug011,pcbhdrug051))
#rename some columns to ease the next steps:
self_harm_data_c <-self_harm_data_c%>%
rename(
pSDQ=ppbhsdqbeht1,
cSDQ=pcbhsdqbeht1,
pCONN=ppbhconnt1,
pEMOL=ppbhconnemlt1,
pHYPER=ppbhconnimpt1,
pINAT=ppbhconninat1,
pMFQ=ppbhmfqt1,
cMFQ=pcbhmfqt1,
pAUT=ppbhaqt1,
cAUT=pcbhaqt1,
cCAPS=pcbhcapst1,
cGRAND=pcbhgrndt1,
cPRND=pcbhprndt1,
pSANS=ppbhsanst1,
cANHE=pcbhanhdt1,
pANX=ppbhanxt1,
cANX=pcbhcasit1,
cTEPS=pcbhtepst1,
cEAT=pcbheddsm1,
cINSOM=pcbhinsomt1,
cSWAN=pcbhswanm1)
DesData <- subset(self_harm_data_c, !is.na(age1&age2) &!is.na(sex1&sex2)& (!is.na(NSSH1)|!is.na(SSH1)))
#
#select only one twin from each pair because of double entry method
measures<-c("pHYPER",'pCONN',"pEMOL",'pINAT','pSDQ',"cAUT","cSDQ","pAUT","cSWAN",
"cANX","pANX","pMFQ","cEAT","cINSOM","cMFQ",
"pSANS","cCAPS","cANHE","cPRND","cGRAND","cTEPS",
"cSMOK","cCANN","cALC")
des_table<-data.frame()
for (i in 1:length(measures))
{des<-describe(DesData[,measures[i]])
des_table[i,1]<-measures[i]
des_table[i,c(2:4)]<-c(des$n,des$mean,des$sd)
}
colnames(des_table)<-c("Measure","Sample size","Mean","SD")
des_table<-des_table%>%
add_column(Category=ifelse(des_table$Measure=="pSDQ"|
des_table$Measure=="cSDQ"|
des_table$Measure=="pAUT"|
des_table$Measure=="cAUT","Others",
ifelse(des_table$Measure=="pCONN"|
des_table$Measure=="pEMOL"|
des_table$Measure=="pINAT"|
des_table$Measure=="pHYPER"|
des_table$Measure=="cSWAN","Externalising problems",
ifelse(des_table$Measure=="pMFQ"|
des_table$Measure=="cMFQ"|
des_table$Measure=="pANX"|
des_table$Measure=="cANX"|
des_table$Measure=="cEAT"|
des_table$Measure=="cINSOM","Internalising problems",
ifelse(des_table$Measure=="cCAPS"|
des_table$Measure=="cGRAND"|
des_table$Measure=="cTEPS"|
des_table$Measure=="cANHE"|
des_table$Measure=="cPRND"|
des_table$Measure=="pSANS","Psychotic-like experiences",
ifelse(des_table$Measure=="cSMOK"|
des_table$Measure=="cALC"|
des_table$Measure=="cCANN","Substance abuse","No"))))))%>%
select(Category, Measure, `Sample size`, Mean, SD)%>%
arrange(Measure)%>%
arrange(Category)
des_table$Mean<-round(des_table$Mean,2)
CANN<-paste(round((1-prop.table(table(DesData$cCANN))[1])*100,2),"%")
SMOK<-paste(round((1-prop.table(table(DesData$cSMOK))[1])*100,2), "%")
ALC<-paste(round((1-prop.table(table(DesData$cALC))[1])*100,2), "%")
des_table$Mean[22:24]<-c(CANN,SMOK,ALC)
des_table$SD[22:24]<-NA
knitr::kable(des_table,digits=2)%>%
kable_styling(font_size = 12)%>%
collapse_rows()
| Category | Measure | Sample size | Mean | SD |
|---|---|---|---|---|
| Externalising problems | cSWAN | 1474 | 4.81 | 0.82 |
| pCONN | 6658 | 5.93 | 6.65 | |
| pEMOL | 6661 | 1.17 | 1.72 | |
| pHYPER | 6656 | 2.31 | 3.15 | |
| pINAT | 6657 | 3.62 | 4.40 | |
| Internalising problems | cANX | 6666 | 8.2 | 5.91 |
| cEAT | 1465 | 3.24 | 1.92 | |
| cINSOM | 5175 | 3.8 | 4.12 | |
| cMFQ | 6665 | 3.74 | 4.51 | |
| pANX | 6666 | 3.59 | 4.17 | |
| pMFQ | 6663 | 0.93 | 2.21 | |
| Others | cAUT | 6659 | 12.12 | 5.78 |
| cSDQ | 6661 | 9.35 | 5.10 | |
| pAUT | 6665 | 23.75 | 10.76 | |
| pSDQ | 6669 | 3.46 | 2.99 | |
| Psychotic-like experiences | cANHE | 6657 | 1.25 | 1.30 |
| cCAPS | 6666 | 4.74 | 6.08 | |
| cGRAND | 6662 | 5.14 | 4.33 | |
| cPRND | 6663 | 12.26 | 10.65 | |
| cTEPS | 6667 | 33.89 | 7.77 | |
| pSANS | 6660 | 2.68 | 3.79 | |
| Substance abuse | cALC | 4451 | 8.34 % | NA |
| cCANN | 5026 | 20.03 % | NA | |
| cSMOK | 5007 | 35.34 % | NA |
We then exported the table into an Excel file for further editting.
xlsx::write.xlsx(des_table,"MH_measures.xlsx")
Although in the manuscript we mainly presented the bivariate model, we also fitted two univariate models, one for NSSH and one for SSH.
The codes presented below were used to derive results in Note S1 and Table S3.
Full script:
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
str(self_harm_data);class(self_harm_data)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>%
filter(!is.na(u1cslfh021)|!is.na(u1cslfh022))%>% #no missing data for self-harm
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032, x3zygos,sexzyg,u1cage1,u1cage2,sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric)
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
nv <- 1 # number of variables per twin
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
selVars <- c('NSSH1' , 'NSSH2')
useVars<- c('NSSH1' , 'NSSH2',"sex1","sex2",'u1cage1', 'u1cage2')
# Select Data for Analysis
#x3zygos 1 = MZ, not 1 = DZ twins
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(u1cage1|u1cage2) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(u1cage1|u1cage2) &!is.na(sex1&sex2), useVars)
# series of comparisons were carried out to see the missing values. There is no missing value for excluding unknown sex
# - already excluded in exclude line in the first place.
# for age, the benefit of using co-twin's age as proxy is there - to retain sample size.
# mzData2 <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(u1cage1|u1cage2), useVars) #select only one twin from each pair because of double entry method
# dzData2 <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(u1cage1|u1cage2), useVars)
#
# mzData3 <- subset(self_harm_data_c, x3zygos==1 & random==1 &!is.na(u1cage1&u1cage2), useVars) #select only one twin from each pair because of double entry method
# dzData3 <- subset(self_harm_data_c, x3zygos!=1 & random==1 &!is.na(u1cage1&u1cage2), useVars)
#
# mzData4 <- subset(self_harm_data_c, x3zygos==1 & random==1 &!is.na(u1cage1&u1cage2)&!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
# dzData4 <- subset(self_harm_data_c, x3zygos!=1 & random==1 &!is.na(u1cage1&u1cage2)&!is.na(sex1&sex2), useVars)
#fill in missing ages using proxy, creating new age variable "age"
mzData <- mutate(mzData, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
mzData <- mutate(mzData, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
dzData <- mutate(dzData, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
dzData <- mutate(dzData, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
# 1) Specify Saturated Model (Tetrachoric correlations)
# Matrix & Algebra for expected means (SND), Thresholds and correlation
obs1 <-mxMatrix(type="Full", nrow=1, ncol=2, free=F,labels=c("data.age1","data.age2"), name="age" )
obs2 <-mxMatrix(type="Full", nrow=1, ncol=2, free=F,labels=c("data.sex1","data.sex2"), name="sex" )
MeanL <-mxMatrix( type="Zero", nrow=1, ncol=ntv, name="M" )
betaA <-mxMatrix( type="Full", nrow=nth, ncol=1, free=TRUE, values=.05,
labels=c("BaTH"), name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=1, free=TRUE, values=.05,
labels=c("BsTH"), name="BsexTH" )
Inc <-mxMatrix( type="Lower", nrow=nth, ncol=nth, free=FALSE, values=1, name="L" )
Tmz <-mxMatrix(type="Full", nrow=nth, ncol=ntv, free=TRUE, values=c(0.5,0.05,0.05,0.05,0.5,0.05,0.05,0.05), lbound=c(-4,.001,.001,.001,-4,.001,.001,.001), ubound=c(4,1,1,1,4,1,1,1),
labels=c("Tmz11","imz11","imz21","imz31", "Tmz12","imz12","imz22","imz32"), name="ThMZ" )
ThreMZ <-mxAlgebra( expression= L %*% ThMZ+ BageTH%x%age + BsexTH%x%sex, name="expThreMZ" )
Tdz <-mxMatrix(type="Full", nrow=nth, ncol=ntv, free=TRUE, values=c(0.5,0.05,0.05,0.05,0.5,0.05,0.05,0.05), lbound=c(-4,.001,.001,.001,-4,.001,.001,.001), ubound=c(4,1,1,1,4,1,1,1),
labels=c("Tdz11","idz11","idz21","idz31", "Tdz12","idz12","idz22","idz32"), name="ThDZ" )
ThreDZ <-mxAlgebra( expression= L %*% ThDZ+ BageTH%x%age + BsexTH%x%sex, name="expThreDZ" )
CorMZ <-mxMatrix(type="Stand", nrow=ntv, ncol=ntv, free=T, values=.6, lbound=-.999, ubound=.999, name="expCorMZ")
CorDZ <-mxMatrix(type="Stand", nrow=ntv, ncol=ntv, free=T, values=.3, lbound=-.999, ubound=.999, name="expCorDZ")
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="expCorMZ", means="M", dimnames=selVars, thresholds="expThreMZ" )
objDZ <- mxExpectationNormal( covariance="expCorDZ", means="M", dimnames=selVars, thresholds="expThreDZ" )
fitFunction <- mxFitFunctionML()
# Combine Groups
modelMZ <- mxModel( MeanL, obs1, obs2, betaA, betaS ,Inc, Tmz, ThreMZ, CorMZ, dataMZ, objMZ, fitFunction, name="MZ" )
modelDZ <- mxModel( MeanL, obs1, obs2, betaA, betaS ,Inc, Tdz, ThreDZ, CorDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
Conf <- mxCI (c ('MZ.expCorMZ[2,1]', 'DZ.expCorDZ[2,1]','MZ.BageTH[1,1]','MZ.BsexTH[1,1]') )
SatModel <- mxModel( "Sat", modelMZ, modelDZ, minus2ll, obj, Conf )
# 1) RUN Saturated Model (Tetrachoric correlations)
SatFit <- mxRun( SatModel,intervals=T)
(SatSum <- summary(SatFit))
SatFit$output
# Generate SatModel Output
round(SatFit@output$estimate,4)
SatFit$MZ$expCorMZ
SatFit$DZ$expCorDZ
mxEval(MZ.expThreMZ, SatFit)
mxEval(MZ.expCorMZ, SatFit)
mxEval(DZ.expThreDZ, SatFit)
mxEval(DZ.expCorDZ, SatFit)
# 2) Specify and Run Sub1Model: equating Thresholds across Twin 1 and Twin 2 within MZ group
# Note: omxSetParameters: function to modify the attributes of parameters in a model
# without having to re-specify the model
Sub1Model <- mxModel(SatModel, name="sub1")
Sub1Model <- omxSetParameters(Sub1Model, labels=c("Tmz11","imz11","imz21","imz31", "Tmz12","imz12","imz22","imz32"),
newlabels=c("Tmz11","imz11","imz21","imz31", "Tmz11","imz11","imz21","imz31"), free=T, values=c(0.5,0.05,0.05,0.05,0.5,0.05,0.05,0.05),
lbound=c(-4,.001,.001,.001,-4,.001,.001,.001), ubound=c(4,1,1,1,4,1,1,1))
Sub1Fit <- mxRun( Sub1Model,intervals=TRUE)
(Sub1Sum <- summary(Sub1Fit))
mxCompare(SatFit, Sub1Fit)
# Generate Sub1Model Output
round(Sub1Fit@output$estimate,4)
Sub1Fit$MZ$expCorMZ
Sub1Fit$DZ$expCorDZ
mxEval(MZ.expThreMZ, Sub1Fit)
mxEval(MZ.expCorMZ, Sub1Fit)
mxEval(DZ.expThreDZ, Sub1Fit)
mxEval(DZ.expCorDZ, Sub1Fit)
# 3) Specify and Run Sub2Model: equating Thresholds across Twin 1 and Twin 2 within DZ group
Sub2Model <- mxModel(SatModel, name="sub2")
Sub2Model <- omxSetParameters(Sub2Model, labels=c("Tdz11","idz11","idz21","idz31", "Tdz12","idz12","idz22","idz32"),
newlabels=c("Tdz11","idz11","idz21","idz31", "Tdz11","idz11","idz21","idz31"), free=T, values=c(0.5,0.05,0.05,0.05,0.5,0.05,0.05,0.05),
lbound=c(-4,.001,.001,.001,-4,.001,.001,.001), ubound=c(4,1,1,1,4,1,1,1))
Sub2Fit <- mxRun( Sub2Model, intervals=TRUE)
(Sub2Sum <- summary(Sub2Fit))
mxCompare(SatFit, Sub2Fit)
# Generate Sub2Model Output
round(Sub2Fit@output$estimate,4)
Sub2Fit$MZ$expCorMZ
Sub2Fit$DZ$expCorDZ
mxEval(MZ.expThreMZ, Sub2Fit)
mxEval(MZ.expCorMZ, Sub2Fit)
mxEval(DZ.expThreDZ, Sub2Fit)
mxEval(DZ.expCorDZ, Sub2Fit)
# 4) Specify and Run Sub3Model: equating Thresholds across Twin 1 and Twin 2 and zygosity groups
Sub3Model <- mxModel(Sub1Model, name="sub3")
Sub3Model <- omxSetParameters(Sub3Model, labels=c("Tdz11","idz11","idz21","idz31", "Tdz12","idz12","idz22","idz32"),
newlabels=c("Tmz11","imz11","imz21","imz31", "Tmz11","imz11","imz21","imz31"), free=T, values=c(0.5,0.05,0.05,0.05,0.5,0.05,0.05,0.05),
lbound=c(-4,.001,.001,.001,-4,.001,.001,.001), ubound=c(4,1,1,1,4,1,1,1))
Sub3Fit <- mxRun(Sub3Model, intervals=TRUE)
(Sub3Sum <- summary(Sub3Fit))
# Generate Sub3Model Output
round(Sub3Fit@output$estimate,4)
Sub3Fit$MZ$expCorMZ
Sub3Fit$DZ$expCorDZ
mxEval(MZ.expThreMZ, Sub3Fit)
mxEval(MZ.expCorMZ, Sub3Fit)
mxEval(DZ.expThreDZ, Sub3Fit)
mxEval(DZ.expCorDZ, Sub3Fit)
# *********************************************************************
# Print Comparative Fit Statistics for Saturated and all sub Models
(SatNested.fit <- rbind(
mxCompare(SatFit, Sub1Fit),
mxCompare(SatFit, Sub2Fit)[2,],
mxCompare(SatFit, Sub3Fit)[2,] ) )
## Sub3Fit is a good enough fit! p>0.05
# 5) Specify ACE Model, with ONE overall set of Thresholds
# Note: There is a constraint on the total variances to be unity
#define definition variables
obs1 <-mxMatrix(type="Full", nrow=1, ncol=2, free=F,labels=c("data.age1","data.age2"), name="age" )
obs2 <-mxMatrix(type="Full", nrow=1, ncol=2, free=F,labels=c("data.sex1","data.sex2"), name="sex" )
# Matrices declared to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Full", nrow=1, ncol=1, free=TRUE, values=.6, label="a11", name="a" )
pathC <- mxMatrix( type="Full", nrow=1, ncol=1, free=TRUE, values=.6, label="c11", name="c" )
pathE <- mxMatrix( type="Full", nrow=1, ncol=1, free=TRUE, values=.6, label="e11", name="e" )
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
covP <- mxAlgebra( expression=A+C+E, name="V" )
# Matrix & Algebra for expected means vector and expected thresholds
meanL <- mxMatrix( type="Zero", nrow=1, ncol=ntv, name="M" )
Inc <- mxMatrix( type="Lower", nrow=nth, ncol=nth, free=FALSE, values=1, name="L" )
betaA <-mxMatrix( type="Full", nrow=nth, ncol=1, free=TRUE, values=.05,
labels=c("BaTH"), name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=1, free=TRUE, values=.05,
labels=c("BsTH"), name="BsexTH" )
Threshold <-mxMatrix(type="Full", nrow=nth, ncol=ntv, free=TRUE, values=c(0.5,0.05,0.05,0.05,0.5,0.05,0.05,0.05),
lbound=c(-4,.001,.001,.001,-4,.001,.001,.001), ubound=c(4,1,1,1,4,1,1,1),
labels=c("T11","i11","i21","i31", "T11","i11","i21","i31"), name="Th" )
Thre <-mxAlgebra( expression= L %*% Th + BageTH%x%age + BsexTH%x%sex, name="expThre" )
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="expCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="expCovDZ" )
# Constraint on total variance of Ordinal variables (A+C+E=1)
matUnv <- mxMatrix( type="Unit", nrow=nv, ncol=1, name="Unv" )
varL <- mxConstraint( expression=diag2vec(V)==Unv, name="VarL" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="expCovMZ", means="M", dimnames=selVars, thresholds="expThre" )
objDZ <- mxExpectationNormal( covariance="expCovDZ", means="M", dimnames=selVars, thresholds="expThre" )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, matUnv )
modelMZ <- mxModel( pars, meanL, obs1, obs2, betaA, betaS ,Inc, Threshold, Thre, covMZ, dataMZ, objMZ, fitFunction, name="MZ" )
modelDZ <- mxModel( pars, meanL, obs1, obs2, betaA, betaS ,Inc, Threshold, Thre, covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll<- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
Conf <- mxCI (c ('A[1,1]', 'C[1,1]', 'E[1,1]','MZ.BageTH[1,1]','MZ.BsexTH[1,1]') )
AceModel <- mxModel( "ACE", pars, varL, modelMZ, modelDZ, minus2ll, obj, Conf)
# 5) RUN AceModel
AceFit <- mxRun(AceModel, intervals=TRUE)
(AceSum <- summary(AceFit,verbose=TRUE))
mxEval(MZ.expThre, AceFit)
round(AceFit@output$estimate,4)
round(c(AceFit$A$result,AceFit$C$result,AceFit$E$result),2)
comparison=mxCompare(SatFit, AceFit)
AceFit@intervals
AceSum$CIdetail
(AceSum$CI)
setwd("../results")
save.image(file="liab_threshold_NSSH_cov_25_Dec_2019.RData")
Based on the script above, results for constrained correlation model for NSSH:
Sub3summ<-summary(Sub3Fit) # NSSH univariate concor model
Sub3summ$CI
## lbound estimate ubound note
## MZ.expCorMZ[2,1] 0.475580026 0.54322254 0.60452431
## DZ.expCorDZ[2,1] 0.198675200 0.27187145 0.34239605
## MZ.BageTH[1,1] 0.002076626 0.03538576 0.06872407
## MZ.BsexTH[1,1] 0.334029326 0.39628913 0.45881734
Results for ACE model for NSSH:
Acesumm<-summary(AceFit,verbose=TRUE) # NSSH univariate ACE model
Acesumm$CI
## lbound estimate ubound note
## ACE.A[1,1] 0.349685156 0.5427077084 0.60024198
## ACE.C[1,1] NA 0.0005168836 0.15529702 !!!
## ACE.E[1,1] 0.399758588 0.4567755055 0.52442368
## MZ.BageTH[1,1] 0.002079556 0.0353858090 0.06872304
## MZ.BsexTH[1,1] 0.334032621 0.3962887941 0.45881746
Acesumm$CIdetail[,1:3] #details for CI with !!
## parameter side value
## 1 ACE.A[1,1] lower 0.3496851562
## 2 ACE.A[1,1] upper 0.6002419833
## 3 ACE.C[1,1] lower 0.0003233958
## 4 ACE.C[1,1] upper 0.1552970189
## 5 ACE.E[1,1] lower 0.3997585884
## 6 ACE.E[1,1] upper 0.5244236752
## 7 MZ.BageTH[1,1] lower 0.0020795561
## 8 MZ.BageTH[1,1] upper 0.0687230447
## 9 MZ.BsexTH[1,1] lower 0.3340326206
## 10 MZ.BsexTH[1,1] upper 0.4588174643
Full script:
rm(list=ls())
require(OpenMx);require(psych);require(foreign);require(tidyverse)
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
str(self_harm_data);class(self_harm_data)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>%
filter(!is.na(u1cslfh021)|!is.na(u1cslfh022))%>% #no missing data for self-harm
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh041,u1cslfh042, x3zygos,sexzyg,u1cage1,u1cage2,sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric)
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
table(self_harm_data_c$u1cslfh021,useNA="always")
table(self_harm_data_c$u1cslfh022,useNA="always")
table(self_harm_data_c$u1cslfh041,useNA="always")
table(self_harm_data_c$u1cslfh042,useNA="always")
table(self_harm_data_c$SSH1,useNA="always")
table(self_harm_data_c$SSH2,useNA="always")
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
names (self_harm_data_c)
summary(self_harm_data_c)
describe(self_harm_data_c)
str(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
str(self_harm_data_c)
dim(self_harm_data_c)
nv <- 1 # number of variables per twin
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
selVars <- c('SSH1' , 'SSH2')
useVars<- c('SSH1' , 'SSH2',"sex1","sex2",'u1cage1', 'u1cage2')
table(self_harm_data_c$sex1,useNA='always')
# Select Data for Analysis
#x3zygos 1 = MZ, not 1 = DZ twins
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(u1cage1|u1cage2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(u1cage1|u1cage2), useVars)
table(mzData$SSH1)
dim(mzData)
dim(dzData)
head(mzData);head(dzData)
describe(mzData)
describe(dzData)
# get CT for Ordinal variable
table(mzData$SSH1, mzData$SSH2)
table(dzData$SSH1, dzData$SSH2)
#fill in missing ages using proxy, creating new age variable "age"
mzData <- mutate(mzData, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
mzData <- mutate(mzData, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
dzData <- mutate(dzData, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
dzData <- mutate(dzData, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
# 1) Specify Saturated Model (Tetrachoric correlations)
# Matrix & Algebra for the covariates, expected means (SND), Thresholds and correlation etc
#covariates as definition variables
obs1 <-mxMatrix(type="Full", nrow=1, ncol=2, free=F,labels=c("data.age1","data.age2"), name="age" )
obs2 <-mxMatrix(type="Full", nrow=1, ncol=2, free=F,labels=c("data.sex1","data.sex2"), name="sex" )
#mean
MeanL <-mxMatrix( type="Zero", nrow=1, ncol=ntv, name="M" )
#the covariates - age and sex
betaA <-mxMatrix( type="Full", nrow=nth, ncol=1, free=TRUE, values=.05,
labels=c("BaTH"), name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=1, free=TRUE, values=.05,
labels=c("BsTH"), name="BsexTH" )
# lower matrix
Inc <-mxMatrix( type="Lower", nrow=nth, ncol=nth, free=FALSE, values=1, name="L" )
#thresholds
Tmz <-mxMatrix(type="Full", nrow=nth, ncol=ntv, free=TRUE, values=c(0.5,0.05,0.05,0.05,0.5,0.05,0.05,0.05), lbound=c(-4,.001,.001,.001,-4,.001,.001,.001), ubound=c(4,1,1,1,4,1,1,1),
labels=c("Tmz11","imz11","imz21","imz31", "Tmz12","imz12","imz22","imz32"), name="ThMZ" )
ThreMZ <-mxAlgebra( expression= L %*% ThMZ+ BageTH%x%age + BsexTH%x%sex, name="expThreMZ" )
Tdz <-mxMatrix(type="Full", nrow=nth, ncol=ntv, free=TRUE, values=c(0.5,0.05,0.05,0.05,0.5,0.05,0.05,0.05), lbound=c(-4,.001,.001,.001,-4,.001,.001,.001), ubound=c(4,1,1,1,4,1,1,1),
labels=c("Tdz11","idz11","idz21","idz31", "Tdz12","idz12","idz22","idz32"), name="ThDZ" )
ThreDZ <-mxAlgebra( expression= L %*% ThDZ+ BageTH%x%age + BsexTH%x%sex, name="expThreDZ" )
#correlations
CorMZ <-mxMatrix(type="Stand", nrow=ntv, ncol=ntv, free=T, values=.6, lbound=-.999, ubound=.999, name="expCorMZ")
CorDZ <-mxMatrix(type="Stand", nrow=ntv, ncol=ntv, free=T, values=.3, lbound=-.999, ubound=.999, name="expCorDZ")
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="expCorMZ", means="M", dimnames=selVars, thresholds="expThreMZ" )
objDZ <- mxExpectationNormal( covariance="expCorDZ", means="M", dimnames=selVars, thresholds="expThreDZ" )
fitFunction <- mxFitFunctionML()
# Combine Groups
modelMZ <- mxModel( MeanL, obs1, obs2, betaA, betaS ,Inc, Tmz, ThreMZ, CorMZ, dataMZ, objMZ, fitFunction, name="MZ" )
modelDZ <- mxModel( MeanL, obs1, obs2, betaA, betaS ,Inc, Tdz, ThreDZ, CorDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
Conf <- mxCI (c ('MZ.expCorMZ[2,1]', 'DZ.expCorDZ[2,1]','MZ.BageTH[1,1]','MZ.BsexTH[1,1]') )
SatModel <- mxModel( "Sat", modelMZ, modelDZ, minus2ll, obj, Conf )
# 1) RUN Saturated Model (Tetrachoric correlations)
SatFit <- mxRun( SatModel,intervals=F)
(SatSum <- summary(SatFit))
SatFit$output
# Generate SatModel Output
round(SatFit@output$estimate,4)
SatFit$MZ$expCorMZ
SatFit$DZ$expCorDZ
mxEval(MZ.expThreMZ, SatFit)
mxEval(MZ.expCorMZ, SatFit)
mxEval(DZ.expThreDZ, SatFit)
mxEval(DZ.expCorDZ, SatFit)
# 2) Specify and Run Sub1Model: equating Thresholds across Twin 1 and Twin 2 within MZ group
# Note: omxSetParameters: function to modify the attributes of parameters in a model
# without having to re-specify the model
Sub1Model <- mxModel(SatModel, name="sub1")
Sub1Model <- omxSetParameters(Sub1Model, labels=c("Tmz11","imz11","imz21","imz31", "Tmz12","imz12","imz22","imz32"),
newlabels=c("Tmz11","imz11","imz21","imz31", "Tmz11","imz11","imz21","imz31"), free=T, values=c(0.5,0.05,0.05,0.05,0.5,0.05,0.05,0.05),
lbound=c(-4,.001,.001,.001,-4,.001,.001,.001), ubound=c(4,1,1,1,4,1,1,1))
Sub1Fit <- mxRun( Sub1Model,intervals=TRUE)
(Sub1Sum <- summary(Sub1Fit))
mxCompare(SatFit, Sub1Fit)
# Generate Sub1Model Output
round(Sub1Fit@output$estimate,4)
Sub1Fit$MZ$expCorMZ
Sub1Fit$DZ$expCorDZ
mxEval(MZ.expThreMZ, Sub1Fit)
mxEval(MZ.expCorMZ, Sub1Fit)
mxEval(DZ.expThreDZ, Sub1Fit)
mxEval(DZ.expCorDZ, Sub1Fit)
# 3) Specify and Run Sub2Model: equating Thresholds across Twin 1 and Twin 2 within DZ group
Sub2Model <- mxModel(SatModel, name="sub2")
Sub2Model <- omxSetParameters(Sub2Model, labels=c("Tdz11","idz11","idz21","idz31", "Tdz12","idz12","idz22","idz32"),
newlabels=c("Tdz11","idz11","idz21","idz31", "Tdz11","idz11","idz21","idz31"), free=T, values=c(0.5,0.05,0.05,0.05,0.5,0.05,0.05,0.05),
lbound=c(-4,.001,.001,.001,-4,.001,.001,.001), ubound=c(4,1,1,1,4,1,1,1))
Sub2Fit <- mxRun( Sub2Model, intervals=TRUE)
(Sub2Sum <- summary(Sub2Fit))
mxCompare(SatFit, Sub2Fit)
# Generate Sub2Model Output
round(Sub2Fit@output$estimate,4)
Sub2Fit$MZ$expCorMZ
Sub2Fit$DZ$expCorDZ
mxEval(MZ.expThreMZ, Sub2Fit)
mxEval(MZ.expCorMZ, Sub2Fit)
mxEval(DZ.expThreDZ, Sub2Fit)
mxEval(DZ.expCorDZ, Sub2Fit)
# 4) Specify and Run Sub3Model: equating Thresholds across Twin 1 and Twin 2 and zygosity groups
Sub3Model <- mxModel(Sub1Model, name="sub3")
Sub3Model <- omxSetParameters(Sub3Model, labels=c("Tdz11","idz11","idz21","idz31", "Tdz12","idz12","idz22","idz32"),
newlabels=c("Tmz11","imz11","imz21","imz31", "Tmz11","imz11","imz21","imz31"), free=T, values=c(0.5,0.05,0.05,0.05,0.5,0.05,0.05,0.05),
lbound=c(-4,.001,.001,.001,-4,.001,.001,.001), ubound=c(4,1,1,1,4,1,1,1))
Sub3Fit <- mxRun(Sub3Model, intervals=TRUE)
(Sub3Sum <- summary(Sub3Fit, verbose=T))
# Generate Sub3Model Output
round(Sub3Fit@output$estimate,4)
Sub3Fit$MZ$expCorMZ
Sub3Fit$DZ$expCorDZ
mxEval(MZ.expThreMZ, Sub3Fit)
mxEval(MZ.expCorMZ, Sub3Fit)
mxEval(DZ.expThreDZ, Sub3Fit)
mxEval(DZ.expCorDZ, Sub3Fit)
# *********************************************************************
# Print Comparative Fit Statistics for Saturated and all sub Models
(SatNested.fit <- rbind(
mxCompare(SatFit, Sub1Fit),
mxCompare(SatFit, Sub2Fit)[2,],
mxCompare(SatFit, Sub3Fit)[2,] ) )
## Sub3Fit is a good enough fit! p>0.05
# 5) Specify ACE Model, with ONE overall set of Thresholds
# Note: There is a constraint on the total variances to be unity
#define definition variables
obs1 <-mxMatrix(type="Full", nrow=1, ncol=2, free=F,labels=c("data.age1","data.age2"), name="age" )
obs2 <-mxMatrix(type="Full", nrow=1, ncol=2, free=F,labels=c("data.sex1","data.sex2"), name="sex" )
# Matrices declared to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Full", nrow=1, ncol=1, free=TRUE, values=.6, label="a11", name="a" )
pathC <- mxMatrix( type="Full", nrow=1, ncol=1, free=TRUE, values=.6, label="c11", name="c" )
pathE <- mxMatrix( type="Full", nrow=1, ncol=1, free=TRUE, values=.6, label="e11", name="e" )
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
covP <- mxAlgebra( expression=A+C+E, name="V" )
# Matrix & Algebra for expected means vector and expected thresholds
meanL <- mxMatrix( type="Zero", nrow=1, ncol=ntv, name="M" )
Inc <- mxMatrix( type="Lower", nrow=nth, ncol=nth, free=FALSE, values=1, name="L" )
#covariates
betaA <-mxMatrix( type="Full", nrow=nth, ncol=1, free=TRUE, values=.05,
labels=c("BaTH"), name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=1, free=TRUE, values=.05,
labels=c("BsTH"), name="BsexTH" )
Threshold <-mxMatrix(type="Full", nrow=nth, ncol=ntv, free=TRUE, values=c(0.5,0.05,0.05,0.05,0.5,0.05,0.05,0.05),
lbound=c(-4,.001,.001,.001,-4,.001,.001,.001), ubound=c(4,1,1,1,4,1,1,1),
labels=c("T11","i11","i21","i31", "T11","i11","i21","i31"), name="Th" )
Thre <-mxAlgebra( expression= L %*% Th + BageTH%x%age + BsexTH%x%sex, name="expThre" )
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="expCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="expCovDZ" )
# Constraint on total variance of Ordinal variables (A+C+E=1)
matUnv <- mxMatrix( type="Unit", nrow=nv, ncol=1, name="Unv" )
varL <- mxConstraint( expression=diag2vec(V)==Unv, name="VarL" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="expCovMZ", means="M", dimnames=selVars, thresholds="expThre" )
objDZ <- mxExpectationNormal( covariance="expCovDZ", means="M", dimnames=selVars, thresholds="expThre" )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, matUnv )
modelMZ <- mxModel( pars, meanL, obs1, obs2, betaA, betaS ,Inc, Threshold, Thre, covMZ, dataMZ, objMZ, fitFunction, name="MZ" )
modelDZ <- mxModel( pars, meanL, obs1, obs2, betaA, betaS ,Inc, Threshold, Thre, covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll<- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
Conf <- mxCI (c ('A[1,1]', 'C[1,1]', 'E[1,1]','MZ.BageTH[1,1]','MZ.BsexTH[1,1]') )
AceModel <- mxModel( "ACE", pars, varL, modelMZ, modelDZ, minus2ll, obj, Conf)
# 5) RUN AceModel
AceFit <- mxRun(AceModel, intervals=T)
(AceSum <- summary(AceFit,verbose=TRUE))
round(AceFit@output$estimate,4)
round(c(AceFit$A$result,AceFit$C$result,AceFit$E$result),2)
comparison=mxCompare(SatFit, AceFit)
comparison2=mxCompare(SatFit,Sub3Fit)
AceFit@intervals
AceSum$CIdetail
(AceSum$CI)
setwd("../results")
save.image(file="liab_threshold_SSH_cov_25_Dec_2019.RData")
Based on the script above,
Results for the constrained correlation model for SSH
Sub3summ<-summary(Sub3Fit) #SSH univariate concor model
Sub3summ$CI
## lbound estimate ubound note
## MZ.expCorMZ[2,1] 0.38929238 0.49459145 0.58706209
## DZ.expCorDZ[2,1] 0.13310279 0.23830670 0.33914045
## MZ.BageTH[1,1] -0.01742713 0.02210298 0.06168909
## MZ.BsexTH[1,1] 0.18215500 0.25739695 0.33324275
Results for ACE model for SSH
Acesumm<-summary(AceFit,verbose=TRUE) #SSH univariate ACE model
Acesumm$CI
## lbound estimate ubound note
## ACE.A[1,1] 0.22349085 4.912699e-01 0.57709059
## ACE.C[1,1] NA 8.088777e-14 0.20764986 !!!
## ACE.E[1,1] 0.42290963 5.087301e-01 0.60309600
## MZ.BageTH[1,1] -0.01745582 2.209174e-02 0.06169605
## MZ.BsexTH[1,1] 0.18210316 2.573047e-01 0.33309804
Acesumm$CIdetail[,1:3]
## parameter side value
## 1 ACE.A[1,1] lower 2.234909e-01
## 2 ACE.A[1,1] upper 5.770906e-01
## 3 ACE.C[1,1] lower 5.628663e-05
## 4 ACE.C[1,1] upper 2.076499e-01
## 5 ACE.E[1,1] lower 4.229096e-01
## 6 ACE.E[1,1] upper 6.030960e-01
## 7 MZ.BageTH[1,1] lower -1.745582e-02
## 8 MZ.BageTH[1,1] upper 6.169605e-02
## 9 MZ.BsexTH[1,1] lower 1.821032e-01
## 10 MZ.BsexTH[1,1] upper 3.330980e-01
Constraints applied whereby the within-twin correlations and the liability thresholds are the same across birth order and zygosity.
We used the constrained correlational model to derive the phenotypic correlation and cross-twin cross-trait correlation between NSSH and SSH.
Script for the bivariate constrained correlation model:
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
str(self_harm_data);class(self_harm_data)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,x3zygos,u1cage1,u1cage2,sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
str(self_harm_data_c)
prop.table(table(self_harm_data_c$sex1))
sum(table(self_harm_data_c$sex1, self_harm_data_c$u1cslfh021)[1,])/sum(table(self_harm_data_c$sex1, self_harm_data_c$u1cslfh021))
#proportion of females: 62.4%
vars <-c('NSSH','SSH')
selVars <-c('NSSH1', 'SSH1', 'NSSH2', 'SSH2' )
useVars <-c('NSSH1', 'SSH1', 'NSSH2', 'SSH2' , 'u1cage1', 'u1cage2', 'sex1','sex2')
# Select Data for Analysis
selfharmdata_subset<-subset(self_harm_data_c, !is.na(x3zygos)&!is.na(u1cage1|u1cage2) &!is.na(sex1&sex2), useVars)
dim(selfharmdata_subset)
sum(table(selfharmdata_subset$NSSH1)); sum(table(selfharmdata_subset$SSH2))
table(selfharmdata_subset$NSSH1,useNA="always")
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(u1cage1|u1cage2) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(u1cage1|u1cage2) &!is.na(sex1&sex2), useVars)
mzData <- mutate(mzData, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
mzData <- mutate(mzData, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
dzData <- mutate(dzData, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
dzData <- mutate(dzData, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
describe(mzData)
describe(dzData)
# To get the CTs for NSSH
table(mzData$NSSH1, mzData$NSSH2)
table(dzData$NSSH1, dzData$NSSH2)
# To get the CTs for SSH
table(mzData$SSH1, mzData$SSH2)
table(dzData$SSH1, dzData$SSH2)
nv <- 2 # number of variables per twin
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
# 1) Fits a constrained Polychoric correlation model
# TH same across twins and across zyg groups
# Age effect is different acros variables, but same across thresholds within variables (if c>2)
# There is one overall rPH between var1-2 and the x-trait x-twin correlations are symmetric
# CREATE LABELS & START VALUES as objects(to ease specification)
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13','Tmz_21','imz_21','imz_22','imz_23') # THs for var 1 and 2 for a twin individual (mz)
LabCorMZ <-c('r21','rMZ1','MZxtxt','MZxtxt','rMZ2','r21')
LabThDZ <-c('Tmz_11','imz_11','imz_12','imz_13','Tmz_21','imz_21','imz_22','imz_23') # THs for var 1 and 2 for a twin individual (mz)
LabCorDZ <-c('r21','rDZ1','DZxtxt','DZxtxt','rDZ2','r21')
LabCovA <-c('BageThNSSH', 'BageThNSSH','BageThNSSH', 'BageThNSSH', 'BageThSSH', 'BageThSSH','BageThSSH', 'BageThSSH')
LabCovS <-c('BsexThNSSH', 'BsexThNSSH','BsexThNSSH', 'BsexThNSSH', 'BsexThSSH', 'BsexThSSH','BsexThSSH', 'BsexThSSH')
ThPat <-c(T,T,T,T)
StCorMZ <-c(.5, .4, .25, .25, .20, .5)
StCorDZ <-c(.5, .1, .15, .15, .10, .5)
StTH <-c(0.1,0.01,0.01,0.01)
#
# # Define definition variables to hold the Covariates
obsAge1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Age1")
obsAge2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Age2")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#
#
# Matrix & Algebra for expected means (SND), Thresholds, effect of Age on Th and correlations
Mean <-mxMatrix( type="Zero", nrow=1, ncol=ntv, name="M" )
betaA <-mxMatrix( type="Full", nrow=nth, ncol=nv, free=T, values=.2, labels=LabCovA, name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nv, free=T, values=.2, labels=LabCovS, name="BsexTH" )
Tmz <-mxMatrix( type="Full", nrow=nth, ncol=nv, free=ThPat, values=StTH, lbound=c(-4,-4), ubound=c(4,4),
labels=LabThMZ, name="ThMZ")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
ThresMZ <-mxAlgebra( expression= cbind(Low%*%ThMZ + BageTH%x%Age1 + BsexTH%x%Sex1,
Low%*%ThMZ + BageTH%x%Age2 + BsexTH%x%Sex2),
name="expThresMZ")
CorMZ <-mxMatrix( type="Stand", nrow=ntv, ncol=ntv, free=T, values=StCorMZ, labels=LabCorMZ, lbound=-.99, ubound=.99,
name="expCorMZ")
Tdz <-mxMatrix( type="Full", nrow=nth, ncol=nv, free=ThPat, values=StTH, lbound=c(-4,-4), ubound=c(4,4),
labels=LabThDZ, name="ThDZ")
ThresDZ <-mxAlgebra( expression= cbind(Low%*%ThDZ + BageTH%x%Age1 + BsexTH%x%Sex1,
Low%*%ThDZ + BageTH%x%Age2 + BsexTH%x%Sex2),
name="expThresDZ")
CorDZ <-mxMatrix( type="Stand", nrow=ntv, ncol=ntv, free=T, values=StCorDZ, labels=LabCorDZ, lbound=-.99, ubound=.99,
name="expCorDZ")
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="expCorMZ", means="M", dimnames=selVars, thresholds="expThresMZ" )
objDZ <- mxExpectationNormal( covariance="expCorDZ", means="M", dimnames=selVars, thresholds="expThresDZ" )
fitFunction <- mxFitFunctionML()
# Combine Groups
modelMZ <- mxModel( obsAge1, obsAge2, obsSex1, obsSex2, Mean, betaA, betaS, Tmz, inc, ThresMZ, CorMZ, dataMZ, objMZ, fitFunction, name="MZ" )
modelDZ <- mxModel( obsAge1, obsAge2, obsSex1, obsSex2, Mean, betaA, betaS, Tdz, inc, ThresDZ, CorDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
Conf1 <- mxCI (c ('MZ.expCorMZ','DZ.expCorDZ') )
Conf2 <- mxCI(c('MZ.BageTH','MZ.BsexTH'))
SatModel <- mxModel( "Sat", modelMZ, modelDZ, minus2ll, obj, Conf1, Conf2 )
# 1) RUN Saturated Model
SatFit <- mxTryHardOrdinal(SatModel, intervals=T)
summary<-(SatSumm <- summary(SatFit,verbose=T));summary
Results of bivariate constrained correlation model. The cross-twin and cross-twin cross-trait correlations are presented in Table S1:
SatSumm <- summary(SatFit,verbose=T)
SatSumm$CI
## lbound estimate ubound note
## r21 0.857873936 0.87171340 0.88433833
## rMZ1 0.485710368 0.55170787 0.61165972
## MZxtxt 0.423093710 0.49186840 0.55460937
## rMZ2 0.414349785 0.50686245 0.59034596
## rDZ1 0.200112240 0.27359131 0.34402180
## DZxtxt 0.177558984 0.24900658 0.31808443
## rDZ2 0.120780350 0.21587485 0.31008366
## BageThNSSH 0.002802471 0.03601269 0.06919654
## BageThSSH -0.025919889 0.01191569 0.04041692
## BsexThNSSH NA 0.40102636 0.46336563 !!!
## BsexThSSH 0.195487426 0.26709746 0.33925738
# Generate SatModel Output
round(SatFit@output$estimate,4)
## BageThNSSH BageThSSH BsexThNSSH BsexThSSH Tmz_11 imz_11 imz_12
## 0.0360 0.0119 0.4010 0.2671 -0.1599 0.4480 0.1888
## imz_13 Tmz_21 imz_21 imz_22 imz_23 r21 rMZ1
## 0.1517 0.8986 0.5485 0.2471 0.1597 0.8717 0.5517
## MZxtxt rMZ2 rDZ1 DZxtxt rDZ2
## 0.4919 0.5069 0.2736 0.2490 0.2159
We fitted the bivariate ACE model using Cholesky decomposition, which is then transformed into a correlated factors model.
Script for the unconstrained bivariate ACE model, after running the constrained correlation model:
# 2) Specify ACE Model, with ONE overall set of Thresholds with Age and Sex effects on thresholds
# CREATE LABELS for Cholesky decomposition with a function
laLower <- function(la,nv) { paste(la,rev(nv+1-sequence(1:nv)),rep(1:nv,nv:1),sep="_") }
LabTh <-c('T_11','i_11','i_21','i_31','T_22','i_12','i_22','i_32')
LabCovA <-c('BageThNSSH', 'BageThNSSH','BageThNSSH', 'BageThNSSH', 'BageThSSH', 'BageThSSH', 'BageThSSH', 'BageThSSH')
LabCovS <-c('BsexThNSSH', 'BsexThNSSH','BsexThNSSH', 'BsexThNSSH', 'BsexThSSH', 'BsexThSSH','BsexThSSH', 'BsexThSSH')
ThPat <-c(T,T,T,T,T,T,T,T)
StTH <-c(0.02,0.44,0.19,0.15,1.00, 0.55, 0.25, 0.16)
# Define definition variables to hold the Covariates
obsAge1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Age1")
obsAge2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Age2")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
# Matrix & Algebra for expected means (SND), Thresholds, effect of Age on Th and correlations
Mean <-mxMatrix( type="Zero", nrow=1, ncol=ntv, name="M" )
betaA <-mxMatrix( type="Full", nrow=nth, ncol=nv, free=T, values=c(0.03,0.03,0.03,0.03,0.008,0.008,0.008,0.008), labels=LabCovA, name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nv, free=T, values=c(0.40,0.40,0.40,0.40,0.30,0.30,0.30,0.30), labels=LabCovS, name="BsexTH" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nv, free=ThPat, values=StTH, labels=LabTh,
lbound=c(-4,-4,-4,-4), ubound=c(4,4,4,4), name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH%x%Age1 + BsexTH%x%Sex1, Low%*%Th + BageTH%x%Age2 + BsexTH%x%Sex2),
name="expThres")
# Matrices declared to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(.7,.6,.1), label=laLower("a",nv), name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(.0001,.0001,.0001), label=laLower("c",nv), name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(.6,.5,.4), label=laLower("e",nv), name="e" )
# Matrices generated to hold A, C, and E components and total Variance
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
covP <- mxAlgebra( expression=A+C+E, name="V" )
# Algebra to compute standardized variance components
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[1,1], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[2,2], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[1,1], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[2,2], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[1,1], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[2,2], name="SSH_e")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Algebra to compute Rph-A, Rph-C & Rph-E between SSH and NSSH
rphace<- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE" )
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="expCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="expCovDZ" )
# Constraint on total variance of Ordinal variables (A+C+E=1)
mUnv <- mxMatrix( type="Unit", nrow=nv, ncol=1, name="Unv" )
varL <- mxConstraint( expression=diag2vec(V)==Unv, name="VarL" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="expCovMZ", means="M", dimnames=selVars, thresholds="expThres" )
objDZ <- mxExpectationNormal( covariance="expCovDZ", means="M", dimnames=selVars, thresholds="expThres" )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list(pathA, pathC, pathE,covA, covC, covE, covP,
StA, StC, StE, matI, rph, rA, rC, rE, rphace,
obsAge1, obsAge2, obsSex1, obsSex2, Mean, betaA, betaS, Tr, Thres,
inc, mUnv, varL
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2)
modelMZ <- mxModel( pars, covMZ, dataMZ, objMZ, fitFunction, name="MZ" ) #varL only for MZ twins
modelDZ <- mxModel( pars, covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
Conf1 <- mxCI (c ('MZ.h2[1,1]', 'MZ.h2[2,2]', 'MZ.c2[1,1]', 'MZ.c2[2,2]', 'MZ.e2[1,1]', 'MZ.e2[2,2]') )
Conf2 <- mxCI (c ('MZ.Rph[2,1]', 'MZ.Ra[2,1]', 'MZ.Rc[2,1]', 'MZ.Re[2,1]') )
Conf3 <- mxCI (c ('MZ.RphACE[1,1]', 'MZ.RphACE[1,2]', 'MZ.RphACE[1,3]') )
Conf4 <- mxCI (c('MZ.BageTH','MZ.BsexTH'))
AceModel <- mxModel( "ACE", modelMZ, modelDZ,minus2ll, obj, Conf1, Conf2, Conf3, Conf4)
# 4) RUN AceModel
AceFit <- mxTryHardOrdinal(AceModel, intervals=T)
Results of the unconstrained bivariate model are represented in Figure 1
AceSumm <- summary(AceFit,verbose=TRUE) # summary of results
AceSumm$CI
## lbound estimate ubound note
## MZ.h2[1,1] 0.365911640 5.512456e-01 0.60728279
## MZ.h2[2,2] 0.298445577 4.953580e-01 0.57411890
## MZ.c2[1,1] NA 4.017441e-05 0.14934530 !!!
## MZ.c2[2,2] NA 4.766445e-05 0.15977685 !!!
## MZ.e2[1,1] 0.392682298 4.487142e-01 0.51405530
## MZ.e2[2,2] 0.425983863 5.045944e-01 0.59285937
## MZ.Rph[2,1] 0.857760255 8.715993e-01 0.88429987
## MZ.Ra[2,1] 0.888127959 9.415333e-01 1.00000000
## MZ.Rc[2,1] -1.000000000 9.945385e-01 NA !!!
## MZ.Re[2,1] 0.745281398 7.976567e-01 0.84315934
## MZ.RphACE[1,1] 0.316929614 4.920031e-01 0.55041981
## MZ.RphACE[1,2] -0.015008381 4.352048e-05 0.13782449
## MZ.RphACE[1,3] 0.322748848 3.795527e-01 0.44575515
## BageThNSSH -0.005381187 2.840035e-02 0.06165628
## BageThSSH -0.028848071 7.335219e-03 0.04549574
## BsexThNSSH 0.340127383 4.021614e-01 0.46445768
## BsexThSSH 0.195724135 2.672927e-01 0.33926390
# for CI with "!!!", the CIs are in AceSumm$CIdetail
AceSumm$CIdetail[,1:3]
## parameter side value
## 1 MZ.h2[1,1] lower 3.659116e-01
## 2 MZ.h2[1,1] upper 6.072828e-01
## 3 MZ.h2[2,2] lower 2.984456e-01
## 4 MZ.h2[2,2] upper 5.741189e-01
## 5 MZ.c2[1,1] lower 3.538302e-34
## 6 MZ.c2[1,1] upper 1.493453e-01
## 7 MZ.c2[2,2] lower 1.444403e-32
## 8 MZ.c2[2,2] upper 1.597769e-01
## 9 MZ.e2[1,1] lower 3.926823e-01
## 10 MZ.e2[1,1] upper 5.140553e-01
## 11 MZ.e2[2,2] lower 4.259839e-01
## 12 MZ.e2[2,2] upper 5.928594e-01
## 13 MZ.Rph[2,1] lower 8.577603e-01
## 14 MZ.Rph[2,1] upper 8.842999e-01
## 15 MZ.Ra[2,1] lower 8.881280e-01
## 16 MZ.Ra[2,1] upper 1.000000e+00
## 17 MZ.Rc[2,1] lower -1.000000e+00
## 18 MZ.Rc[2,1] upper 1.000000e+00
## 19 MZ.Re[2,1] lower 7.452814e-01
## 20 MZ.Re[2,1] upper 8.431593e-01
## 21 MZ.RphACE[1,1] lower 3.169296e-01
## 22 MZ.RphACE[1,1] upper 5.504198e-01
## 23 MZ.RphACE[1,2] lower -1.500838e-02
## 24 MZ.RphACE[1,2] upper 1.378245e-01
## 25 MZ.RphACE[1,3] lower 3.227488e-01
## 26 MZ.RphACE[1,3] upper 4.457552e-01
## 27 BageThNSSH lower -5.381187e-03
## 28 BageThNSSH upper 6.165628e-02
## 29 BageThSSH lower -2.884807e-02
## 30 BageThSSH upper 4.549574e-02
## 31 BsexThNSSH lower 3.401274e-01
## 32 BsexThNSSH upper 4.644577e-01
## 33 BsexThSSH lower 1.957241e-01
## 34 BsexThSSH upper 3.392639e-01
mxEval(MZ.h2,AceFit) # Heritability
## [,1] [,2]
## [1,] 0.5512456 0.5644831
## [2,] 0.5644831 0.4953580
mxEval(DZ.h2,AceFit) # shared E
## [,1] [,2]
## [1,] 0.5512456 0.5644831
## [2,] 0.5644831 0.4953580
mxEval(MZ.c2,AceFit) # Non-shared E
## [,1] [,2]
## [1,] 4.017441e-05 4.993175e-05
## [2,] 4.993175e-05 4.766445e-05
mxEval(MZ.Ra,AceFit) # Genetic correlation
## [,1] [,2]
## [1,] 1.0000000 0.9415333
## [2,] 0.9415333 1.0000000
mxEval(MZ.RphACE,AceFit)[1]/sum(mxEval(MZ.RphACE,AceFit)) #proportion of phenotypic correlation explained by genetic factors
## [1] 0.5644831
mxEval(MZ.Re,AceFit) # Non-shared E correlation
## [,1] [,2]
## [1,] 1.0000000 0.7976567
## [2,] 0.7976567 1.0000000
mxEval(MZ.RphACE,AceFit)[3]/sum(mxEval(MZ.RphACE,AceFit)) #proportion of phenotypic correlation explained by non-shared E factors
## [1] 0.435467
We constrained the a,c, and e paths of NSSH and SSH to be the same, and tested if this constrained model is significantly worse than the unconstrained model.
Script for constrained bivariate ACE model:
# 4) RUN constrained AceModel, constraining NSSH and SSH to have the same aetiology among the MZ twins.
Sub1Model <- mxModel(AceModel, name="sub1",
mxConstraint(MZ.NSSH_a==MZ.SSH_a, name="con1"),
mxConstraint(MZ.NSSH_c==MZ.SSH_c, name="con2"),
mxConstraint(MZ.NSSH_e==MZ.SSH_e, name="con3"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = T)
#save the output
setwd("../results")
save.image(file="Biv_LT_NSSH_SSH_ordinal_SLSQP_sat_ACE_constrained_with_comparisons_30_April_2020.RData")
Results of the goodness of fit test is in Table S4:
mxCompare(AceFit,Sub1Fit) #is Sub1Fit a significantly worse fit?
## base comparison ep minus2LL df AIC diffLL diffdf p
## 1 ACE <NA> 21 18857.03 18109 -17360.97 NA NA NA
## 2 ACE sub1 21 18859.55 18112 -17364.45 2.521106 3 0.4714889
We tested for quantitative sex differences in the aetiologies for NSSH and SSH Results of sex differences analyses are in Note S2, Table S4 and Table S6
We firstly ran a constrained correlation model to obtain the cross-twin correlations for twins of different zygosity and sex (MZ males, MZ females, DZ males, DZ females and DZ opposite sex)
# MODEL 1: Constrained Correlation Model
# One threshold for males, one threshold for females (i.e. within sex, the threshold is equated across twin order and zygosity group)
# Matrix for expected Means/Threshold
# Define definition variables to hold the Covariates (Age on TH of categorical variables
Obs1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Def1")
Obs2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Def2")
# Matrix & Algebra for expected means (SND), Thresholds, effect of Age on Th
Mean <-mxMatrix( type="Zero", nrow=1, ncol=ntv, name="expM" )
Betam <-mxMatrix( type="Full", nrow=1, ncol=1, free=T, labels=c('Bm1'), values=0.02, name="BetaM" )
Betaf <-mxMatrix( type="Full", nrow=1, ncol=1, free=T, labels=c('Bf1'), values=0.01, name="BetaF" )
TrM <-mxMatrix( type="Full", nrow=nth, ncol=nv, free=T,
values=c(0.69,1.10,1.30,1.50), labels=c('THm1','THm2','THm3','THm4'),
lbound=c(-4,0.001,0.001,0.001), ubound=c(4,4,4,4), name="Thm")
TrF <-mxMatrix( type="Full", nrow=nth, ncol=nv, free=T,
values=c(0.22,0.60,0.80,1.00), labels=c('THf1','THf2','THf3','THf4'),
lbound=c(-4,0.001,0.001,0.001), ubound=c(4,4,4,4), name="Thf")
#Inc <-mxMatrix( type="Lower", nrow=nth, ncol=nth, free=FALSE, values=1, name="L" )
ThresM <-mxAlgebra( expression= cbind(Thm + (BetaM%x%(Def1)), Thm + (BetaM%x%(Def2))), name="expThresm")
ThresF <-mxAlgebra( expression= cbind(Thf + (BetaF%x%(Def1)), Thf + (BetaF%x%(Def2))), name="expThresf")
ThresMF <-mxAlgebra( expression= cbind(Thm + (BetaM%x%(Def1)), Thf + (BetaF%x%(Def2))), name="expThresmf")
# Matrices to store correlations
corMZM <-mxMatrix( type="Stand", nrow=ntv, ncol=ntv, free=T, values=.6, labels=c("RMZM"), lbound=-.999, ubound=.999, name="expCovMZM")
corDZM <-mxMatrix( type="Stand", nrow=ntv, ncol=ntv, free=T, values=.3, labels=c("RDZM"), lbound=-.999, ubound=.999, name="expCovDZM")
corMZF <-mxMatrix( type="Stand", nrow=ntv, ncol=ntv, free=T, values=.5, labels=c("RMZF"), lbound=-.999, ubound=.999, name="expCovMZF")
corDZF <-mxMatrix( type="Stand", nrow=ntv, ncol=ntv, free=T, values=.2, labels=c("RDZF"), lbound=-.999, ubound=.999, name="expCovDZF")
corDOS <-mxMatrix( type="Stand", nrow=ntv, ncol=ntv, free=T, values=.7, labels=c("RDOS"), lbound=-.999, ubound=.999, name="expCovDOS")
# Data objects for Multiple Groups
dataMZM <- mxData( observed=mzmData, type="raw" )
dataDZM <- mxData( observed=dzmData, type="raw" )
dataMZF <- mxData( observed=mzfData, type="raw" )
dataDZF <- mxData( observed=dzfData, type="raw" )
dataDOS <- mxData( observed=dzoData, type="raw" )
# Objective objects for Multiple Groups
objmzm <- mxExpectationNormal( covariance="expCovMZM", means="expM", dimnames=selVars, thresholds="expThresm", threshnames=c("NSSH1","NSSH2") )
objdzm <- mxExpectationNormal( covariance="expCovDZM", means="expM", dimnames=selVars, thresholds="expThresm", threshnames=c("NSSH1","NSSH2") )
objmzf <- mxExpectationNormal( covariance="expCovMZF", means="expM", dimnames=selVars, thresholds="expThresf", threshnames=c("NSSH1","NSSH2") )
objdzf <- mxExpectationNormal( covariance="expCovDZF", means="expM", dimnames=selVars, thresholds="expThresf", threshnames=c("NSSH1","NSSH2") )
objdzo <- mxExpectationNormal( covariance="expCovDOS", means="expM", dimnames=selVars, thresholds="expThresmf", threshnames=c("NSSH1","NSSH2") )
fitFunction <- mxFitFunctionML()
# Combine Groups
parsm <- list( Obs1, Obs2, Mean, Betam, fitFunction)
parsf <- list( Obs1, Obs2, Mean, Betaf, fitFunction)
modelMZM <- mxModel(parsm, TrM, ThresM, corMZM, dataMZM, objmzm, name="MZM")
modelDZM <- mxModel(parsm, TrM, ThresM, corDZM, dataDZM, objdzm, name="DZM")
modelMZF <- mxModel(parsf, TrF, ThresF, corMZF, dataMZF, objmzf, name="MZF")
modelDZF <- mxModel(parsf, TrF, ThresF, corDZF, dataDZF, objdzf, name="DZF")
modelDOS <- mxModel(parsm, parsf, TrM, TrF, ThresMF, corDOS, dataDOS, objdzo, name="DOS")
minus2ll <- mxAlgebra(expression=MZM.objective + DZM.objective + MZF.objective + DZF.objective + DOS.objective, name="m2LL")
obj <- mxFitFunctionAlgebra("m2LL")
Conf1 <- mxCI (c ('MZM.expCovMZM[2,1]', 'MZF.expCovMZF[2,1]'))
Conf2 <- mxCI (c ('DZM.expCovDZM[2,1]', 'DZF.expCovDZF[2,1]'))
Conf3 <- mxCI (c ('DOS.expCovDOS[2,1]'))
corModel <- mxModel('cor', modelMZM, modelDZM, modelMZF, modelDZF, modelDOS, minus2ll, obj, Conf1, Conf2, Conf3)
# RUN cor Model
corFit <- mxRun(corModel, intervals=T)
corSumm <- summary(corFit)
corSumm$CI
#save the results to an Excel sheet
xlsx::write.xlsx(corSumm$CI, "descriptive_stats.xlsx", sheetName = "NSSH_cor", append = T)
Results from the constrained correlation model (sex differences) for NSSH:
| Zygosity and sex | lbound | estimate | ubound |
|---|---|---|---|
| MZ male | 0.37 | 0.51 | 0.63 |
| MZ female | 0.48 | 0.56 | 0.63 |
| DZ male | 0.04 | 0.25 | 0.44 |
| DZ female | 0.24 | 0.35 | 0.45 |
| DZ opposite sex | 0.09 | 0.20 | 0.31 |
In the heterogeneity model, males and females were allowed to have difference h2, c2 and e2 for NSSH.
Script for the heterogeneity model:
#
# MODEL 2: Quantitative sex limitation model (heterogeneity model)
# Same genetic and C factors account for (co)variances in males and females, but the magnitude of their effects is still allowed to differ across the sexes
# Male-female Ra fixed to 0.5 in DZOS group (Ra=0.5)
# Male-female Rc fixed to 1 in DZOS groups (Rc=1.0)
# Matrix for expected Means
# Define definition variables to hold the Covariates (Age on TH of categorical variables
Obs1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Def1")
Obs2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Def2")
# Matrix & Algebra for expected means (SND), Thresholds, effect of Age on Th
Mean <-mxMatrix( type="Zero", nrow=1, ncol=ntv, name="expM" )
Betam <-mxMatrix( type="Full", nrow=1, ncol=1, free=T, labels=c('Bm1'), values=0.0186, name="BetaM" )
Betaf <-mxMatrix( type="Full", nrow=1, ncol=1, free=T, labels=c('Bf1'), values=0.0375, name="BetaF" )
TrM <-mxMatrix( type="Full", nrow=nth, ncol=nv, free=T,
values=c(0.61,1.10,1.29,1.43), labels=c('THm1','THm2','THm3','THm4'),
lbound=c(-4,-4,-4,-4), ubound=c(4,4,4,4), name="Thm")
TrF <-mxMatrix( type="Full", nrow=nth, ncol=nv, free=T,
values=c(-0.19,0.23,0.42,0.59), labels=c('THf1','THf2','THf3','THf4'),
lbound=c(-4,-4,-4,-4), ubound=c(4,4,4,4), name="Thf")
ThresM <-mxAlgebra( expression= cbind(Thm + (BetaM%x%Def1), Thm + (BetaM%x%Def2)), name="expThresm")
ThresF <-mxAlgebra( expression= cbind(Thf + (BetaF%x%Def1), Thf + (BetaF%x%Def2)), name="expThresf")
ThresMF <-mxAlgebra( expression= cbind(Thm + (BetaM%x%Def1), Thf + (BetaF%x%Def2)), name="expThresmf")
# Matrices to store a, c and e Path Coefficients
pathAm <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=T, values=c(.71), label=c("am11"), name="am")
pathCm <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=T, values=c(.07), label=c("cm11"), name="cm")
pathEm <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=T, values=c(.70), label=c("em11"), name="em")
pathAf <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=T, values=c(.64), label=c("af11"), name="af")
pathCf <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=T, values=c(.38), label=c("cf11"), name="cf")
pathEf <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=T, values=c(.67), label=c("ef11"), name="ef")
rAmf <- mxMatrix( type="Full", nrow=nv, ncol=nv, free=F, values=.5, lbound=0, ubound=.5, name="Rao" ) # fixed to .5
rCmf <- mxMatrix( type="Full", nrow=nv, ncol=nv, free=F, values=1, lbound=0, ubound=1,name="Rco" ) # fixed to 1
# Matrices generated to hold A, and E computed Variance Components
covAm <- mxAlgebra( expression=am %*% t(am), name="Am")
covCm <- mxAlgebra( expression=cm %*% t(cm), name="Cm")
covEm <- mxAlgebra( expression=em %*% t(em), name="Em")
covAf <- mxAlgebra( expression=af %*% t(af), name="Af")
covCf <- mxAlgebra( expression=cf %*% t(cf), name="Cf")
covEf <- mxAlgebra( expression=ef %*% t(ef), name="Ef")
# Algebra to compute standardized variance components
covM <- mxAlgebra( expression=Am+Cm+Em, name="Vm")
covF <- mxAlgebra( expression=Af+Cf+Ef, name="Vf")
StAm <- mxAlgebra( expression=Am/Vm, name="hm2")
StCm <- mxAlgebra( expression=Cm/Vm, name="cm2")
StEm <- mxAlgebra( expression=Em/Vm, name="em2")
StAf <- mxAlgebra( expression=Af/Vf, name="hf2")
StCf <- mxAlgebra( expression=Cf/Vf, name="cf2")
StEf <- mxAlgebra( expression=Ef/Vf, name="ef2")
# Constraint on total variance of Ordinal variable (A+C+E=1)
varLM <- mxConstraint( expression=Vm[1,1]==1, name="VarLM" )
varLF <- mxConstraint( expression=Vf[1,1]==1, name="VarLF" )
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZM <- mxAlgebra( expression= rbind ( cbind(Am+Cm+Em, Am+Cm),
cbind(Am+Cm, Am+Cm+Em)) , name="expCovMZM")
covMZF <- mxAlgebra( expression= rbind ( cbind(Af+Cf+Ef, Af+Cf),
cbind(Af+Cf, Af+Cf+Ef)) , name="expCovMZF")
covDZM <- mxAlgebra( expression= rbind ( cbind(Am+Cm+Em, 0.5%x%Am+Cm),
cbind(0.5%x%Am+Cm, Am+Cm+Em)) , name="expCovDZM")
covDZF <- mxAlgebra( expression= rbind ( cbind(Af+Cf+Ef, 0.5%x%Af+Cf),
cbind(0.5%x%Af+Cf, Af+Cf+Ef)) , name="expCovDZF")
covDOS <- mxAlgebra( expression= rbind ( cbind(Am+Cm+Em, am%*%Rao%*%t(af) + cm%*%Rco%*%t(cf) ),
cbind(af%*%t(Rao)%*%t(am) + cf%*%t(Rco)%*%t(cm), Af+Cf+Ef) ) , name="expCovDOS")
# Data objects for Multiple Groups
dataMZM <- mxData( observed=mzmData, type="raw" )
dataDZM <- mxData( observed=dzmData, type="raw" )
dataMZF <- mxData( observed=mzfData, type="raw" )
dataDZF <- mxData( observed=dzfData, type="raw" )
dataDOS <- mxData( observed=dzoData, type="raw" )
# Objective objects for Multiple Groups
objmzm <- mxExpectationNormal( covariance="expCovMZM", means="expM", dimnames=selVars, thresholds="expThresm", threshnames=c("NSSH1","NSSH2") )
objdzm <- mxExpectationNormal( covariance="expCovDZM", means="expM", dimnames=selVars, thresholds="expThresm", threshnames=c("NSSH1","NSSH2") )
objmzf <- mxExpectationNormal( covariance="expCovMZF", means="expM", dimnames=selVars, thresholds="expThresf", threshnames=c("NSSH1","NSSH2") )
objdzf <- mxExpectationNormal( covariance="expCovDZF", means="expM", dimnames=selVars, thresholds="expThresf", threshnames=c("NSSH1","NSSH2") )
objdzo <- mxExpectationNormal( covariance="expCovDOS", means="expM", dimnames=selVars, thresholds="expThresmf", threshnames=c("NSSH1","NSSH2") )
fitFunction <- mxFitFunctionML()
# Combine Groups
parsm <- list( Obs1, Obs2, Mean, Betam, pathAm, pathCm, pathEm, covAm, covCm, covEm, covM, StAm, StCm, StEm, fitFunction )
parsf <- list( Obs1, Obs2, Mean, Betaf, pathAf, pathCf, pathEf, covAf, covCf, covEf, covF, StAf, StCf, StEf, fitFunction )
modelMZM <- mxModel(parsm, TrM, ThresM, covMZM, dataMZM, objmzm, varLM, name="MZM")
modelDZM <- mxModel(parsm, TrM, ThresM, covDZM, dataDZM, objdzm, name="DZM")
modelMZF <- mxModel(parsf, TrF, ThresF, covMZF, dataMZF, objmzf, varLF, name="MZF")
modelDZF <- mxModel(parsf, TrF, ThresF, covDZF, dataDZF, objdzf, name="DZF")
modelDOS <- mxModel(parsm, parsf, TrM, TrF, ThresMF,
rAmf, rCmf, covDOS, dataDOS, objdzo, name="DOS")
minus2ll <- mxAlgebra(expression=MZM.objective + DZM.objective + MZF.objective + DZF.objective + DOS.objective, name="m2LL")
obj <- mxFitFunctionAlgebra("m2LL")
ciM <- mxCI (c ('MZM.hm2', 'MZM.cm2', 'MZM.em2' ) ) # h2, c2, e2 males
ciF <- mxCI (c ('MZF.hf2', 'MZF.cf2', 'MZF.ef2' ) ) # h2, c2, e2 females
HetACEModel <-mxModel('HetACE', modelMZM, modelDZM, modelMZF, modelDZF, modelDOS, minus2ll, obj, ciM, ciF)
# RUN univariate ACE Model
HetACEFit <- mxTryHardOrdinal(HetACEModel, intervals=T)
Results from the heterogeneity model for NSSH:
HetACESumm <- summary(HetACEFit, verbose=T)
HetACESumm$CI #show the CI
## lbound estimate ubound note
## MZM.hm2[1,1] NA 0.500921211 0.6167271 !!!
## MZM.cm2[1,1] NA 0.005371819 0.3730496 !!!
## MZM.em2[1,1] 3.790635e-01 0.493706970 0.6260728
## MZF.hf2[1,1] 1.654440e-01 0.413755539 0.6126553
## MZF.cf2[1,1] 2.131622e-34 0.142030974 NA !!!
## MZF.ef2[1,1] 3.748761e-01 0.444213487 0.5225311
HetACESumm$CIdetail[,1:3] # show the CI details
## parameter side value
## 1 MZM.hm2[1,1] lower 3.861800e-05
## 2 MZM.hm2[1,1] upper 6.167271e-01
## 3 MZM.cm2[1,1] lower 1.779879e-30
## 4 MZM.cm2[1,1] upper 3.730496e-01
## 5 MZM.em2[1,1] lower 3.790635e-01
## 6 MZM.em2[1,1] upper 6.260728e-01
## 7 MZF.hf2[1,1] lower 1.654440e-01
## 8 MZF.hf2[1,1] upper 6.126553e-01
## 9 MZF.cf2[1,1] lower 2.131622e-34
## 10 MZF.cf2[1,1] upper 5.665264e-01
## 11 MZF.ef2[1,1] lower 3.748761e-01
## 12 MZF.ef2[1,1] upper 5.225311e-01
Script for homogeneity model for sex in NSSH:
# MODEL: univ HOMOGENEITY MODEL
# NO Quantitative dif AND NO Qualitative sex Diff
# There is one set of A,C,E parameters and one set of A,C,E correlations across gender
# From the heterogeneity model (model 3), we simply use the same 'labeling' to equate male and female A, C and E paths
HomACEModel <- mxModel(HetACEFit, name="HomACE")
HomACEModel <-omxSetParameters(HomACEModel, labels=c("af11", "cf11", "ef11"), free=T, newlabels=c("am11", "cm11", "em11"), values=c(.7, .01, .4))
HomACEModel <- omxAssignFirstParameters(HomACEModel)
HomACEFit <- mxTryHardOrdinal(HomACEModel, intervals=T)
Results for homogeneity model for sex in NSSH:
HomACESumm <- summary(HomACEFit,verbose=T)
HomACESumm$CI
## lbound estimate ubound note
## MZM.hm2[1,1] 0.3505886 5.433484e-01 0.6003098
## MZM.cm2[1,1] NA 4.564371e-07 0.1544247 !!!
## MZM.em2[1,1] 0.3996902 4.566512e-01 0.5180843
## MZF.hf2[1,1] 0.3505886 5.433484e-01 0.6003098
## MZF.cf2[1,1] NA 4.564371e-07 0.1544247 !!!
## MZF.ef2[1,1] 0.3996902 4.566512e-01 0.5180843
HomACESumm$CIdetail[,1:3]
## parameter side value
## 1 MZM.hm2[1,1] lower 3.505886e-01
## 2 MZM.hm2[1,1] upper 6.003098e-01
## 3 MZM.cm2[1,1] lower 2.735922e-20
## 4 MZM.cm2[1,1] upper 1.544247e-01
## 5 MZM.em2[1,1] lower 3.996902e-01
## 6 MZM.em2[1,1] upper 5.180843e-01
## 7 MZF.hf2[1,1] lower 3.505886e-01
## 8 MZF.hf2[1,1] upper 6.003098e-01
## 9 MZF.cf2[1,1] lower 2.735922e-20
## 10 MZF.cf2[1,1] upper 1.544247e-01
## 11 MZF.ef2[1,1] lower 3.996902e-01
## 12 MZF.ef2[1,1] upper 5.180843e-01
Is the homogeneity model a better fit than the heterogeneity model for NSSH?
mxCompare(HetACEFit, HomACEFit)
## base comparison ep minus2LL df AIC diffLL diffdf p
## 1 HetACE <NA> 16 13948.13 9049 -4149.867 NA NA NA
## 2 HetACE HomACE 13 13952.25 9052 -4151.751 4.115972 3 0.2492105
# The answer is yes
nv <- 1 # number of variables per twin
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
selVars <- c('SSH1' , 'SSH2')
useVars<- c('SSH1' , 'SSH2',"sex1","sex2",'age1', 'age2')
# Select Data for Analysis
#sexzyg 1 = MZ male, 2=DZ male, 3=MZ female, 4=DZ female, 5=DZOS
mzmData <- subset(self_harm_data_c, sexzyg==1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #MZM
dzmData <- subset(self_harm_data_c, sexzyg==2 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #DZM
mzfData <- subset(self_harm_data_c, sexzyg==3 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #MZF
dzfData <- subset(self_harm_data_c, sexzyg==4 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #DZF
dzoData <- subset(self_harm_data_c, sexzyg==5 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #DZO
hetcor(mzmData$SSH1, mzmData$SSH2)$correlations #0.68
hetcor(dzoData$SSH1, dzoData$SSH2)$correlations #0.14
table(mzmData$sex1);table(mzmData$sex2) #males=1
table(dzmData$sex1);table(dzmData$sex2)
table(mzfData$sex1);table(mzfData$sex2) #females=0
table(dzfData$sex1);table(dzfData$sex2)
table(dzoData$sex1,useNA = "always");table(dzoData$sex2,useNA = "always") #total=1875
#recode twin 1 as males and twin 2 as females for dzoData:
dzoData$newSSH1=NA;dzoData$newSSH2=NA;dzoData$newsex1=NA;dzoData$newsex2=NA
table(dzoData$SSH1,useNA = "always");table(dzoData$SSH2,useNA = "always")
table(is.na(dzoData$SSH1));table(is.na(dzoData$SSH2))
table(dzoData$sex1,useNA = "always");table(dzoData$sex2,useNA = "always")
dzoData<-mutate(dzoData, newSSH1=ifelse(sex1==1,SSH1, ifelse(sex1==0,SSH2,999)))
dzoData<-mutate(dzoData, newSSH2=ifelse(sex2==0,SSH2, ifelse(sex2==1,SSH1,999)))
dzoData<-mutate(dzoData, newsex1=ifelse(sex1==1,sex1, ifelse(sex1==0,sex2,999))) #recode twin 1 as males
dzoData<-mutate(dzoData, newsex2=ifelse(sex2==0,sex2, ifelse(sex2==1,sex1,999))) #recode twin 2 as females
table(dzoData$newSSH1,dzoData$newsex1,useNA = "always")
table(dzoData$newSSH2,dzoData$newsex2,useNA = "always")
sum(table(dzoData$newSSH1,dzoData$newsex1))
sum(table(dzoData$newSSH2,dzoData$newsex2))
#minus one to get zero and to replace the values to SSH1/2
dzoData$newSSH1<-dzoData$newSSH1-1
dzoData$newSSH2<-dzoData$newSSH2-1
table(dzoData$newSSH1,dzoData$newsex1)
table(dzoData$newSSH2,dzoData$newsex2)
#check number
check<-subset(self_harm_data_c, sexzyg==5 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars)
table(check$SSH1,check$sex1)
#check correlation
hetcor(as.factor(dzoData$SSH1), as.factor(dzoData$SSH2)) #0.14
hetcor(as.factor(dzoData$newSSH1), as.factor(dzoData$newSSH2)) #0.16
dzoData$SSH1<-dzoData$newSSH1
dzoData$SSH2<-dzoData$newSSH2
dzoData$sex1<-dzoData$newsex1
dzoData$sex2<-dzoData$newsex2
table(dzoData$SSH1,dzoData$sex1)
table(dzoData$SSH2,dzoData$sex2)
#make them ordered factor again
dzoData$SSH1<-mxFactor(dzoData$SSH1, levels=c(0:4) )
dzoData$SSH2<-mxFactor(dzoData$SSH2, levels=c(0:4) )
psych::describe(mzmData)
psych::describe(dzmData)
psych::describe(mzfData)
psych::describe(dzfData)
psych::describe(dzoData)
# To get Contingency Tables per zygosity group (i.e. complete pairs only)
table(mzmData$SSH1, mzmData$SSH2)
table(dzmData$SSH1, dzmData$SSH2)
table(mzfData$SSH1, mzfData$SSH2)
table(dzfData$SSH1, dzfData$SSH2)
table(dzoData$SSH1, dzoData$SSH2)
hetcor(mzmData$SSH1, mzmData$SSH2)$correlations
hetcor(dzoData$SSH1, dzoData$SSH2)$correlations
# MODEL 1: Constrained Correlation Model
# One threshold for males, one threshold for females (i.e. within sex, the threshold is equated across twin order and zygosity group)
# Matrix for expected Means/Threshold
# Define definition variables to hold the Covariates (Age on TH of categorical variables
Obs1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Def1")
Obs2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Def2")
# Matrix & Algebra for expected means (SND), Thresholds, effect of Age on Th
Mean <-mxMatrix( type="Zero", nrow=1, ncol=ntv, name="expM" )
Betam <-mxMatrix( type="Full", nrow=1, ncol=1, free=T, labels=c('Bm1'), values=-0.004, name="BetaM" )
Betaf <-mxMatrix( type="Full", nrow=1, ncol=1, free=T, labels=c('Bf1'), values=0.036, name="BetaF" )
TrM <-mxMatrix( type="Full", nrow=nth, ncol=nv, free=T,
values=c(1.506,2.04,2.36,2.49), labels=c('THm1','THm2','THm3','THm4'),
lbound=-5, ubound=5, name="Thm")
TrF <-mxMatrix( type="Full", nrow=nth, ncol=nv, free=T,
values=c(0.35,0.93,1.17,1.36), labels=c('THf1','THf2','THf3','THf4'),
lbound=-5, ubound=5, name="Thf")
#Inc <-mxMatrix( type="Lower", nrow=nth, ncol=nth, free=FALSE, values=1, name="L" )
ThresM <-mxAlgebra( expression= cbind(Thm + (BetaM%x%(Def1)), Thm + (BetaM%x%(Def2))), name="expThresm")
ThresF <-mxAlgebra( expression= cbind(Thf + (BetaF%x%(Def1)), Thf + (BetaF%x%(Def2))), name="expThresf")
ThresMF <-mxAlgebra( expression= cbind(Thm + (BetaM%x%(Def1)), Thf + (BetaF%x%(Def2))), name="expThresmf")
# Matrices to store correlations
corMZM <-mxMatrix( type="Stand", nrow=ntv, ncol=ntv, free=T, values=.70, labels=c("RMZM"), lbound=-.999, ubound=.999, name="expCovMZM")
corDZM <-mxMatrix( type="Stand", nrow=ntv, ncol=ntv, free=T, values=.30, labels=c("RDZM"), lbound=-.999, ubound=.999, name="expCovDZM")
corMZF <-mxMatrix( type="Stand", nrow=ntv, ncol=ntv, free=T, values=.42, labels=c("RMZF"), lbound=-.999, ubound=.999, name="expCovMZF")
corDZF <-mxMatrix( type="Stand", nrow=ntv, ncol=ntv, free=T, values=.30, labels=c("RDZF"), lbound=-.999, ubound=.999, name="expCovDZF")
corDOS <-mxMatrix( type="Stand", nrow=ntv, ncol=ntv, free=T, values=.15, labels=c("RDOS"), lbound=-.999, ubound=.999, name="expCovDOS")
# Data objects for Multiple Groups
dataMZM <- mxData( observed=mzmData, type="raw" )
dataDZM <- mxData( observed=dzmData, type="raw" )
dataMZF <- mxData( observed=mzfData, type="raw" )
dataDZF <- mxData( observed=dzfData, type="raw" )
dataDOS <- mxData( observed=dzoData, type="raw" )
# Objective objects for Multiple Groups
objmzm <- mxExpectationNormal( covariance="expCovMZM", means="expM", dimnames=selVars, thresholds="expThresm", threshnames=c("SSH1","SSH2") )
objdzm <- mxExpectationNormal( covariance="expCovDZM", means="expM", dimnames=selVars, thresholds="expThresm", threshnames=c("SSH1","SSH2") )
objmzf <- mxExpectationNormal( covariance="expCovMZF", means="expM", dimnames=selVars, thresholds="expThresf", threshnames=c("SSH1","SSH2") )
objdzf <- mxExpectationNormal( covariance="expCovDZF", means="expM", dimnames=selVars, thresholds="expThresf", threshnames=c("SSH1","SSH2") )
objdzo <- mxExpectationNormal( covariance="expCovDOS", means="expM", dimnames=selVars, thresholds="expThresmf", threshnames=c("SSH1","SSH2") )
fitFunction <- mxFitFunctionML()
# Combine Groups
parsm <- list( Obs1, Obs2, Mean, Betam, fitFunction)
parsf <- list( Obs1, Obs2, Mean, Betaf, fitFunction)
modelMZM <- mxModel(parsm, TrM, ThresM, corMZM, dataMZM, objmzm, name="MZM")
modelDZM <- mxModel(parsm, TrM, ThresM, corDZM, dataDZM, objdzm, name="DZM")
modelMZF <- mxModel(parsf, TrF, ThresF, corMZF, dataMZF, objmzf, name="MZF")
modelDZF <- mxModel(parsf, TrF, ThresF, corDZF, dataDZF, objdzf, name="DZF")
modelDOS <- mxModel(parsm, parsf, TrM, TrF, ThresMF, corDOS, dataDOS, objdzo, name="DOS")
minus2ll <- mxAlgebra(expression=MZM.objective + DZM.objective + MZF.objective + DZF.objective + DOS.objective, name="m2LL")
obj <- mxFitFunctionAlgebra("m2LL")
Conf1 <- mxCI (c ('MZM.expCovMZM[2,1]', 'MZF.expCovMZF[2,1]'))
Conf2 <- mxCI (c ('DZM.expCovDZM[2,1]', 'DZF.expCovDZF[2,1]'))
Conf3 <- mxCI (c ('DOS.expCovDOS[2,1]'))
corModel <- mxModel('cor', modelMZM, modelDZM, modelMZF, modelDZF, modelDOS, minus2ll, obj, Conf1, Conf2, Conf3)
# RUN cor Model
corFit <- mxTryHardOrdinal(corModel, intervals=T,extraTries=20)
(corSumm <- summary(corFit))
xlsx::write.xlsx(corSumm$CI, "descriptive_stats.xlsx", sheetName = "SSH_cor", append = T)
The results from the constrained correlation model for twins across zygosity and sex for SSH:
| Zygosity and sex | lbound | estimate | ubound |
|---|---|---|---|
| MZ male | 0.53 | 0.70 | 0.81 |
| MZ female | 0.28 | 0.42 | 0.53 |
| DZ male | 0.03 | 0.29 | 0.53 |
| DZ female | 0.13 | 0.28 | 0.42 |
| DZ opposite sex | 0.00 | 0.17 | 0.34 |
Script for heterogeneity model for sex in SSH:
# MODEL 2: Quantitative sex limitation model (heterogeneity model)
# Same genetic and C factors account for (co)variances in males and females, but the magnitude of their effects is still allowed to differ across the sexes
# Male-female Ra fixed to 0.5 in DZOS group (Ra=0.5)
# Male-female Rc fixed to 1 in DZOS groups (Rc=1.0)
# Matrix for expected Means
# Define definition variables to hold the Covariates (Age on TH of categorical variables
Obs1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Def1")
Obs2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Def2")
# Matrix & Algebra for expected means (SND), Thresholds, effect of Age on Th
Mean <-mxMatrix( type="Zero", nrow=1, ncol=ntv, name="expM" )
Betam <-mxMatrix( type="Full", nrow=1, ncol=1, free=T, labels=c('Bm1'), values=-0.0046, name="BetaM" )
Betaf <-mxMatrix( type="Full", nrow=1, ncol=1, free=T, labels=c('Bf1'), values=0.0364, name="BetaF" )
TrM <-mxMatrix( type="Full", nrow=nth, ncol=nv, free=T,
values=c(1.516,2.054,2.373,2.499), labels=c('THm1','THm2','THm3','THm4'),
lbound=-4, ubound=4, name="Thm")
TrF <-mxMatrix( type="Full", nrow=nth, ncol=nv, free=T,
values=c(0.351,0.928,1.170,2.356), labels=c('THf1','THf2','THf3','THf4'),
lbound=-4, ubound=4, name="Thf")
ThresM <-mxAlgebra( expression= cbind(Thm + (BetaM%x%Def1), Thm + (BetaM%x%Def2)), name="expThresm")
ThresF <-mxAlgebra( expression= cbind(Thf + (BetaF%x%Def1), Thf + (BetaF%x%Def2)), name="expThresf")
ThresMF <-mxAlgebra( expression= cbind(Thm + (BetaM%x%Def1), Thf + (BetaF%x%Def2)), name="expThresmf")
# Matrices to store a, c and e Path Coefficients
pathAm <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=T, values=c(.825), label=c("am11"), name="am")
pathCm <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=T, values=c(.087), label=c("cm11"), name="cm")
pathEm <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=T, values=c(.558), label=c("em11"), name="em")
pathAf <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=T, values=c(.508), label=c("af11"), name="af")
pathCf <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=T, values=c(.394), label=c("cf11"), name="cf")
pathEf <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=T, values=c(.766), label=c("ef11"), name="ef")
rAmf <- mxMatrix( type="Full", nrow=nv, ncol=nv, free=F, values=.5, lbound=0, ubound=.5, name="Rao" ) # fixed to .5
rCmf <- mxMatrix( type="Full", nrow=nv, ncol=nv, free=F, values=1, lbound=0, ubound=1,name="Rco" ) # fixed to 1
# Matrices generated to hold A, and E computed Variance Components
covAm <- mxAlgebra( expression=am %*% t(am), name="Am")
covCm <- mxAlgebra( expression=cm %*% t(cm), name="Cm")
covEm <- mxAlgebra( expression=em %*% t(em), name="Em")
covAf <- mxAlgebra( expression=af %*% t(af), name="Af")
covCf <- mxAlgebra( expression=cf %*% t(cf), name="Cf")
covEf <- mxAlgebra( expression=ef %*% t(ef), name="Ef")
# Algebra to compute standardized variance components
covM <- mxAlgebra( expression=Am+Cm+Em, name="Vm")
covF <- mxAlgebra( expression=Af+Cf+Ef, name="Vf")
StAm <- mxAlgebra( expression=Am/Vm, name="hm2")
StCm <- mxAlgebra( expression=Cm/Vm, name="cm2")
StEm <- mxAlgebra( expression=Em/Vm, name="em2")
StAf <- mxAlgebra( expression=Af/Vf, name="hf2")
StCf <- mxAlgebra( expression=Cf/Vf, name="cf2")
StEf <- mxAlgebra( expression=Ef/Vf, name="ef2")
# Constraint on total variance of Ordinal variable (A+C+E=1)
varLM <- mxConstraint( expression=Vm[1,1]==1, name="VarLM" )
varLF <- mxConstraint( expression=Vf[1,1]==1, name="VarLF" )
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZM <- mxAlgebra( expression= rbind ( cbind(Am+Cm+Em, Am+Cm),
cbind(Am+Cm, Am+Cm+Em)) , name="expCovMZM")
covMZF <- mxAlgebra( expression= rbind ( cbind(Af+Cf+Ef, Af+Cf),
cbind(Af+Cf, Af+Cf+Ef)) , name="expCovMZF")
covDZM <- mxAlgebra( expression= rbind ( cbind(Am+Cm+Em, 0.5%x%Am+Cm),
cbind(0.5%x%Am+Cm, Am+Cm+Em)) , name="expCovDZM")
covDZF <- mxAlgebra( expression= rbind ( cbind(Af+Cf+Ef, 0.5%x%Af+Cf),
cbind(0.5%x%Af+Cf, Af+Cf+Ef)) , name="expCovDZF")
covDOS <- mxAlgebra( expression= rbind ( cbind(Am+Cm+Em, am%*%Rao%*%t(af) + cm%*%Rco%*%t(cf) ),
cbind(af%*%t(Rao)%*%t(am) + cf%*%t(Rco)%*%t(cm), Af+Cf+Ef) ) , name="expCovDOS")
# Data objects for Multiple Groups
dataMZM <- mxData( observed=mzmData, type="raw" )
dataDZM <- mxData( observed=dzmData, type="raw" )
dataMZF <- mxData( observed=mzfData, type="raw" )
dataDZF <- mxData( observed=dzfData, type="raw" )
dataDOS <- mxData( observed=dzoData, type="raw" )
# Objective objects for Multiple Groups
objmzm <- mxExpectationNormal( covariance="expCovMZM", means="expM", dimnames=selVars, thresholds="expThresm", threshnames=c("SSH1","SSH2") )
objdzm <- mxExpectationNormal( covariance="expCovDZM", means="expM", dimnames=selVars, thresholds="expThresm", threshnames=c("SSH1","SSH2") )
objmzf <- mxExpectationNormal( covariance="expCovMZF", means="expM", dimnames=selVars, thresholds="expThresf", threshnames=c("SSH1","SSH2") )
objdzf <- mxExpectationNormal( covariance="expCovDZF", means="expM", dimnames=selVars, thresholds="expThresf", threshnames=c("SSH1","SSH2") )
objdzo <- mxExpectationNormal( covariance="expCovDOS", means="expM", dimnames=selVars, thresholds="expThresmf", threshnames=c("SSH1","SSH2") )
fitFunction <- mxFitFunctionML()
# Combine Groups
parsm <- list( Obs1, Obs2, Mean, Betam, pathAm, pathCm, pathEm, covAm, covCm, covEm, covM, StAm, StCm, StEm, fitFunction )
parsf <- list( Obs1, Obs2, Mean, Betaf, pathAf, pathCf, pathEf, covAf, covCf, covEf, covF, StAf, StCf, StEf, fitFunction )
modelMZM <- mxModel(parsm, TrM, ThresM, covMZM, dataMZM, objmzm, varLM, name="MZM")
modelDZM <- mxModel(parsm, TrM, ThresM, covDZM, dataDZM, objdzm, name="DZM")
modelMZF <- mxModel(parsf, TrF, ThresF, covMZF, dataMZF, objmzf, varLF, name="MZF")
modelDZF <- mxModel(parsf, TrF, ThresF, covDZF, dataDZF, objdzf, name="DZF")
modelDOS <- mxModel(parsm, parsf, TrM, TrF, ThresMF,
rAmf, rCmf, covDOS, dataDOS, objdzo, name="DOS")
minus2ll <- mxAlgebra(expression=MZM.objective + DZM.objective + MZF.objective + DZF.objective + DOS.objective, name="m2LL")
obj <- mxFitFunctionAlgebra("m2LL")
ciM <- mxCI (c ('MZM.hm2', 'MZM.cm2', 'MZM.em2' ) ) # h2, c2, e2 males
ciF <- mxCI (c ('MZF.hf2', 'MZF.cf2', 'MZF.ef2' ) ) # h2, c2, e2 females
HetACEModel <-mxModel('HetACE', modelMZM, modelDZM, modelMZF, modelDZF, modelDOS, minus2ll, obj, ciM, ciF)
# RUN univariate ACE Model
HetACEFit <- mxTryHardOrdinal(HetACEModel, intervals=T)
Results for heterogeneity model for sex in SSH:
HetACESumm <- summary(HetACEFit, verbose=T)
HetACESumm$CI
## lbound estimate ubound note
## MZM.hm2[1,1] NA 0.500921211 0.6167271 !!!
## MZM.cm2[1,1] NA 0.005371819 0.3730496 !!!
## MZM.em2[1,1] 3.790635e-01 0.493706970 0.6260728
## MZF.hf2[1,1] 1.654440e-01 0.413755539 0.6126553
## MZF.cf2[1,1] 2.131622e-34 0.142030974 NA !!!
## MZF.ef2[1,1] 3.748761e-01 0.444213487 0.5225311
HetACESumm$CIdetail[,1:3]
## parameter side value
## 1 MZM.hm2[1,1] lower 3.861800e-05
## 2 MZM.hm2[1,1] upper 6.167271e-01
## 3 MZM.cm2[1,1] lower 1.779879e-30
## 4 MZM.cm2[1,1] upper 3.730496e-01
## 5 MZM.em2[1,1] lower 3.790635e-01
## 6 MZM.em2[1,1] upper 6.260728e-01
## 7 MZF.hf2[1,1] lower 1.654440e-01
## 8 MZF.hf2[1,1] upper 6.126553e-01
## 9 MZF.cf2[1,1] lower 2.131622e-34
## 10 MZF.cf2[1,1] upper 5.665264e-01
## 11 MZF.ef2[1,1] lower 3.748761e-01
## 12 MZF.ef2[1,1] upper 5.225311e-01
Script for homogeneity model for sex in SSH:
# MODEL 3: univ HOMOGENEITY MODEL
# NO Quantitative dif AND NO Qualitative sex Diff
# There is one set of A,C,E parameters and one set of A,C,E correlations across gender
# From the heterogeneity model (model 3), we simply use the same 'labeling' to equate male and female A, C and E paths
HomACEModel <- mxModel(HetACEFit, name="HomACE")
HomACEModel <-omxSetParameters(HomACEModel, labels=c("af11", "cf11", "ef11"), free=T, newlabels=c("am11", "cm11", "em11"), values=c(.50, .01, .49))
HomACEModel <- omxAssignFirstParameters(HomACEModel)
HomACEFit <- mxTryHardOrdinal(HomACEModel, intervals=T)
Results for homogeneity model for sex in SSH:
HomACESumm <- summary(HomACEFit,verbose=T)
HomACESumm$CI
## lbound estimate ubound note
## MZM.hm2[1,1] 0.2170751 4.906305e-01 0.5765491
## MZM.cm2[1,1] NA 6.271857e-10 0.2122188 !!!
## MZM.em2[1,1] 0.4234444 5.093695e-01 0.6038119
## MZF.hf2[1,1] 0.2170752 4.906305e-01 0.5765491
## MZF.cf2[1,1] NA 6.271857e-10 0.2122188 !!!
## MZF.ef2[1,1] 0.4234444 5.093695e-01 0.6038119
HomACESumm$CIdetail[,1:3]
## parameter side value
## 1 MZM.hm2[1,1] lower 2.170751e-01
## 2 MZM.hm2[1,1] upper 5.765491e-01
## 3 MZM.cm2[1,1] lower 1.281004e-25
## 4 MZM.cm2[1,1] upper 2.122188e-01
## 5 MZM.em2[1,1] lower 4.234444e-01
## 6 MZM.em2[1,1] upper 6.038119e-01
## 7 MZF.hf2[1,1] lower 2.170752e-01
## 8 MZF.hf2[1,1] upper 5.765491e-01
## 9 MZF.cf2[1,1] lower 1.281004e-25
## 10 MZF.cf2[1,1] upper 2.122188e-01
## 11 MZF.ef2[1,1] lower 4.234444e-01
## 12 MZF.ef2[1,1] upper 6.038119e-01
Is the homogeneity model a good fit compared to the heterogeneity model for SSH?
mxCompare(HetACEFit, HomACEFit)
## base comparison ep minus2LL df AIC diffLL diffdf p
## 1 HetACE <NA> 16 7829.442 9049 -10268.56 NA NA NA
## 2 HetACE HomACE 13 7837.305 9052 -10266.69 7.863871 3 0.04891047
#The answer is yes, since the p-value is marginally significant, and is 0.05 if rounded off to 2 decimal places.
In total, we fit 24 trivariate models out of 19 mental health measures. The models were run and results were saved in RData format. Scripts used to run each model with a different mental health measure are as follow:
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
str(self_harm_data);class(self_harm_data)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,pcbhaqt1,pcbhaqt2,x3zygos,u1cage1,u1cage2,pcbhage1,pcbhage2, sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
self_harm_data_c <- mutate(self_harm_data_c, age_161 = ifelse(is.na(pcbhage1),pcbhage2 , pcbhage1))
self_harm_data_c <- mutate(self_harm_data_c, age_162 = ifelse(is.na(pcbhage2),pcbhage1 , pcbhage2))
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$SSH1)
table(self_harm_data_c$SSH2)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
str(self_harm_data_c)
#******************************************************
# Regress out age, sex and transform cAUT variable
#******************************************************
#**Regressing out age & sex **#
self_harm_data_c$rescAUT1 <- residuals(lm(self_harm_data_c$pcbhaqt1 ~ self_harm_data_c$age_161 + self_harm_data_c$sex1, na.action="na.exclude"))
self_harm_data_c$rescAUT2 <- residuals(lm(self_harm_data_c$pcbhaqt2 ~ self_harm_data_c$age_162 + self_harm_data_c$sex2, na.action="na.exclude"))
hist(self_harm_data_c$pcbhaqt1)
hist(self_harm_data_c$rescAUT1)
describe(self_harm_data_c$rescAUT1)
# #transform the data to get a normal distribution
self_harm_data_c$trans_rescAUT1 <-sqrt(self_harm_data_c$rescAUT1+16)*2
self_harm_data_c$trans_rescAUT2 <-sqrt(self_harm_data_c$rescAUT2+16)*2
hist(self_harm_data_c$rescAUT1)
hist(self_harm_data_c$trans_rescAUT1)
describe(self_harm_data_c$trans_rescAUT1)
library(polycor) #check phenotypic correlation
hetcor(self_harm_data_c$trans_rescAUT1, self_harm_data_c$NSSH1)$correlations #0.20
hetcor(self_harm_data_c$pcbhaqt1, self_harm_data_c$NSSH1)$correlations #without covariates, 0.20
hetcor(self_harm_data_c$SSH1, self_harm_data_c$NSSH1)$correlations # 0.87, same as in other less complex models.
vars <-c('cAUT','NSSH', 'SSH')
selVars <-c('trans_rescAUT1', 'NSSH1', 'SSH1', 'trans_rescAUT2', 'NSSH2', 'SSH2')
useVars <-c('trans_rescAUT1', 'NSSH1', 'SSH1', 'trans_rescAUT2', 'NSSH2', 'SSH2', 'age1', 'age2', 'sex1','sex2')
# Select Data for Analysis
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars)
describe(mzData)
describe(dzData)
nv <- 3 # number of variables per twin
nvo <-2 #number of ordinal variables per twin
nvc <-nv-nvo #number of continuous variables per twin
poso <- nvc+1 #position where ordinal variables start
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
nlower <- ntv*(ntv+1)/2 # number of free elements in a lower matrix ntv*ntv
ncor <-(nv*(nv+1)/2)-nv # number of free elements in a correlation matrix nv*nv
ninc <- nth-1 #number of max increments
ncovariates <- 2 #number of covariates
# 2) Specify ACE Model, with ONE overall set of Means, ONE overall Threshold on IQ liability
# To create Labels for Lower Triangular Matrices
StTH <-c(-0.32,0.45,0.19,0.15,0.70,0.54,0.24,0.15)
aLabs <- paste("a", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
cLabs <- paste("c", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
eLabs <- paste("e", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13','Tmz_21','imz_21','imz_22','imz_23') # THs for var 1 and 2 for a
LabCovA <-c('BageThNSSH', 'BageThNSSH','BageThNSSH', 'BageThNSSH', 'BageThSSH', 'BageThSSH','BageThSSH', 'BageThSSH')
LabCovS <-c('BsexThNSSH', 'BsexThNSSH','BsexThNSSH', 'BsexThNSSH', 'BsexThSSH', 'BsexThSSH','BsexThSSH', 'BsexThSSH')
# Matrices to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.64,0.25,0.14,0.72,0.62,0.23), labels=aLabs, name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.30,0.15,0.19,0.01,0.01,0.01), labels=cLabs, name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.84,0.03,0.12,0.67,0.50,0.42), labels=eLabs, name="e" )
# # Define definition variables to hold the Covariates
obsAge1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Age1")
obsAge2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Age2")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#effect of age and sex on ordinal variable
betaA <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovA, name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovS, name="BsexTH" )
#mean and thresholds
Mean <-mxMatrix( "Full", 1, ntv, free=c(T,F,F,T,F,F), values=StMZmean, labels=c("m1", NA,NA, "m1", NA,NA), name="ExpMean" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=StTH, lbound=c(-4,0.001,0.001,0.001), ubound=c(4,4),
labels=LabThMZ, name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH%x%Age1 + BsexTH%x%Sex1,
Low%*%Th + BageTH%x%Age2 + BsexTH%x%Sex2),
name="ExpThres")
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
# Algebra to compute standardized variance components
covP <- mxAlgebra( expression=A+C+E, name="V" )
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Constraint on total variance of Ordinal variable (A+C+E=1)
varL1 <- mxConstraint( expression=V[2,2]==1, name="L1" )
varL2 <- mxConstraint( expression=V[3,3]==1, name="L2" )
# Algebra to compute Rph-A, Rph-C & Rph-E between cAUT-NSSH
rphace_cAUT_NSSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE_cAUT_NSSH" )
rphace_cAUT_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[3,1]*sqrt(h2[3,3])),
(sqrt(c2[1,1])*Rc[3,1]*sqrt(c2[3,3])),
(sqrt(e2[1,1])*Re[3,1]*sqrt(e2[3,3])) ), name="RphACE_cAUT_SSH" )
rphace_NSSH_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[2,2])*Ra[3,2]*sqrt(h2[3,3])),
(sqrt(c2[2,2])*Rc[3,2]*sqrt(c2[3,3])),
(sqrt(e2[2,2])*Re[3,2]*sqrt(e2[3,3])) ), name="RphACE_NSSH_SSH" )
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[2,2], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[3,3], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[2,2], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[3,3], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[2,2], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[3,3], name="SSH_e")
#rA
raNSSHcAUT<-mxAlgebra(expression=Ra[2,1], name="rA_NSSH_cAUT")
raSSHcAUT<-mxAlgebra(expression=Ra[3,1], name="rA_SSH_cAUT")
#rC
rcNSSHcAUT<-mxAlgebra(expression=Rc[2,1], name="rC_NSSH_cAUT")
rcSSHcAUT<-mxAlgebra(expression=Rc[3,1], name="rC_SSH_cAUT")
#rE
reNSSHcAUT<-mxAlgebra(expression=Re[2,1], name="rE_NSSH_cAUT")
reSSHcAUT<-mxAlgebra(expression=Re[3,1], name="rE_SSH_cAUT")
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="ExpCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, StA, StC, StE, matI, rph, rA, rC, rE,
rphace_cAUT_NSSH,rphace_cAUT_SSH,rphace_NSSH_SSH,
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2,
raNSSHcAUT,raSSHcAUT,rcNSSHcAUT,rcSSHcAUT,reNSSHcAUT,reSSHcAUT)
modelMZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covMZ, dataMZ, objMZ, fitFunction, varL1, varL2, name="MZ" )
modelDZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
#confidence intervals
Conf1 <- mxCI (c('Rph[2,1]','Rph[3,1]'))
Conf2 <- mxCI ('Ra[2,1]')
Conf3 <- mxCI ('Ra[3,1]')
Conf4 <- mxCI ('Rc[2,1]')
Conf5 <- mxCI ('Rc[3,1]')
Conf6 <- mxCI ('Re[2,1]')
Conf7 <- mxCI ('Re[3,1]')
AceModel1 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf1) #
AceModel2 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf2) #
AceModel3 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf3) #
AceModel4 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf4) #
AceModel5 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf5) #
AceModel6 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf6) #
AceModel7 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf7) #
# 3) RUN AceModel
AceFit1 <- mxTryHardOrdinal(AceModel1, intervals=T) #best fit -2lnL should be 40393.31
AceFit2 <- mxTryHardOrdinal(AceModel2, intervals=T) #best fit -2lnL should be 40393.31
AceFit3 <- mxTryHardOrdinal(AceModel3, intervals=T) #best fit -2lnL should be 40393.31
AceFit4 <- mxTryHardOrdinal(AceModel4, intervals=T) #best fit -2lnL should be 40393.31
AceFit5 <- mxTryHardOrdinal(AceModel5, intervals=T) #best fit -2lnL should be 40393.31
AceFit6 <- mxTryHardOrdinal(AceModel6, intervals=T) #best fit -2lnL should be 40393.31
AceFit7 <- mxTryHardOrdinal(AceModel7, intervals=T) #best fit -2lnL should be 40393.31
(AceSum1 <- summary(AceFit1,verbose=T))
(AceSum2 <- summary(AceFit2,verbose=T))
(AceSum3 <- summary(AceFit3,verbose=T))
(AceSum4 <- summary(AceFit4,verbose=T))
(AceSum5 <- summary(AceFit5,verbose=T))
(AceSum6 <- summary(AceFit6,verbose=T))
(AceSum7 <- summary(AceFit7,verbose=T))
#get the estimates and CIs
CI1 <- AceSum1$CI
CI2 <- AceSum2$CI
CI3 <- AceSum3$CI
CI4 <- AceSum4$CI
CI5 <- AceSum5$CI
CI6 <- AceSum6$CI
CI7 <- AceSum7$CI
tot_CI<-rbind(CI1,CI2,CI3,CI4,CI5,CI6,CI7)
#evaluate the contents
mxEval(MZ.ExpCovMZ, AceFit1)
mxEval(DZ.ExpCovDZ, AceFit1)
mxEval(ACE.h2, AceFit1)
mxEval(ACE.c2, AceFit1)
mxEval(ACE.e2, AceFit1)
mxEval(ACE.Ra, AceFit1)
mxEval(ACE.Rc, AceFit1)
mxEval(ACE.Re, AceFit1)
mxEval(ACE.Rph, AceFit1)
mxEval(ACE.RphACE_cAUT_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1]*100
mxEval(ACE.RphACE_cAUT_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1]*100
mxEval(ACE.V,AceFit1)
#get the proportion explained by A,C and E in the phenotypic correlation
proportion<-as.data.frame(rbind((mxEval(ACE.RphACE_cAUT_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1])*100,
(mxEval(ACE.RphACE_cAUT_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1])*100,
mxEval(ACE.RphACE_cAUT_NSSH, AceFit1),
mxEval(ACE.RphACE_cAUT_SSH, AceFit1)),
row.names=c("NSSH%","SSH%", "NSSH","SSH"))
colnames(proportion)<-c("A","C","E")
proportion
#constrain the model
Sub1Model <- mxModel(AceModel1, name="sub1",
mxConstraint(MZ.rA_NSSH_cAUT==MZ.rA_SSH_cAUT, name="rA_con"),
mxConstraint(MZ.rC_NSSH_cAUT==MZ.rC_SSH_cAUT, name="rC_con"),
mxConstraint(MZ.rE_NSSH_cAUT==MZ.rE_SSH_cAUT, name="rE_con"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = F)
(Sub1Sum <- summary(Sub1Fit))
mxEval(MZ.NSSH_a,Sub1Fit);mxEval(MZ.SSH_a,Sub1Fit)
mxEval(MZ.NSSH_c,Sub1Fit);mxEval(MZ.SSH_c,Sub1Fit)
mxEval(MZ.NSSH_e,Sub1Fit);mxEval(MZ.SSH_e,Sub1Fit)
mxEval(MZ.path_a,Sub1Fit);mxEval(MZ.path_c,Sub1Fit);mxEval(MZ.path_e,Sub1Fit)
mxEval(MZ.Ra,Sub1Fit);mxEval(MZ.Rc,Sub1Fit);mxEval(MZ.Re,Sub1Fit)
mxEval(MZ.h2,Sub1Fit)
### compare with ACE model
comparison <- mxCompare(AceFit1,Sub1Fit)
## 6) save the results
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_cAUT_SLSQP_ACE_04_June_2020.RData")
# save the estimates and their confidence intervals
xlsx::write.xlsx(tot_CI, file="trivariate_estimates_with_CI_04_June_2020.xlsx",
sheetName="cAUT", append=TRUE)
# save the proportions
write.xlsx(proportion, file="trivariate_proportion_04_June_2020.xlsx",
sheetName="cAUT", append=TRUE)
# save the results of the chi-square test
write.xlsx(comparison, file="trivariate_constrained_results_04_June_2020.xlsx",
sheetName="cAUT", append=TRUE)
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
str(self_harm_data);class(self_harm_data)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,ppbhaqt1,ppbhaqt2,x3zygos,u1cage1,u1cage2,pcbhage1,pcbhage2, sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
self_harm_data_c <- mutate(self_harm_data_c, age_161 = ifelse(is.na(pcbhage1),pcbhage2 , pcbhage1))
self_harm_data_c <- mutate(self_harm_data_c, age_162 = ifelse(is.na(pcbhage2),pcbhage1 , pcbhage2))
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$SSH1)
table(self_harm_data_c$SSH2)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
str(self_harm_data_c)
#******************************************************
# Regress out age, sex and transform pAUT variable
#******************************************************
#**Regressing out age & sex **#
self_harm_data_c$respAUT1 <- residuals(lm(self_harm_data_c$ppbhaqt1 ~ self_harm_data_c$age_161 + self_harm_data_c$sex1, na.action="na.exclude"))
self_harm_data_c$respAUT2 <- residuals(lm(self_harm_data_c$ppbhaqt2 ~ self_harm_data_c$age_162 + self_harm_data_c$sex2, na.action="na.exclude"))
hist(self_harm_data_c$ppbhaqt1)
hist(self_harm_data_c$respAUT1)
describe(self_harm_data_c$respAUT1)
# #transform the data to get a normal distribution
self_harm_data_c$trans_respAUT1 <-sqrt(self_harm_data_c$respAUT1+36)*1.5
self_harm_data_c$trans_respAUT2 <-sqrt(self_harm_data_c$respAUT2+36)*1.5
hist(self_harm_data_c$respAUT1)
hist(self_harm_data_c$trans_respAUT1)
describe(self_harm_data_c$trans_respAUT1)
library(polycor) #check phenotypic correlation
hetcor(self_harm_data_c$trans_respAUT1, self_harm_data_c$NSSH1)$correlations #0.08
hetcor(self_harm_data_c$ppbhaqt1, self_harm_data_c$NSSH1)$correlations #without covariates, 0.05
hetcor(self_harm_data_c$SSH1, self_harm_data_c$NSSH1)$correlations # 0.87, same as in other less complex models.
vars <-c('pAUT','NSSH', 'SSH')
selVars <-c('trans_respAUT1', 'NSSH1', 'SSH1', 'trans_respAUT2', 'NSSH2', 'SSH2')
useVars <-c('trans_respAUT1', 'NSSH1', 'SSH1', 'trans_respAUT2', 'NSSH2', 'SSH2', 'age1', 'age2', 'sex1','sex2')
# Select Data for Analysis
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars)
describe(mzData)
describe(dzData)
nv <- 3 # number of variables per twin
nvo <-2 #number of ordinal variables per twin
nvc <-nv-nvo #number of continuous variables per twin
poso <- nvc+1 #position where ordinal variables start
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
nlower <- ntv*(ntv+1)/2 # number of free elements in a lower matrix ntv*ntv
ncor <-(nv*(nv+1)/2)-nv # number of free elements in a correlation matrix nv*nv
ninc <- nth-1 #number of max increments
ncovariates <- 2 #number of covariates
### Create starting values for covariance matrix
SHData_for_stv<-self_harm_data_c%>%
select('trans_respAUT1', 'NSSH1', 'SSH1', 'trans_respAUT2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(SHData_for_stv)
mzData_for_stv<-mzData%>%
select('trans_respAUT1', 'NSSH1', 'SSH1', 'trans_respAUT2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(mzData_for_stv)
dzData_for_stv<-dzData%>%
select('trans_respAUT1', 'NSSH1', 'SSH1', 'trans_respAUT2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(dzData_for_stv)
jiggle <-rnorm(nlower, mean = 0, sd = .1)
MZmean <-colMeans(mzData_for_stv,na.rm=TRUE)
DZmean <-colMeans(dzData_for_stv,na.rm=TRUE)
StMZmean<- c(mean(MZmean[c(1,4)]),0,0,mean(MZmean[c(1,4)]),0,0)
StDZmean<- c(mean(DZmean[c(1,4)]),0,0,mean(DZmean[c(1,4)]),0,0)
Stsd <-mean(sapply(mzData_for_stv[,c(1,4)],sd, na.rm=TRUE))
StWithinperson <-vechs(cor(SHData_for_stv[,1:3],use="pairwise"))
StBetweenMZ <-vech(cor(mzData_for_stv[,1:3],mzData_for_stv[,4:6],use="pairwise"))
StBetweenDZ <-vech(cor(dzData_for_stv[,1:3],dzData_for_stv[,4:6],use="pairwise"))
str(self_harm_data_c)
# 2) Specify ACE Model, with ONE overall set of Means, ONE overall Threshold on IQ liability
# To create Labels for Lower Triangular Matrices
StTH <-c(-0.32,0.45,0.19,0.15,0.70,0.54,0.24,0.15)
aLabs <- paste("a", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
cLabs <- paste("c", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
eLabs <- paste("e", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13','Tmz_21','imz_21','imz_22','imz_23') # THs for var 1 and 2 for a
LabCovA <-c('BageThNSSH', 'BageThNSSH','BageThNSSH', 'BageThNSSH', 'BageThSSH', 'BageThSSH','BageThSSH', 'BageThSSH')
LabCovS <-c('BsexThNSSH', 'BsexThNSSH','BsexThNSSH', 'BsexThNSSH', 'BsexThSSH', 'BsexThSSH','BsexThSSH', 'BsexThSSH')
# Matrices to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.64,0.25,0.14,0.72,0.62,0.23), labels=aLabs, name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.30,0.15,0.19,0.01,0.01,0.01), labels=cLabs, name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.84,0.03,0.12,0.67,0.50,0.42), labels=eLabs, name="e" )
# # Define definition variables to hold the Covariates
obsAge1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Age1")
obsAge2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Age2")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#effect of age and sex on ordinal variable
betaA <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovA, name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovS, name="BsexTH" )
#mean and thresholds
Mean <-mxMatrix( "Full", 1, ntv, free=c(T,F,F,T,F,F), values=StMZmean, labels=c("m1", NA,NA, "m1", NA,NA), name="ExpMean" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=StTH, lbound=c(-4,0.001,0.001,0.001), ubound=c(4,4),
labels=LabThMZ, name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH%x%Age1 + BsexTH%x%Sex1,
Low%*%Th + BageTH%x%Age2 + BsexTH%x%Sex2),
name="ExpThres")
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
# Algebra to compute standardized variance components
covP <- mxAlgebra( expression=A+C+E, name="V" )
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Constraint on total variance of Ordinal variable (A+C+E=1)
varL1 <- mxConstraint( expression=V[2,2]==1, name="L1" )
varL2 <- mxConstraint( expression=V[3,3]==1, name="L2" )
# Algebra to compute Rph-A, Rph-C & Rph-E between pAUT-NSSH
rphace_pAUT_NSSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE_pAUT_NSSH" )
rphace_pAUT_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[3,1]*sqrt(h2[3,3])),
(sqrt(c2[1,1])*Rc[3,1]*sqrt(c2[3,3])),
(sqrt(e2[1,1])*Re[3,1]*sqrt(e2[3,3])) ), name="RphACE_pAUT_SSH" )
rphace_NSSH_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[2,2])*Ra[3,2]*sqrt(h2[3,3])),
(sqrt(c2[2,2])*Rc[3,2]*sqrt(c2[3,3])),
(sqrt(e2[2,2])*Re[3,2]*sqrt(e2[3,3])) ), name="RphACE_NSSH_SSH" )
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[2,2], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[3,3], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[2,2], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[3,3], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[2,2], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[3,3], name="SSH_e")
#rA
raNSSHpAUT<-mxAlgebra(expression=Ra[2,1], name="rA_NSSH_pAUT")
raSSHpAUT<-mxAlgebra(expression=Ra[3,1], name="rA_SSH_pAUT")
#rC
rcNSSHpAUT<-mxAlgebra(expression=Rc[2,1], name="rC_NSSH_pAUT")
rcSSHpAUT<-mxAlgebra(expression=Rc[3,1], name="rC_SSH_pAUT")
#rE
reNSSHpAUT<-mxAlgebra(expression=Re[2,1], name="rE_NSSH_pAUT")
reSSHpAUT<-mxAlgebra(expression=Re[3,1], name="rE_SSH_pAUT")
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="ExpCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, StA, StC, StE, matI, rph, rA, rC, rE,
rphace_pAUT_NSSH,rphace_pAUT_SSH,rphace_NSSH_SSH,
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2,
raNSSHpAUT,raSSHpAUT,rcNSSHpAUT,rcSSHpAUT,reNSSHpAUT,reSSHpAUT)
modelMZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covMZ, dataMZ, objMZ, fitFunction, varL1, varL2, name="MZ" )
modelDZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
#confidence intervals
Conf1 <- mxCI (c('Rph[2,1]','Rph[3,1]'))
Conf2 <- mxCI ('Ra[2,1]')
Conf3 <- mxCI ('Ra[3,1]')
Conf4 <- mxCI ('Rc[2,1]')
Conf5 <- mxCI ('Rc[3,1]')
Conf6 <- mxCI ('Re[2,1]')
Conf7 <- mxCI ('Re[3,1]')
AceModel1 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf1) #
AceModel2 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf2) #
AceModel3 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf3) #
AceModel4 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf4) #
AceModel5 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf5) #
AceModel6 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf6) #
AceModel7 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf7) #
# ------------------------------------------------------------------------------
# 3) RUN AceModel
AceFit1 <- mxTryHardOrdinal(AceModel1, intervals=T) #best fit -2lnL should be 40393.31
AceFit2 <- mxTryHardOrdinal(AceModel2, intervals=T) #best fit -2lnL should be 40393.31
AceFit3 <- mxTryHardOrdinal(AceModel3, intervals=T) #best fit -2lnL should be 40393.31
AceFit4 <- mxTryHardOrdinal(AceModel4, intervals=T) #best fit -2lnL should be 40393.31
AceFit5 <- mxTryHardOrdinal(AceModel5, intervals=T) #best fit -2lnL should be 40393.31
AceFit6 <- mxTryHardOrdinal(AceModel6, intervals=T) #best fit -2lnL should be 40393.31
AceFit7 <- mxTryHardOrdinal(AceModel7, intervals=T) #best fit -2lnL should be 40393.31
(AceSum1 <- summary(AceFit1,verbose=T))
(AceSum2 <- summary(AceFit2,verbose=T))
(AceSum3 <- summary(AceFit3,verbose=T))
(AceSum4 <- summary(AceFit4,verbose=T))
(AceSum5 <- summary(AceFit5,verbose=T))
(AceSum6 <- summary(AceFit6,verbose=T))
(AceSum7 <- summary(AceFit7,verbose=T))
#get the estimates and CIs
CI1 <- AceSum1$CI
CI2 <- AceSum2$CI
CI3 <- AceSum3$CI
CI4 <- AceSum4$CI
CI5 <- AceSum5$CI
CI6 <- AceSum6$CI
CI7 <- AceSum7$CI
tot_CI<-rbind(CI1,CI2,CI3,CI4,CI5,CI6,CI7)
#evaluate the contents
mxEval(MZ.ExpCovMZ, AceFit1)
mxEval(DZ.ExpCovDZ, AceFit1)
mxEval(ACE.h2, AceFit1)
mxEval(ACE.c2, AceFit1)
mxEval(ACE.e2, AceFit1)
mxEval(ACE.Ra, AceFit1)
mxEval(ACE.Rc, AceFit1)
mxEval(ACE.Re, AceFit1)
mxEval(ACE.Rph, AceFit1)
mxEval(ACE.RphACE_pAUT_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1]*100
mxEval(ACE.RphACE_pAUT_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1]*100
mxEval(ACE.V,AceFit1)
#get the proportion explained by A,C and E in the phenotypic correlation
proportion<-as.data.frame(rbind((mxEval(ACE.RphACE_pAUT_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1])*100,
(mxEval(ACE.RphACE_pAUT_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1])*100,
mxEval(ACE.RphACE_pAUT_NSSH, AceFit1),
mxEval(ACE.RphACE_pAUT_SSH, AceFit1)),
row.names=c("NSSH%","SSH%", "NSSH","SSH"))
colnames(proportion)<-c("A","C","E")
proportion
#constrain the model
Sub1Model <- mxModel(AceModel1, name="sub1",
mxConstraint(MZ.rA_NSSH_pAUT==MZ.rA_SSH_pAUT, name="rA_con"),
mxConstraint(MZ.rC_NSSH_pAUT==MZ.rC_SSH_pAUT, name="rC_con"),
mxConstraint(MZ.rE_NSSH_pAUT==MZ.rE_SSH_pAUT, name="rE_con"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = F)
(Sub1Sum <- summary(Sub1Fit))
mxEval(MZ.NSSH_a,Sub1Fit);mxEval(MZ.SSH_a,Sub1Fit)
mxEval(MZ.NSSH_c,Sub1Fit);mxEval(MZ.SSH_c,Sub1Fit)
mxEval(MZ.NSSH_e,Sub1Fit);mxEval(MZ.SSH_e,Sub1Fit)
mxEval(MZ.path_a,Sub1Fit);mxEval(MZ.path_c,Sub1Fit);mxEval(MZ.path_e,Sub1Fit)
mxEval(MZ.Ra,Sub1Fit);mxEval(MZ.Rc,Sub1Fit);mxEval(MZ.Re,Sub1Fit)
mxEval(MZ.h2,Sub1Fit)
### compare with ACE model
comparison <- mxCompare(AceFit1,Sub1Fit)
# COMPARE MODELS: Print Comparative Fit Statistics
library(xlsx)
## 6) save the results
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_pAUT_SLSQP_ACE_04_June_2020.RData")
# save the estimates and their confidence intervals
write.xlsx(tot_CI, file="trivariate_estimates_with_CI_04_June_2020.xlsx",
sheetName="pAUT", append=TRUE)
# save the proportions
write.xlsx(proportion, file="trivariate_proportion_04_June_2020.xlsx",
sheetName="pAUT", append=TRUE)
# save the results of the chi-square test
write.xlsx(comparison, file="trivariate_constrained_results_04_June_2020.xlsx",
sheetName="pAUT", append=TRUE)
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
str(self_harm_data);class(self_harm_data)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,pcbhsdqbeht1,pcbhsdqbeht2,x3zygos,u1cage1,u1cage2,pcbhage1,pcbhage2, sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
self_harm_data_c <- mutate(self_harm_data_c, age_161 = ifelse(is.na(pcbhage1),pcbhage2 , pcbhage1))
self_harm_data_c <- mutate(self_harm_data_c, age_162 = ifelse(is.na(pcbhage2),pcbhage1 , pcbhage2))
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$SSH1)
table(self_harm_data_c$SSH2)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
str(self_harm_data_c)
#******************************************************
# Regress out age, sex and transform cSDQ variable
#******************************************************
#**Regressing out age & sex **#
self_harm_data_c$rescSDQ1 <- residuals(lm(self_harm_data_c$pcbhsdqbeht1 ~ self_harm_data_c$age_161 + self_harm_data_c$sex1, na.action="na.exclude"))
self_harm_data_c$rescSDQ2 <- residuals(lm(self_harm_data_c$pcbhsdqbeht2 ~ self_harm_data_c$age_162 + self_harm_data_c$sex2, na.action="na.exclude"))
hist(self_harm_data_c$rescSDQ1)
hist(self_harm_data_c$rescSDQ2)
describe(self_harm_data_c$rescSDQ1)
# #transform the data to get a normal distribution
self_harm_data_c$trans_rescSDQ1 <-sqrt(self_harm_data_c$rescSDQ1+12)*2
self_harm_data_c$trans_rescSDQ2 <-sqrt(self_harm_data_c$rescSDQ2+12)*2
hist(self_harm_data_c$rescSDQ1)
hist(self_harm_data_c$trans_rescSDQ1)
describe(self_harm_data_c$trans_rescSDQ1)
library(polycor) #check phenotypic correlation
hetcor(self_harm_data_c$trans_rescSDQ1, self_harm_data_c$NSSH1)$correlations #0.36
hetcor(self_harm_data_c$pcbhsdqbeht1, self_harm_data_c$NSSH1)$correlations #without covariates, 0.36
hetcor(self_harm_data_c$SSH1, self_harm_data_c$NSSH1)$correlations # 0.87, same as in other less complex models.
vars <-c('cSDQ','NSSH', 'SSH')
selVars <-c('trans_rescSDQ1', 'NSSH1', 'SSH1', 'trans_rescSDQ2', 'NSSH2', 'SSH2')
useVars <-c('trans_rescSDQ1', 'NSSH1', 'SSH1', 'trans_rescSDQ2', 'NSSH2', 'SSH2', 'age1', 'age2', 'sex1','sex2')
# Select Data for Analysis
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars)
describe(mzData)
describe(dzData)
nv <- 3 # number of variables per twin
nvo <-2 #number of ordinal variables per twin
nvc <-nv-nvo #number of continuous variables per twin
poso <- nvc+1 #position where ordinal variables start
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
nlower <- ntv*(ntv+1)/2 # number of free elements in a lower matrix ntv*ntv
ncor <-(nv*(nv+1)/2)-nv # number of free elements in a correlation matrix nv*nv
ninc <- nth-1 #number of max increments
ncovariates <- 2 #number of covariates
### Create starting values for covariance matrix
SHData_for_stv<-self_harm_data_c%>%
select('trans_rescSDQ1', 'NSSH1', 'SSH1', 'trans_rescSDQ2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(SHData_for_stv)
mzData_for_stv<-mzData%>%
select('trans_rescSDQ1', 'NSSH1', 'SSH1', 'trans_rescSDQ2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(mzData_for_stv)
dzData_for_stv<-dzData%>%
select('trans_rescSDQ1', 'NSSH1', 'SSH1', 'trans_rescSDQ2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(dzData_for_stv)
jiggle <-rnorm(nlower, mean = 0, sd = .1)
MZmean <-colMeans(mzData_for_stv,na.rm=TRUE)
DZmean <-colMeans(dzData_for_stv,na.rm=TRUE)
StMZmean<- c(mean(MZmean[c(1,4)]),0,0,mean(MZmean[c(1,4)]),0,0)
StDZmean<- c(mean(DZmean[c(1,4)]),0,0,mean(DZmean[c(1,4)]),0,0)
Stsd <-mean(sapply(mzData_for_stv[,c(1,4)],sd, na.rm=TRUE))
StWithinperson <-vechs(cor(SHData_for_stv[,1:3],use="pairwise"))
StBetweenMZ <-vech(cor(mzData_for_stv[,1:3],mzData_for_stv[,4:6],use="pairwise"))
StBetweenDZ <-vech(cor(dzData_for_stv[,1:3],dzData_for_stv[,4:6],use="pairwise"))
str(self_harm_data_c)
# 2) Specify ACE Model, with ONE overall set of Means, ONE overall Threshold on IQ liability
# To create Labels for Lower Triangular Matrices
StTH <-c(-0.26,0.45,0.19,0.15,0.79,0.55,0.25,0.16)
aLabs <- paste("a", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
cLabs <- paste("c", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
eLabs <- paste("e", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
# Matrices to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(1.02,0.31,0.33,0.61,0.52,0.23), labels=aLabs, name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.30,0.25,0.22,0.01,0.01,0.01), labels=cLabs, name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(1.04,0.14,0.16,0.67,0.56,0.42), labels=eLabs, name="e" )
# # Define definition variables to hold the Covariates
obsAge1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Age1")
obsAge2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Age2")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#effect of age and sex on ordinal variable
betaA <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.02, labels=LabCovA, name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.40, labels=LabCovS, name="BsexTH" )
#mean and thresholds
Mean <-mxMatrix( "Full", 1, ntv, free=c(T,F,F,T,F,F), values=StMZmean, labels=c("m1", NA,NA, "m1", NA,NA), name="ExpMean" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=StTH, lbound=c(-4,-4), ubound=c(4,4),
labels=LabThMZ, name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH%x%Age1 + BsexTH%x%Sex1,
Low%*%Th + BageTH%x%Age2 + BsexTH%x%Sex2),
name="ExpThres")
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
# Algebra to compute standardized variance components
covP <- mxAlgebra( expression=A+C+E, name="V" )
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Constraint on total variance of Ordinal variable (A+C+E=1)
varL1 <- mxConstraint( expression=V[2,2]==1, name="L1" )
varL2 <- mxConstraint( expression=V[3,3]==1, name="L2" )
# Algebra to compute Rph-A, Rph-C & Rph-E between cSDQ-NSSH
rphace_cSDQ_NSSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE_cSDQ_NSSH" )
rphace_cSDQ_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[3,1]*sqrt(h2[3,3])),
(sqrt(c2[1,1])*Rc[3,1]*sqrt(c2[3,3])),
(sqrt(e2[1,1])*Re[3,1]*sqrt(e2[3,3])) ), name="RphACE_cSDQ_SSH" )
rphace_NSSH_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[2,2])*Ra[3,2]*sqrt(h2[3,3])),
(sqrt(c2[2,2])*Rc[3,2]*sqrt(c2[3,3])),
(sqrt(e2[2,2])*Re[3,2]*sqrt(e2[3,3])) ), name="RphACE_NSSH_SSH" )
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[2,2], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[3,3], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[2,2], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[3,3], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[2,2], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[3,3], name="SSH_e")
#rA
raNSSHcSDQ<-mxAlgebra(expression=Ra[2,1], name="rA_NSSH_cSDQ")
raSSHcSDQ<-mxAlgebra(expression=Ra[3,1], name="rA_SSH_cSDQ")
#rC
rcNSSHcSDQ<-mxAlgebra(expression=Rc[2,1], name="rC_NSSH_cSDQ")
rcSSHcSDQ<-mxAlgebra(expression=Rc[3,1], name="rC_SSH_cSDQ")
#rE
reNSSHcSDQ<-mxAlgebra(expression=Re[2,1], name="rE_NSSH_cSDQ")
reSSHcSDQ<-mxAlgebra(expression=Re[3,1], name="rE_SSH_cSDQ")
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="ExpCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, StA, StC, StE, matI, rph, rA, rC, rE,
rphace_cSDQ_NSSH,rphace_cSDQ_SSH,rphace_NSSH_SSH,
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2,
raNSSHcSDQ,raSSHcSDQ,rcNSSHcSDQ,rcSSHcSDQ,reNSSHcSDQ,reSSHcSDQ)
modelMZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covMZ, dataMZ, objMZ, fitFunction, varL1, varL2, name="MZ" )
modelDZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
#confidence intervals
Conf1 <- mxCI (c('Rph[2,1]','Rph[3,1]'))
Conf2 <- mxCI ('Ra[2,1]')
Conf3 <- mxCI ('Ra[3,1]')
Conf4 <- mxCI ('Rc[2,1]')
Conf5 <- mxCI ('Rc[3,1]')
Conf6 <- mxCI ('Re[2,1]')
Conf7 <- mxCI ('Re[3,1]')
AceModel1 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf1) #
AceModel2 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf2) #
AceModel3 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf3) #
AceModel4 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf4) #
AceModel5 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf5) #
AceModel6 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf6) #
AceModel7 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf7) #
# 3) RUN AceModel
AceFit1 <- mxTryHardOrdinal(AceModel1, intervals=T) #best fit -2lnL should be 40393.31
AceFit2 <- mxTryHardOrdinal(AceModel2, intervals=T) #best fit -2lnL should be 40393.31
AceFit3 <- mxTryHardOrdinal(AceModel3, intervals=T) #best fit -2lnL should be 40393.31
AceFit4 <- mxTryHardOrdinal(AceModel4, intervals=T) #best fit -2lnL should be 40393.31
AceFit5 <- mxTryHardOrdinal(AceModel5, intervals=T) #best fit -2lnL should be 40393.31
AceFit6 <- mxTryHardOrdinal(AceModel6, intervals=T) #best fit -2lnL should be 40393.31
AceFit7 <- mxTryHardOrdinal(AceModel7, intervals=T) #best fit -2lnL should be 40393.31
(AceSum1 <- summary(AceFit1,verbose=T))
(AceSum2 <- summary(AceFit2,verbose=T))
(AceSum3 <- summary(AceFit3,verbose=T))
(AceSum4 <- summary(AceFit4,verbose=T))
(AceSum5 <- summary(AceFit5,verbose=T))
(AceSum6 <- summary(AceFit6,verbose=T))
(AceSum7 <- summary(AceFit7,verbose=T))
#get the estimates and CIs
CI1 <- AceSum1$CI
CI2 <- AceSum2$CI
CI3 <- AceSum3$CI
CI4 <- AceSum4$CI
CI5 <- AceSum5$CI
CI6 <- AceSum6$CI
CI7 <- AceSum7$CI
tot_CI<-rbind(CI1,CI2,CI3,CI4,CI5,CI6,CI7)
#evaluate the contents
mxEval(MZ.ExpCovMZ, AceFit1)
mxEval(DZ.ExpCovDZ, AceFit1)
mxEval(ACE.h2, AceFit1)
mxEval(ACE.c2, AceFit1)
mxEval(ACE.e2, AceFit1)
mxEval(ACE.Ra, AceFit1)
mxEval(ACE.Rc, AceFit1)
mxEval(ACE.Re, AceFit1)
mxEval(ACE.Rph, AceFit1)
mxEval(ACE.RphACE_cSDQ_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1]*100
mxEval(ACE.RphACE_cSDQ_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1]*100
mxEval(ACE.V,AceFit1)
#get the proportion explained by A,C and E in the phenotypic correlation
proportion<-as.data.frame(rbind((mxEval(ACE.RphACE_cSDQ_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1])*100,
(mxEval(ACE.RphACE_cSDQ_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1])*100,
mxEval(ACE.RphACE_cSDQ_NSSH, AceFit1),
mxEval(ACE.RphACE_cSDQ_SSH, AceFit1)),
row.names=c("NSSH%","SSH%", "NSSH","SSH"))
colnames(proportion)<-c("A","C","E")
proportion
#constrain the model
Sub1Model <- mxModel(AceModel1, name="sub1",
mxConstraint(MZ.rA_NSSH_cSDQ==MZ.rA_SSH_cSDQ, name="rA_con"),
mxConstraint(MZ.rC_NSSH_cSDQ==MZ.rC_SSH_cSDQ, name="rC_con"),
mxConstraint(MZ.rE_NSSH_cSDQ==MZ.rE_SSH_cSDQ, name="rE_con"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = F)
(Sub1Sum <- summary(Sub1Fit))
mxEval(MZ.NSSH_a,Sub1Fit);mxEval(MZ.SSH_a,Sub1Fit)
mxEval(MZ.NSSH_c,Sub1Fit);mxEval(MZ.SSH_c,Sub1Fit)
mxEval(MZ.NSSH_e,Sub1Fit);mxEval(MZ.SSH_e,Sub1Fit)
mxEval(MZ.path_a,Sub1Fit);mxEval(MZ.path_c,Sub1Fit);mxEval(MZ.path_e,Sub1Fit)
mxEval(MZ.Ra,Sub1Fit);mxEval(MZ.Rc,Sub1Fit);mxEval(MZ.Re,Sub1Fit)
mxEval(MZ.h2,Sub1Fit)
### compare with ACE model
comparison <- mxCompare(AceFit1,Sub1Fit)
library(xlsx)
## 6) save the results
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_cSDQ_SLSQP_ACE_04_June_2020.RData")
# save the estimates and their confidence intervals
write.xlsx(tot_CI, file="trivariate_estimates_with_CI_04_June_2020.xlsx",
sheetName="cSDQ", append=TRUE)
# # Add a second data set in a new worksheet
# write.xlsx(mtcars, file="myworkbook.xlsx", sheetName="MTCARS",
# append=TRUE)
# save the proportions
write.xlsx(proportion, file="trivariate_proportion_04_June_2020.xlsx",
sheetName="cSDQ", append=TRUE)
# save the results of the chi-square test
write.xlsx(comparison, file="trivariate_constrained_results_04_June_2020.xlsx",
sheetName="cSDQ", append=TRUE)
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
str(self_harm_data);class(self_harm_data)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,ppbhsdqbeht1,ppbhsdqbeht2,x3zygos,u1cage1,u1cage2,pcbhage1,pcbhage2, sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
self_harm_data_c <- mutate(self_harm_data_c, age_161 = ifelse(is.na(pcbhage1),pcbhage2 , pcbhage1))
self_harm_data_c <- mutate(self_harm_data_c, age_162 = ifelse(is.na(pcbhage2),pcbhage1 , pcbhage2))
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$SSH1)
table(self_harm_data_c$SSH2)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
str(self_harm_data_c)
#******************************************************
# Regress out age, sex and transform SDQ variable
#******************************************************
#**Regressing out age & sex from anxiety (pgadtot)**#
self_harm_data_c$respSDQ1 <- residuals(lm(self_harm_data_c$ppbhsdqbeht1 ~ self_harm_data_c$age_161 + self_harm_data_c$sex1, na.action="na.exclude"))
self_harm_data_c$respSDQ2 <- residuals(lm(self_harm_data_c$ppbhsdqbeht2 ~ self_harm_data_c$age_162 + self_harm_data_c$sex2, na.action="na.exclude"))
hist(self_harm_data_c$respSDQ1)
hist(self_harm_data_c$respSDQ2)
describe(self_harm_data_c$respSDQ1)
# #transform the data to get a normal distribution
self_harm_data_c$trans_respSDQ1 <-log(self_harm_data_c$respSDQ1+6)*3
self_harm_data_c$trans_respSDQ2 <-log(self_harm_data_c$respSDQ2+6)*3
hist(self_harm_data_c$respSDQ1)
hist(self_harm_data_c$trans_respSDQ1)
describe(self_harm_data_c$trans_respSDQ1)
library(polycor) #check phenotypic correlation
hetcor(self_harm_data_c$trans_respSDQ1, self_harm_data_c$NSSH1)$correlations #0.16
hetcor(self_harm_data_c$ppbhsdqbeht1, self_harm_data_c$NSSH1)$correlations #without covariates, 0.1202
hetcor(self_harm_data_c$SSH1, self_harm_data_c$NSSH1)$correlations # 0.87, same as in other less complex models.
vars <-c('pSDQ','NSSH', 'SSH')
selVars <-c('trans_respSDQ1', 'NSSH1', 'SSH1', 'trans_respSDQ2', 'NSSH2', 'SSH2')
useVars <-c('trans_respSDQ1', 'NSSH1', 'SSH1', 'trans_respSDQ2', 'NSSH2', 'SSH2', 'age1', 'age2', 'sex1','sex2')
# Select Data for Analysis
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars)
describe(mzData)
describe(dzData)
nv <- 3 # number of variables per twin
nvo <-2 #number of ordinal variables per twin
nvc <-nv-nvo #number of continuous variables per twin
poso <- nvc+1 #position where ordinal variables start
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
nlower <- ntv*(ntv+1)/2 # number of free elements in a lower matrix ntv*ntv
ncor <-(nv*(nv+1)/2)-nv # number of free elements in a correlation matrix nv*nv
ninc <- nth-1 #number of max increments
ncovariates <- 2 #number of covariates
### Create starting values for covariance matrix
SHData_for_stv<-self_harm_data_c%>%
select('trans_respSDQ1', 'NSSH1', 'SSH1', 'trans_respSDQ2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(SHData_for_stv)
mzData_for_stv<-mzData%>%
select('trans_respSDQ1', 'NSSH1', 'SSH1', 'trans_respSDQ2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(mzData_for_stv)
dzData_for_stv<-dzData%>%
select('trans_respSDQ1', 'NSSH1', 'SSH1', 'trans_respSDQ2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(dzData_for_stv)
jiggle <-rnorm(nlower, mean = 0, sd = .1)
MZmean <-colMeans(mzData_for_stv,na.rm=TRUE)
DZmean <-colMeans(dzData_for_stv,na.rm=TRUE)
StMZmean<- c(mean(MZmean[c(1,4)]),0,0,mean(MZmean[c(1,4)]),0,0)
StDZmean<- c(mean(DZmean[c(1,4)]),0,0,mean(DZmean[c(1,4)]),0,0)
Stsd <-mean(sapply(mzData_for_stv[,c(1,4)],sd, na.rm=TRUE))
StWithinperson <-vechs(cor(SHData_for_stv[,1:3],use="pairwise"))
StBetweenMZ <-vech(cor(mzData_for_stv[,1:3],mzData_for_stv[,4:6],use="pairwise"))
StBetweenDZ <-vech(cor(dzData_for_stv[,1:3],dzData_for_stv[,4:6],use="pairwise"))
str(self_harm_data_c)
# 2) Specify ACE Model, with ONE overall set of Means, ONE overall Threshold on IQ liability
# To create Labels for Lower Triangular Matrices
StTH <-c(-0.2,0.45,0.19,0.15,0.76,0.55,0.25,0.16)
aLabs <- paste("a", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
cLabs <- paste("c", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
eLabs <- paste("e", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13','Tmz_21','imz_21','imz_22','imz_23') # THs for var 1 and 2 for a
LabCovA <-c('BageThNSSH', 'BageThNSSH','BageThNSSH', 'BageThNSSH', 'BageThSSH', 'BageThSSH','BageThSSH', 'BageThSSH')
LabCovS <-c('BsexThNSSH', 'BsexThNSSH','BsexThNSSH', 'BsexThNSSH', 'BsexThSSH', 'BsexThSSH','BsexThSSH', 'BsexThSSH')
# Matrices to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(1.30,0.15,0.18,0.72,0.64,0.23), labels=aLabs, name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.30,0.02,0.01,0.01,0.001,.001), labels=cLabs, name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.66,0.03,0.06,.67,0.57,0.42), labels=eLabs, name="e" )
# # Define definition variables to hold the Covariates
obsAge1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Age1")
obsAge2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Age2")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#effect of age and sex on ordinal variable
betaA <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovA, name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovS, name="BsexTH" )
#mean and thresholds
Mean <-mxMatrix( "Full", 1, ntv, free=c(T,F,F,T,F,F), values=StMZmean, labels=c("m1", NA,NA, "m1", NA,NA), name="ExpMean" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=StTH, lbound=c(-4,-4), ubound=c(4,4),
labels=LabThMZ, name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH%x%Age1 + BsexTH%x%Sex1,
Low%*%Th + BageTH%x%Age2 + BsexTH%x%Sex2),
name="ExpThres")
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
# Algebra to compute standardized variance components
covP <- mxAlgebra( expression=A+C+E, name="V" )
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Constraint on total variance of Ordinal variable (A+C+E=1)
varL1 <- mxConstraint( expression=V[2,2]==1, name="L1" )
varL2 <- mxConstraint( expression=V[3,3]==1, name="L2" )
# Algebra to compute Rph-A, Rph-C & Rph-E between pSDQ-NSSH
rphace_pSDQ_NSSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE_pSDQ_NSSH" )
rphace_pSDQ_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[3,1]*sqrt(h2[3,3])),
(sqrt(c2[1,1])*Rc[3,1]*sqrt(c2[3,3])),
(sqrt(e2[1,1])*Re[3,1]*sqrt(e2[3,3])) ), name="RphACE_pSDQ_SSH" )
rphace_NSSH_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[2,2])*Ra[3,2]*sqrt(h2[3,3])),
(sqrt(c2[2,2])*Rc[3,2]*sqrt(c2[3,3])),
(sqrt(e2[2,2])*Re[3,2]*sqrt(e2[3,3])) ), name="RphACE_NSSH_SSH" )
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[2,2], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[3,3], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[2,2], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[3,3], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[2,2], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[3,3], name="SSH_e")
#rA
raNSSHpSDQ<-mxAlgebra(expression=Ra[2,1], name="rA_NSSH_pSDQ")
raSSHpSDQ<-mxAlgebra(expression=Ra[3,1], name="rA_SSH_pSDQ")
#rC
rcNSSHpSDQ<-mxAlgebra(expression=Rc[2,1], name="rC_NSSH_pSDQ")
rcSSHpSDQ<-mxAlgebra(expression=Rc[3,1], name="rC_SSH_pSDQ")
#rE
reNSSHpSDQ<-mxAlgebra(expression=Re[2,1], name="rE_NSSH_pSDQ")
reSSHpSDQ<-mxAlgebra(expression=Re[3,1], name="rE_SSH_pSDQ")
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="ExpCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, StA, StC, StE, matI, rph, rA, rC, rE,
rphace_pSDQ_NSSH,rphace_pSDQ_SSH,rphace_NSSH_SSH,
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2,
raNSSHpSDQ,raSSHpSDQ,rcNSSHpSDQ,rcSSHpSDQ,reNSSHpSDQ,reSSHpSDQ)
modelMZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covMZ, dataMZ, objMZ, fitFunction, varL1, varL2, name="MZ" )
modelDZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
#confidence intervals
Conf1 <- mxCI (c('Rph[2,1]','Rph[3,1]'))
Conf2 <- mxCI ('Ra[2,1]')
Conf3 <- mxCI ('Ra[3,1]')
Conf4 <- mxCI ('Rc[2,1]')
Conf5 <- mxCI ('Rc[3,1]')
Conf6 <- mxCI ('Re[2,1]')
Conf7 <- mxCI ('Re[3,1]')
AceModel1 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf1) #note that I asked for CI for Conf2 only
AceModel2 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf2) #note that I asked for CI for Conf2 only
AceModel3 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf3) #note that I asked for CI for Conf2 only
AceModel4 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf4) #note that I asked for CI for Conf2 only
AceModel5 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf5) #note that I asked for CI for Conf2 only
AceModel6 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf6) #note that I asked for CI for Conf2 only
AceModel7 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf7) #note that I asked for CI for Conf2 only
# 3) RUN AceModel
AceFit1 <- mxTryHardOrdinal(AceModel1, intervals=T) #best fit -2lnL should be 40393.31
AceFit2 <- mxTryHardOrdinal(AceModel2, intervals=T) #best fit -2lnL should be 40393.31
AceFit3 <- mxTryHardOrdinal(AceModel3, intervals=T) #best fit -2lnL should be 40393.31
AceFit4 <- mxTryHardOrdinal(AceModel4, intervals=T) #best fit -2lnL should be 40393.31
AceFit5 <- mxTryHardOrdinal(AceModel5, intervals=T) #best fit -2lnL should be 40393.31
AceFit6 <- mxTryHardOrdinal(AceModel6, intervals=T) #best fit -2lnL should be 40393.31
AceFit7 <- mxTryHardOrdinal(AceModel7, intervals=T) #best fit -2lnL should be 40393.31
(AceSum1 <- summary(AceFit1,verbose=T))
(AceSum2 <- summary(AceFit2,verbose=T))
(AceSum3 <- summary(AceFit3,verbose=T))
(AceSum4 <- summary(AceFit4,verbose=T))
(AceSum5 <- summary(AceFit5,verbose=T))
(AceSum6 <- summary(AceFit6,verbose=T))
(AceSum7 <- summary(AceFit7,verbose=T))
#get the estimates and CIs
CI1 <- AceSum1$CI
CI2 <- AceSum2$CI
CI3 <- AceSum3$CI
CI4 <- AceSum4$CI
CI5 <- AceSum5$CI
CI6 <- AceSum6$CI
CI7 <- AceSum7$CI
tot_CI<-rbind(CI1,CI2,CI3,CI4,CI5,CI6,CI7)
#evaluate the contents
mxEval(MZ.ExpCovMZ, AceFit1)
mxEval(DZ.ExpCovDZ, AceFit1)
mxEval(ACE.h2, AceFit1)
mxEval(ACE.c2, AceFit1)
mxEval(ACE.e2, AceFit1)
mxEval(ACE.Ra, AceFit1)
mxEval(ACE.Rc, AceFit1)
mxEval(ACE.Re, AceFit1)
mxEval(ACE.Rph, AceFit1)
mxEval(ACE.RphACE_pSDQ_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1]*100
mxEval(ACE.RphACE_pSDQ_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1]*100
mxEval(ACE.V,AceFit1)
#get the proportion explained by A,C and E in the phenotypic correlation
proportion<-as.data.frame(rbind((mxEval(ACE.RphACE_pSDQ_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1])*100,
(mxEval(ACE.RphACE_pSDQ_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1])*100,
mxEval(ACE.RphACE_pSDQ_NSSH, AceFit1),
mxEval(ACE.RphACE_pSDQ_SSH, AceFit1)),
row.names=c("NSSH%","SSH%", "NSSH","SSH"))
colnames(proportion)<-c("A","C","E")
proportion
#constrain the model
Sub1Model <- mxModel(AceModel1, name="sub1",
mxConstraint(MZ.rA_NSSH_pSDQ==MZ.rA_SSH_pSDQ, name="rA_con"),
mxConstraint(MZ.rC_NSSH_pSDQ==MZ.rC_SSH_pSDQ, name="rC_con"),
mxConstraint(MZ.rE_NSSH_pSDQ==MZ.rE_SSH_pSDQ, name="rE_con"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = F)
(Sub1Sum <- summary(Sub1Fit))
mxEval(MZ.NSSH_a,Sub1Fit);mxEval(MZ.SSH_a,Sub1Fit)
mxEval(MZ.NSSH_c,Sub1Fit);mxEval(MZ.SSH_c,Sub1Fit)
mxEval(MZ.NSSH_e,Sub1Fit);mxEval(MZ.SSH_e,Sub1Fit)
mxEval(MZ.path_a,Sub1Fit);mxEval(MZ.path_c,Sub1Fit);mxEval(MZ.path_e,Sub1Fit)
mxEval(MZ.Ra,Sub1Fit);mxEval(MZ.Rc,Sub1Fit);mxEval(MZ.Re,Sub1Fit)
mxEval(MZ.h2,Sub1Fit)
### compare with ACE model
comparison <- mxCompare(AceFit1,Sub1Fit)
library(xlsx)
## 6) save the results
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_pSDQ_SLSQP_ACE_04_June_2020.RData")
# save the estimates and their confidence intervals
write.xlsx(tot_CI, file="trivariate_estimates_with_CI_04_June_2020.xlsx",
sheetName="pSDQ", append=TRUE)
# # Add a second data set in a new worksheet
# write.xlsx(mtcars, file="myworkbook.xlsx", sheetName="MTCARS",
# append=TRUE)
# save the proportions
write.xlsx(proportion, file="trivariate_proportion_04_June_2020.xlsx",
sheetName="pSDQ", append=TRUE)
# save the results of the chi-square test
write.xlsx(comparison, file="trivariate_constrained_results_04_June_2020.xlsx",
sheetName="pSDQ", append=TRUE)
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
str(self_harm_data);class(self_harm_data)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,pcbhmfqt1,pcbhmfqt2,x3zygos,u1cage1,u1cage2,pcbhage1,pcbhage2, sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
self_harm_data_c <- mutate(self_harm_data_c, age_161 = ifelse(is.na(pcbhage1),pcbhage2 , pcbhage1))
self_harm_data_c <- mutate(self_harm_data_c, age_162 = ifelse(is.na(pcbhage2),pcbhage1 , pcbhage2))
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$SSH1)
table(self_harm_data_c$SSH2)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
str(self_harm_data_c)
#******************************************************
# Regress out age, sex and transform cMFQ variable
#******************************************************
#**Regressing out age & sex **#
self_harm_data_c$rescMFQ1 <- residuals(lm(self_harm_data_c$pcbhmfqt1 ~ self_harm_data_c$age_161 + self_harm_data_c$sex1, na.action="na.exclude"))
self_harm_data_c$rescMFQ2 <- residuals(lm(self_harm_data_c$pcbhmfqt2 ~ self_harm_data_c$age_162 + self_harm_data_c$sex2, na.action="na.exclude"))
hist(self_harm_data_c$pcbhmfqt1)
hist(self_harm_data_c$rescMFQ1)
describe(self_harm_data_c$rescMFQ1)
# #transform the data to get a normal distribution
self_harm_data_c$trans_rescMFQ1 <-log(self_harm_data_c$rescMFQ1+4.96)*1.5
self_harm_data_c$trans_rescMFQ2 <-log(self_harm_data_c$rescMFQ2+4.96)*1.5
hist(self_harm_data_c$rescMFQ1)
hist(self_harm_data_c$trans_rescMFQ1)
describe(self_harm_data_c$trans_rescMFQ1)
library(polycor) #check phenotypic correlation
hetcor(self_harm_data_c$trans_rescMFQ1, self_harm_data_c$NSSH1)$correlations #0.36
hetcor(self_harm_data_c$pcbhmfqt1, self_harm_data_c$NSSH1)$correlations #without covariates, 0.36
hetcor(self_harm_data_c$SSH1, self_harm_data_c$NSSH1)$correlations # 0.87, same as in other less complex models.
vars <-c('cMFQ','NSSH', 'SSH')
selVars <-c('trans_rescMFQ1', 'NSSH1', 'SSH1', 'trans_rescMFQ2', 'NSSH2', 'SSH2')
useVars <-c('trans_rescMFQ1', 'NSSH1', 'SSH1', 'trans_rescMFQ2', 'NSSH2', 'SSH2', 'age1', 'age2', 'sex1','sex2')
# Select Data for Analysis
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars)
describe(mzData)
describe(dzData)
nv <- 3 # number of variables per twin
nvo <-2 #number of ordinal variables per twin
nvc <-nv-nvo #number of continuous variables per twin
poso <- nvc+1 #position where ordinal variables start
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
nlower <- ntv*(ntv+1)/2 # number of free elements in a lower matrix ntv*ntv
ncor <-(nv*(nv+1)/2)-nv # number of free elements in a correlation matrix nv*nv
ninc <- nth-1 #number of max increments
ncovariates <- 2 #number of covariates
### Create starting values for covariance matrix
SHData_for_stv<-self_harm_data_c%>%
select('trans_rescMFQ1', 'NSSH1', 'SSH1', 'trans_rescMFQ2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(SHData_for_stv)
mzData_for_stv<-mzData%>%
select('trans_rescMFQ1', 'NSSH1', 'SSH1', 'trans_rescMFQ2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(mzData_for_stv)
dzData_for_stv<-dzData%>%
select('trans_rescMFQ1', 'NSSH1', 'SSH1', 'trans_rescMFQ2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(dzData_for_stv)
jiggle <-rnorm(nlower, mean = 0, sd = .1)
MZmean <-colMeans(mzData_for_stv,na.rm=TRUE)
DZmean <-colMeans(dzData_for_stv,na.rm=TRUE)
StMZmean<- c(mean(MZmean[c(1,4)]),0,0,mean(MZmean[c(1,4)]),0,0)
StDZmean<- c(mean(DZmean[c(1,4)]),0,0,mean(DZmean[c(1,4)]),0,0)
Stsd <-mean(sapply(mzData_for_stv[,c(1,4)],sd, na.rm=TRUE))
StWithinperson <-vechs(cor(SHData_for_stv[,1:3],use="pairwise"))
StBetweenMZ <-vech(cor(mzData_for_stv[,1:3],mzData_for_stv[,4:6],use="pairwise"))
StBetweenDZ <-vech(cor(dzData_for_stv[,1:3],dzData_for_stv[,4:6],use="pairwise"))
str(self_harm_data_c)
# 2) Specify ACE Model, with ONE overall set of Means, ONE overall Threshold on IQ liability
# To create Labels for Lower Triangular Matrices
StTH <-c(-0.13,0.45,0.19,0.15,0.89,0.55,0.25,0.16)
aLabs <- paste("a", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
cLabs <- paste("c", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
eLabs <- paste("e", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13','Tmz_21','imz_21','imz_22','imz_23') # THs for var 1 and 2 for a
LabCovA <-c('BageThNSSH', 'BageThNSSH','BageThNSSH', 'BageThNSSH', 'BageThSSH', 'BageThSSH','BageThSSH', 'BageThSSH')
LabCovS <-c('BsexThNSSH', 'BsexThNSSH','BsexThNSSH', 'BsexThNSSH', 'BsexThSSH', 'BsexThSSH','BsexThSSH', 'BsexThSSH')
# Matrices to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.70,0.36,0.45,0.60,0.46,0.17), labels=aLabs, name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.30,0.20,0.14,0.05,0.08,0.001), labels=cLabs, name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.64,0.13,0.13,0.67,0.55,0.82), labels=eLabs, name="e" )
# # Define definition variables to hold the Covariates
obsAge1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Age1")
obsAge2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Age2")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#effect of age and sex on ordinal variable
betaA <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovA, name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovS, name="BsexTH" )
#mean and thresholds
Mean <-mxMatrix( "Full", 1, ntv, free=c(T,F,F,T,F,F), values=StMZmean, labels=c("m1", NA,NA, "m1", NA,NA), name="ExpMean" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=StTH, lbound=c(-4,-4), ubound=c(4,4),
labels=LabThMZ, name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH%x%Age1 + BsexTH%x%Sex1,
Low%*%Th + BageTH%x%Age2 + BsexTH%x%Sex2),
name="ExpThres")
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
# Algebra to compute standardized variance components
covP <- mxAlgebra( expression=A+C+E, name="V" )
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Constraint on total variance of Ordinal variable (A+C+E=1)
varL1 <- mxConstraint( expression=V[2,2]==1, name="L1" )
varL2 <- mxConstraint( expression=V[3,3]==1, name="L2" )
# Algebra to compute Rph-A, Rph-C & Rph-E between cMFQ-NSSH
rphace_cMFQ_NSSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE_cMFQ_NSSH" )
rphace_cMFQ_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[3,1]*sqrt(h2[3,3])),
(sqrt(c2[1,1])*Rc[3,1]*sqrt(c2[3,3])),
(sqrt(e2[1,1])*Re[3,1]*sqrt(e2[3,3])) ), name="RphACE_cMFQ_SSH" )
rphace_NSSH_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[2,2])*Ra[3,2]*sqrt(h2[3,3])),
(sqrt(c2[2,2])*Rc[3,2]*sqrt(c2[3,3])),
(sqrt(e2[2,2])*Re[3,2]*sqrt(e2[3,3])) ), name="RphACE_NSSH_SSH" )
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[2,2], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[3,3], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[2,2], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[3,3], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[2,2], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[3,3], name="SSH_e")
#rA
raNSSHcMFQ<-mxAlgebra(expression=Ra[2,1], name="rA_NSSH_cMFQ")
raSSHcMFQ<-mxAlgebra(expression=Ra[3,1], name="rA_SSH_cMFQ")
#rC
rcNSSHcMFQ<-mxAlgebra(expression=Rc[2,1], name="rC_NSSH_cMFQ")
rcSSHcMFQ<-mxAlgebra(expression=Rc[3,1], name="rC_SSH_cMFQ")
#rE
reNSSHcMFQ<-mxAlgebra(expression=Re[2,1], name="rE_NSSH_cMFQ")
reSSHcMFQ<-mxAlgebra(expression=Re[3,1], name="rE_SSH_cMFQ")
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="ExpCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, StA, StC, StE, matI, rph, rA, rC, rE,
rphace_cMFQ_NSSH,rphace_cMFQ_SSH,rphace_NSSH_SSH,
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2,
raNSSHcMFQ,raSSHcMFQ,rcNSSHcMFQ,rcSSHcMFQ,reNSSHcMFQ,reSSHcMFQ)
modelMZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covMZ, dataMZ, objMZ, fitFunction, varL1, varL2, name="MZ" )
modelDZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
#confidence intervals
Conf1 <- mxCI (c('Rph[2,1]','Rph[3,1]'))
Conf2 <- mxCI ('Ra[2,1]')
Conf3 <- mxCI ('Ra[3,1]')
Conf4 <- mxCI ('Rc[2,1]')
Conf5 <- mxCI ('Rc[3,1]')
Conf6 <- mxCI ('Re[2,1]')
Conf7 <- mxCI ('Re[3,1]')
AceModel1 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf1) #
AceModel2 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf2) #
AceModel3 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf3) #
AceModel4 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf4) #
AceModel5 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf5) #
AceModel6 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf6) #
AceModel7 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf7) #
# 3) RUN AceModel
AceFit1 <- mxTryHardOrdinal(AceModel1, intervals=T) #best fit -2lnL should be 40393.31
AceFit2 <- mxTryHardOrdinal(AceModel2, intervals=T) #best fit -2lnL should be 40393.31
AceFit3 <- mxTryHardOrdinal(AceModel3, intervals=T) #best fit -2lnL should be 40393.31
AceFit4 <- mxTryHardOrdinal(AceModel4, intervals=T) #best fit -2lnL should be 40393.31
AceFit5 <- mxTryHardOrdinal(AceModel5, intervals=T) #best fit -2lnL should be 40393.31
AceFit6 <- mxTryHardOrdinal(AceModel6, intervals=T) #best fit -2lnL should be 40393.31
AceFit7 <- mxTryHardOrdinal(AceModel7, intervals=T) #best fit -2lnL should be 40393.31
(AceSum1 <- summary(AceFit1,verbose=T))
(AceSum2 <- summary(AceFit2,verbose=T))
(AceSum3 <- summary(AceFit3,verbose=T))
(AceSum4 <- summary(AceFit4,verbose=T))
(AceSum5 <- summary(AceFit5,verbose=T))
(AceSum6 <- summary(AceFit6,verbose=T))
(AceSum7 <- summary(AceFit7,verbose=T))
#get the estimates and CIs
CI1 <- AceSum1$CI
CI2 <- AceSum2$CI
CI3 <- AceSum3$CI
CI4 <- AceSum4$CI
CI5 <- AceSum5$CI
CI6 <- AceSum6$CI
CI7 <- AceSum7$CI
tot_CI<-rbind(CI1,CI2,CI3,CI4,CI5,CI6,CI7)
#evaluate the contents
mxEval(MZ.ExpCovMZ, AceFit1)
mxEval(DZ.ExpCovDZ, AceFit1)
mxEval(ACE.h2, AceFit1)
mxEval(ACE.c2, AceFit1)
mxEval(ACE.e2, AceFit1)
mxEval(ACE.Ra, AceFit1)
mxEval(ACE.Rc, AceFit1)
mxEval(ACE.Re, AceFit1)
mxEval(ACE.Rph, AceFit1)
mxEval(ACE.RphACE_cMFQ_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1]*100
mxEval(ACE.RphACE_cMFQ_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1]*100
mxEval(ACE.V,AceFit1)
#get the proportion explained by A,C and E in the phenotypic correlation
proportion<-as.data.frame(rbind((mxEval(ACE.RphACE_cMFQ_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1])*100,
(mxEval(ACE.RphACE_cMFQ_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1])*100,
mxEval(ACE.RphACE_cMFQ_NSSH, AceFit1),
mxEval(ACE.RphACE_cMFQ_SSH, AceFit1)),
row.names=c("NSSH%","SSH%", "NSSH","SSH"))
colnames(proportion)<-c("A","C","E")
proportion
#constrain the model
Sub1Model <- mxModel(AceModel1, name="sub1",
mxConstraint(MZ.rA_NSSH_cMFQ==MZ.rA_SSH_cMFQ, name="rA_con"),
mxConstraint(MZ.rC_NSSH_cMFQ==MZ.rC_SSH_cMFQ, name="rC_con"),
mxConstraint(MZ.rE_NSSH_cMFQ==MZ.rE_SSH_cMFQ, name="rE_con"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = F)
(Sub1Sum <- summary(Sub1Fit))
mxEval(MZ.NSSH_a,Sub1Fit);mxEval(MZ.SSH_a,Sub1Fit)
mxEval(MZ.NSSH_c,Sub1Fit);mxEval(MZ.SSH_c,Sub1Fit)
mxEval(MZ.NSSH_e,Sub1Fit);mxEval(MZ.SSH_e,Sub1Fit)
mxEval(MZ.path_a,Sub1Fit);mxEval(MZ.path_c,Sub1Fit);mxEval(MZ.path_e,Sub1Fit)
mxEval(MZ.Ra,Sub1Fit);mxEval(MZ.Rc,Sub1Fit);mxEval(MZ.Re,Sub1Fit)
mxEval(MZ.h2,Sub1Fit)
### compare with ACE model
comparison <- mxCompare(AceFit1,Sub1Fit)
library(xlsx)
## 6) save the results
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_cMFQ_SLSQP_ACE_04_June_2020.RData")
# save the estimates and their confidence intervals
write.xlsx(tot_CI, file="trivariate_estimates_with_CI_04_June_2020.xlsx",
sheetName="cMFQ", append=TRUE)
# save the proportions
write.xlsx(proportion, file="trivariate_proportion_04_June_2020.xlsx",
sheetName="cMFQ", append=TRUE)
# save the results of the chi-square test
write.xlsx(comparison, file="trivariate_constrained_results_04_June_2020.xlsx",
sheetName="cMFQ", append=TRUE)
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse);require(bestNormalize)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
str(self_harm_data);class(self_harm_data)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,ppbhmfqt1,ppbhmfqt2,x3zygos,u1cage1,u1cage2,pcbhage1,pcbhage2, sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
self_harm_data_c <- mutate(self_harm_data_c, age_161 = ifelse(is.na(pcbhage1),pcbhage2 , pcbhage1))
self_harm_data_c <- mutate(self_harm_data_c, age_162 = ifelse(is.na(pcbhage2),pcbhage1 , pcbhage2))
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$SSH1)
table(self_harm_data_c$SSH2)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
str(self_harm_data_c)
#******************************************************
# Regress out age, sex and transform pMFQ variable
#******************************************************
#**Regressing out age & sex **#
self_harm_data_c$respMFQ1 <- residuals(lm(self_harm_data_c$ppbhmfqt1 ~ self_harm_data_c$age_161 + self_harm_data_c$sex1, na.action="na.exclude"))
self_harm_data_c$respMFQ2 <- residuals(lm(self_harm_data_c$ppbhmfqt2 ~ self_harm_data_c$age_162 + self_harm_data_c$sex2, na.action="na.exclude"))
hist(self_harm_data_c$ppbhmfqt1)
hist(self_harm_data_c$respMFQ1)
describe(self_harm_data_c$respMFQ1)
# #transform the data to get a normal distribution
self_harm_data_c$trans_respMFQ1 <-log(self_harm_data_c$respMFQ1+1.29)*2
self_harm_data_c$trans_respMFQ2 <-log(self_harm_data_c$respMFQ2+1.29)*2
hist(self_harm_data_c$respMFQ1)
hist(self_harm_data_c$trans_respMFQ1)
describe(self_harm_data_c$trans_respMFQ1)
library(polycor) #check phenotypic correlation
hetcor(self_harm_data_c$trans_respMFQ1, self_harm_data_c$NSSH1)$correlations #0.16
hetcor(self_harm_data_c$ppbhmfqt1, self_harm_data_c$NSSH1)$correlations #without covariates, 0.20
hetcor(self_harm_data_c$SSH1, self_harm_data_c$NSSH1)$correlations # 0.87, same as in other less complex models.
vars <-c('pMFQ','NSSH', 'SSH')
selVars <-c('trans_respMFQ1', 'NSSH1', 'SSH1', 'trans_respMFQ2', 'NSSH2', 'SSH2')
useVars <-c('trans_respMFQ1', 'NSSH1', 'SSH1', 'trans_respMFQ2', 'NSSH2', 'SSH2', 'age1', 'age2', 'sex1','sex2')
# Select Data for Analysis
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars)
describe(mzData)
describe(dzData)
nv <- 3 # number of variables per twin
nvo <-2 #number of ordinal variables per twin
nvc <-nv-nvo #number of continuous variables per twin
poso <- nvc+1 #position where ordinal variables start
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
nlower <- ntv*(ntv+1)/2 # number of free elements in a lower matrix ntv*ntv
ncor <-(nv*(nv+1)/2)-nv # number of free elements in a correlation matrix nv*nv
ninc <- nth-1 #number of max increments
ncovariates <- 2 #number of covariates
### Create starting values for covariance matrix
SHData_for_stv<-self_harm_data_c%>%
select('trans_respMFQ1', 'NSSH1', 'SSH1', 'trans_respMFQ2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(SHData_for_stv)
mzData_for_stv<-mzData%>%
select('trans_respMFQ1', 'NSSH1', 'SSH1', 'trans_respMFQ2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(mzData_for_stv)
dzData_for_stv<-dzData%>%
select('trans_respMFQ1', 'NSSH1', 'SSH1', 'trans_respMFQ2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(dzData_for_stv)
jiggle <-rnorm(nlower, mean = 0, sd = .1)
MZmean <-colMeans(mzData_for_stv,na.rm=TRUE)
DZmean <-colMeans(dzData_for_stv,na.rm=TRUE)
StMZmean<- c(mean(MZmean[c(1,4)]),0,0,mean(MZmean[c(1,4)]),0,0)
StDZmean<- c(mean(DZmean[c(1,4)]),0,0,mean(DZmean[c(1,4)]),0,0)
Stsd <-mean(sapply(mzData_for_stv[,c(1,4)],sd, na.rm=TRUE))
StWithinperson <-vechs(cor(SHData_for_stv[,1:3],use="pairwise"))
StBetweenMZ <-vech(cor(mzData_for_stv[,1:3],mzData_for_stv[,4:6],use="pairwise"))
StBetweenDZ <-vech(cor(dzData_for_stv[,1:3],dzData_for_stv[,4:6],use="pairwise"))
str(self_harm_data_c)
# 2) Specify ACE Model, with ONE overall set of Means, ONE overall Threshold on IQ liability
# To create Labels for Lower Triangular Matrices
StTH <-c(-0.44,0.45,0.19,0.15,0.70,0.55,0.26,0.16)
aLabs <- paste("a", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
cLabs <- paste("c", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
eLabs <- paste("e", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13','Tmz_21','imz_21','imz_22','imz_23') # THs for var 1 and 2 for a
LabCovA <-c('BageThNSSH', 'BageThNSSH','BageThNSSH', 'BageThNSSH', 'BageThSSH', 'BageThSSH','BageThSSH', 'BageThSSH')
LabCovS <-c('BsexThNSSH', 'BsexThNSSH','BsexThNSSH', 'BsexThNSSH', 'BsexThSSH', 'BsexThSSH','BsexThSSH', 'BsexThSSH')
# Matrices to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.45,0.19,0.20,0.68,0.58,0.05), labels=aLabs, name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.32,0.18,0.01,0.01,0.01,0.01), labels=cLabs, name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.59,0.81,0.79,0.67,0.57,0.45), labels=eLabs, name="e" )
# # Define definition variables to hold the Covariates
obsAge1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Age1")
obsAge2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Age2")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#effect of age and sex on ordinal variable
betaA <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.04, labels=LabCovA, name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.30, labels=LabCovS, name="BsexTH" )
#mean and thresholds
Mean <-mxMatrix( "Full", 1, ntv, free=c(T,F,F,T,F,F), values=StMZmean, labels=c("m1", NA,NA, "m1", NA,NA), name="ExpMean" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=StTH, lbound=c(-4,0.001,0.001,0.001), ubound=c(4),
labels=LabThMZ, name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH%x%Age1 + BsexTH%x%Sex1,
Low%*%Th + BageTH%x%Age2 + BsexTH%x%Sex2),
name="ExpThres")
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
# Algebra to compute standardized variance components
covP <- mxAlgebra( expression=A+C+E, name="V" )
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Constraint on total variance of Ordinal variable (A+C+E=1)
varL1 <- mxConstraint( expression=V[2,2]==1, name="L1" )
varL2 <- mxConstraint( expression=V[3,3]==1, name="L2" )
# Algebra to compute Rph-A, Rph-C & Rph-E between pMFQ-NSSH
rphace_pMFQ_NSSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE_pMFQ_NSSH" )
rphace_pMFQ_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[3,1]*sqrt(h2[3,3])),
(sqrt(c2[1,1])*Rc[3,1]*sqrt(c2[3,3])),
(sqrt(e2[1,1])*Re[3,1]*sqrt(e2[3,3])) ), name="RphACE_pMFQ_SSH" )
rphace_NSSH_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[2,2])*Ra[3,2]*sqrt(h2[3,3])),
(sqrt(c2[2,2])*Rc[3,2]*sqrt(c2[3,3])),
(sqrt(e2[2,2])*Re[3,2]*sqrt(e2[3,3])) ), name="RphACE_NSSH_SSH" )
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[2,2], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[3,3], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[2,2], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[3,3], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[2,2], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[3,3], name="SSH_e")
#rA
raNSSHpMFQ<-mxAlgebra(expression=Ra[2,1], name="rA_NSSH_pMFQ")
raSSHpMFQ<-mxAlgebra(expression=Ra[3,1], name="rA_SSH_pMFQ")
#rC
rcNSSHpMFQ<-mxAlgebra(expression=Rc[2,1], name="rC_NSSH_pMFQ")
rcSSHpMFQ<-mxAlgebra(expression=Rc[3,1], name="rC_SSH_pMFQ")
#rE
reNSSHpMFQ<-mxAlgebra(expression=Re[2,1], name="rE_NSSH_pMFQ")
reSSHpMFQ<-mxAlgebra(expression=Re[3,1], name="rE_SSH_pMFQ")
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="ExpCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, StA, StC, StE, matI, rph, rA, rC, rE,
rphace_pMFQ_NSSH,rphace_pMFQ_SSH,rphace_NSSH_SSH,
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2,
raNSSHpMFQ,raSSHpMFQ,rcNSSHpMFQ,rcSSHpMFQ,reNSSHpMFQ,reSSHpMFQ)
modelMZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covMZ, dataMZ, objMZ, varL1, varL2, fitFunction, name="MZ" )
modelDZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
#confidence intervals
Conf1 <- mxCI (c('Rph[2,1]','Rph[3,1]'))
Conf2 <- mxCI ('Ra[2,1]')
Conf3 <- mxCI ('Ra[3,1]')
Conf4 <- mxCI ('Rc[2,1]')
Conf5 <- mxCI ('Rc[3,1]')
Conf6 <- mxCI ('Re[2,1]')
Conf7 <- mxCI ('Re[3,1]')
AceModel1 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf1) #
AceModel2 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf2) #
AceModel3 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf3) #
AceModel4 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf4) #
AceModel5 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf5) #
AceModel6 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf6) #
AceModel7 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf7) #
# 3) RUN AceModel
AceFit1 <- mxTryHardOrdinal(AceModel1, intervals=T) #best fit -2lnL should be 57172.68
AceFit2 <- mxTryHardOrdinal(AceModel2, intervals=T)
AceFit3 <- mxTryHardOrdinal(AceModel3, intervals=T)
AceFit4 <- mxTryHardOrdinal(AceModel4, intervals=T)
AceFit5 <- mxTryHardOrdinal(AceModel5, intervals=T)
AceFit6 <- mxTryHardOrdinal(AceModel6, intervals=T)
AceFit7 <- mxTryHardOrdinal(AceModel7, intervals=T)
(AceSum1 <- summary(AceFit1,verbose=T))
(AceSum2 <- summary(AceFit2,verbose=T))
(AceSum3 <- summary(AceFit3,verbose=T))
(AceSum4 <- summary(AceFit4,verbose=T))
(AceSum5 <- summary(AceFit5,verbose=T))
(AceSum6 <- summary(AceFit6,verbose=T))
(AceSum7 <- summary(AceFit7,verbose=T))
#get the estimates and CIs
CI1 <- AceSum1$CI
CI2 <- AceSum2$CI
CI3 <- AceSum3$CI
CI4 <- AceSum4$CI
CI5 <- AceSum5$CI
CI6 <- AceSum6$CI
CI7 <- AceSum7$CI
tot_CI<-rbind(CI1,CI2,CI3,CI4,CI5,CI6,CI7)
#evaluate the contents
mxEval(MZ.ExpCovMZ, AceFit1)
mxEval(DZ.ExpCovDZ, AceFit1)
mxEval(ACE.h2, AceFit1)
mxEval(ACE.c2, AceFit1)
mxEval(ACE.e2, AceFit1)
mxEval(ACE.Ra, AceFit1)
mxEval(ACE.Rc, AceFit1)
mxEval(ACE.Re, AceFit1)
mxEval(ACE.Rph, AceFit1)
mxEval(ACE.RphACE_pMFQ_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1]*100
mxEval(ACE.RphACE_pMFQ_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1]*100
mxEval(ACE.V,AceFit1)
#get the proportion explained by A,C and E in the phenotypic correlation
proportion<-as.data.frame(rbind((mxEval(ACE.RphACE_pMFQ_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1])*100,
(mxEval(ACE.RphACE_pMFQ_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1])*100,
mxEval(ACE.RphACE_pMFQ_NSSH, AceFit1),
mxEval(ACE.RphACE_pMFQ_SSH, AceFit1)),
row.names=c("NSSH%","SSH%", "NSSH","SSH"))
colnames(proportion)<-c("A","C","E")
proportion
#constrain the model
Sub1Model <- mxModel(AceModel1, name="sub1",
mxConstraint(MZ.rA_NSSH_pMFQ==MZ.rA_SSH_pMFQ, name="rA_con"),
mxConstraint(MZ.rC_NSSH_pMFQ==MZ.rC_SSH_pMFQ, name="rC_con"),
mxConstraint(MZ.rE_NSSH_pMFQ==MZ.rE_SSH_pMFQ, name="rE_con"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = F)
(Sub1Sum <- summary(Sub1Fit))
mxEval(MZ.NSSH_a,Sub1Fit);mxEval(MZ.SSH_a,Sub1Fit)
mxEval(MZ.NSSH_c,Sub1Fit);mxEval(MZ.SSH_c,Sub1Fit)
mxEval(MZ.NSSH_e,Sub1Fit);mxEval(MZ.SSH_e,Sub1Fit)
mxEval(MZ.path_a,Sub1Fit);mxEval(MZ.path_c,Sub1Fit);mxEval(MZ.path_e,Sub1Fit)
mxEval(MZ.Ra,Sub1Fit);mxEval(MZ.Rc,Sub1Fit);mxEval(MZ.Re,Sub1Fit)
mxEval(MZ.h2,Sub1Fit)
### compare with ACE model
comparison <- mxCompare(AceFit1,Sub1Fit)
library(xlsx)
## 6) save the results
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_pMFQ_SLSQP_ACE_04_June_2020.RData")
# save the estimates and their confidence intervals
write.xlsx(tot_CI, file="trivariate_estimates_with_CI_04_June_2020.xlsx",
sheetName="pMFQ", append=TRUE)
# save the proportions
write.xlsx(proportion, file="trivariate_proportion_04_June_2020.xlsx",
sheetName="pMFQ", append=TRUE)
# save the results of the chi-square test
write.xlsx(comparison, file="trivariate_constrained_results_04_June_2020.xlsx",
sheetName="pMFQ", append=TRUE)
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
str(self_harm_data);class(self_harm_data)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,pcbhcasit1,pcbhcasit2,x3zygos,u1cage1,u1cage2,pcbhage1,pcbhage2, sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
self_harm_data_c <- mutate(self_harm_data_c, age_161 = ifelse(is.na(pcbhage1),pcbhage2 , pcbhage1))
self_harm_data_c <- mutate(self_harm_data_c, age_162 = ifelse(is.na(pcbhage2),pcbhage1 , pcbhage2))
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$SSH1)
table(self_harm_data_c$SSH2)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
str(self_harm_data_c)
#******************************************************
# Regress out age, sex and transform cANX variable
#******************************************************
#**Regressing out age & sex **#
self_harm_data_c$rescANX1 <- residuals(lm(self_harm_data_c$pcbhcasit1 ~ self_harm_data_c$age_161 + self_harm_data_c$sex1, na.action="na.exclude"))
self_harm_data_c$rescANX2 <- residuals(lm(self_harm_data_c$pcbhcasit2 ~ self_harm_data_c$age_162 + self_harm_data_c$sex2, na.action="na.exclude"))
hist(self_harm_data_c$pcbhcasit1)
hist(self_harm_data_c$rescANX1)
describe(self_harm_data_c$rescANX1)
# #transform the data to get a normal distribution
self_harm_data_c$trans_rescANX1 <-sqrt(self_harm_data_c$rescANX1+9.44)*1.5
self_harm_data_c$trans_rescANX2 <-sqrt(self_harm_data_c$rescANX2+9.44)*1.5
hist(self_harm_data_c$rescANX1)
hist(self_harm_data_c$trans_rescANX1)
describe(self_harm_data_c$trans_rescANX1)
library(polycor) #check phenotypic correlation
hetcor(self_harm_data_c$trans_rescANX1, self_harm_data_c$NSSH1)$correlations #0.23
hetcor(self_harm_data_c$rescANX1, self_harm_data_c$NSSH1)$correlations #0.22
hetcor(self_harm_data_c$pcbhcasit1, self_harm_data_c$NSSH1)$correlations #without covariates, 0.25
hetcor(self_harm_data_c$SSH1, self_harm_data_c$NSSH1)$correlations # 0.87, same as in other less complex models.
vars <-c('cANX','NSSH', 'SSH')
selVars <-c('trans_rescANX1', 'NSSH1', 'SSH1', 'trans_rescANX2', 'NSSH2', 'SSH2')
useVars <-c('trans_rescANX1', 'NSSH1', 'SSH1', 'trans_rescANX2', 'NSSH2', 'SSH2', 'age1', 'age2', 'sex1','sex2')
# Select Data for Analysis
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars)
describe(mzData)
describe(dzData)
nv <- 3 # number of variables per twin
nvo <-2 #number of ordinal variables per twin
nvc <-nv-nvo #number of continuous variables per twin
poso <- nvc+1 #position where ordinal variables start
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
nlower <- ntv*(ntv+1)/2 # number of free elements in a lower matrix ntv*ntv
ncor <-(nv*(nv+1)/2)-nv # number of free elements in a correlation matrix nv*nv
ninc <- nth-1 #number of max increments
ncovariates <- 2 #number of covariates
### Create starting values for covariance matrix
SHData_for_stv<-self_harm_data_c%>%
select('trans_rescANX1', 'NSSH1', 'SSH1', 'trans_rescANX2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(SHData_for_stv)
mzData_for_stv<-mzData%>%
select('trans_rescANX1', 'NSSH1', 'SSH1', 'trans_rescANX2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(mzData_for_stv)
dzData_for_stv<-dzData%>%
select('trans_rescANX1', 'NSSH1', 'SSH1', 'trans_rescANX2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(dzData_for_stv)
jiggle <-rnorm(nlower, mean = 0, sd = .1)
MZmean <-colMeans(mzData_for_stv,na.rm=TRUE)
DZmean <-colMeans(dzData_for_stv,na.rm=TRUE)
StMZmean<- c(mean(MZmean[c(1,4)]),0,0,mean(MZmean[c(1,4)]),0,0)
StDZmean<- c(mean(DZmean[c(1,4)]),0,0,mean(DZmean[c(1,4)]),0,0)
Stsd <-mean(sapply(mzData_for_stv[,c(1,4)],sd, na.rm=TRUE))
StWithinperson <-vechs(cor(SHData_for_stv[,1:3],use="pairwise"))
StBetweenMZ <-vech(cor(mzData_for_stv[,1:3],mzData_for_stv[,4:6],use="pairwise"))
StBetweenDZ <-vech(cor(dzData_for_stv[,1:3],dzData_for_stv[,4:6],use="pairwise"))
str(self_harm_data_c)
# 2) Specify ACE Model, with ONE overall set of Means, ONE overall Threshold on IQ liability
# To create Labels for Lower Triangular Matrices
StTH <-c(-0.32,0.45,0.19,0.15,0.70,0.54,0.24,0.15)
aLabs <- paste("a", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
cLabs <- paste("c", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
eLabs <- paste("e", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13','Tmz_21','imz_21','imz_22','imz_23') # THs for var 1 and 2 for a
LabCovA <-c('BageThNSSH', 'BageThNSSH','BageThNSSH', 'BageThNSSH', 'BageThSSH', 'BageThSSH','BageThSSH', 'BageThSSH')
LabCovS <-c('BsexThNSSH', 'BsexThNSSH','BsexThNSSH', 'BsexThNSSH', 'BsexThSSH', 'BsexThSSH','BsexThSSH', 'BsexThSSH')
# Matrices to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.64,0.25,0.14,0.72,0.62,0.23), labels=aLabs, name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.30,0.15,0.19,0.01,0.01,0.01), labels=cLabs, name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.84,0.03,0.12,0.67,0.50,0.42), labels=eLabs, name="e" )
# # Define definition variables to hold the Covariates
obsAge1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Age1")
obsAge2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Age2")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#effect of age and sex on ordinal variable
betaA <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovA, name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovS, name="BsexTH" )
#mean and thresholds
Mean <-mxMatrix( "Full", 1, ntv, free=c(T,F,F,T,F,F), values=StMZmean, labels=c("m1", NA,NA, "m1", NA,NA), name="ExpMean" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=StTH, lbound=c(-4,0.001,0.001,0.001), ubound=c(4,4),
labels=LabThMZ, name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH%x%Age1 + BsexTH%x%Sex1,
Low%*%Th + BageTH%x%Age2 + BsexTH%x%Sex2),
name="ExpThres")
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
# Algebra to compute standardized variance components
covP <- mxAlgebra( expression=A+C+E, name="V" )
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Constraint on total variance of Ordinal variable (A+C+E=1)
varL1 <- mxConstraint( expression=V[2,2]==1, name="L1" )
varL2 <- mxConstraint( expression=V[3,3]==1, name="L2" )
# Algebra to compute Rph-A, Rph-C & Rph-E between cANX-NSSH
rphace_cANX_NSSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE_cANX_NSSH" )
rphace_cANX_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[3,1]*sqrt(h2[3,3])),
(sqrt(c2[1,1])*Rc[3,1]*sqrt(c2[3,3])),
(sqrt(e2[1,1])*Re[3,1]*sqrt(e2[3,3])) ), name="RphACE_cANX_SSH" )
rphace_NSSH_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[2,2])*Ra[3,2]*sqrt(h2[3,3])),
(sqrt(c2[2,2])*Rc[3,2]*sqrt(c2[3,3])),
(sqrt(e2[2,2])*Re[3,2]*sqrt(e2[3,3])) ), name="RphACE_NSSH_SSH" )
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[2,2], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[3,3], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[2,2], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[3,3], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[2,2], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[3,3], name="SSH_e")
#rA
raNSSHcANX<-mxAlgebra(expression=Ra[2,1], name="rA_NSSH_cANX")
raSSHcANX<-mxAlgebra(expression=Ra[3,1], name="rA_SSH_cANX")
#rC
rcNSSHcANX<-mxAlgebra(expression=Rc[2,1], name="rC_NSSH_cANX")
rcSSHcANX<-mxAlgebra(expression=Rc[3,1], name="rC_SSH_cANX")
#rE
reNSSHcANX<-mxAlgebra(expression=Re[2,1], name="rE_NSSH_cANX")
reSSHcANX<-mxAlgebra(expression=Re[3,1], name="rE_SSH_cANX")
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="ExpCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, StA, StC, StE, matI, rph, rA, rC, rE,
rphace_cANX_NSSH,rphace_cANX_SSH,rphace_NSSH_SSH,
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2,
raNSSHcANX,raSSHcANX,rcNSSHcANX,rcSSHcANX,reNSSHcANX,reSSHcANX)
modelMZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covMZ, dataMZ, objMZ, fitFunction, varL1, varL2, name="MZ" )
modelDZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
#confidence intervals
Conf1 <- mxCI (c('Rph[2,1]','Rph[3,1]'))
Conf2 <- mxCI ('Ra[2,1]')
Conf3 <- mxCI ('Ra[3,1]')
Conf4 <- mxCI ('Rc[2,1]')
Conf5 <- mxCI ('Rc[3,1]')
Conf6 <- mxCI ('Re[2,1]')
Conf7 <- mxCI ('Re[3,1]')
AceModel1 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf1) #
AceModel2 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf2) #
AceModel3 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf3) #
AceModel4 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf4) #
AceModel5 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf5) #
AceModel6 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf6) #
AceModel7 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf7) #
# ------------------------------------------------------------------------------
# 3) RUN AceModel
AceFit1 <- mxTryHardOrdinal(AceModel1, intervals=T) #best fit -2lnL should be 40393.31
AceFit2 <- mxTryHardOrdinal(AceModel2, intervals=T) #best fit -2lnL should be 40393.31
AceFit3 <- mxTryHardOrdinal(AceModel3, intervals=T) #best fit -2lnL should be 40393.31
AceFit4 <- mxTryHardOrdinal(AceModel4, intervals=T) #best fit -2lnL should be 40393.31
AceFit5 <- mxTryHardOrdinal(AceModel5, intervals=T) #best fit -2lnL should be 40393.31
AceFit6 <- mxTryHardOrdinal(AceModel6, intervals=T) #best fit -2lnL should be 40393.31
AceFit7 <- mxTryHardOrdinal(AceModel7, intervals=T) #best fit -2lnL should be 40393.31
(AceSum1 <- summary(AceFit1,verbose=T))
(AceSum2 <- summary(AceFit2,verbose=T))
(AceSum3 <- summary(AceFit3,verbose=T))
(AceSum4 <- summary(AceFit4,verbose=T))
(AceSum5 <- summary(AceFit5,verbose=T))
(AceSum6 <- summary(AceFit6,verbose=T))
(AceSum7 <- summary(AceFit7,verbose=T))
#get the estimates and CIs
CI1 <- AceSum1$CI
CI2 <- AceSum2$CI
CI3 <- AceSum3$CI
CI4 <- AceSum4$CI
CI5 <- AceSum5$CI
CI6 <- AceSum6$CI
CI7 <- AceSum7$CI
tot_CI<-rbind(CI1,CI2,CI3,CI4,CI5,CI6,CI7)
#evaluate the contents
mxEval(MZ.ExpCovMZ, AceFit1)
mxEval(DZ.ExpCovDZ, AceFit1)
mxEval(ACE.h2, AceFit1)
mxEval(ACE.c2, AceFit1)
mxEval(ACE.e2, AceFit1)
mxEval(ACE.Ra, AceFit1)
mxEval(ACE.Rc, AceFit1)
mxEval(ACE.Re, AceFit1)
mxEval(ACE.Rph, AceFit1)
mxEval(ACE.RphACE_cANX_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1]*100
mxEval(ACE.RphACE_cANX_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1]*100
mxEval(ACE.V,AceFit1)
#get the proportion explained by A,C and E in the phenotypic correlation
proportion<-as.data.frame(rbind((mxEval(ACE.RphACE_cANX_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1])*100,
(mxEval(ACE.RphACE_cANX_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1])*100,
mxEval(ACE.RphACE_cANX_NSSH, AceFit1),
mxEval(ACE.RphACE_cANX_SSH, AceFit1)),
row.names=c("NSSH%","SSH%", "NSSH","SSH"))
colnames(proportion)<-c("A","C","E")
proportion
#constrain the model
Sub1Model <- mxModel(AceModel1, name="sub1",
mxConstraint(MZ.rA_NSSH_cANX==MZ.rA_SSH_cANX, name="rA_con"),
mxConstraint(MZ.rC_NSSH_cANX==MZ.rC_SSH_cANX, name="rC_con"),
mxConstraint(MZ.rE_NSSH_cANX==MZ.rE_SSH_cANX, name="rE_con"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = F)
(Sub1Sum <- summary(Sub1Fit))
mxEval(MZ.NSSH_a,Sub1Fit);mxEval(MZ.SSH_a,Sub1Fit)
mxEval(MZ.NSSH_c,Sub1Fit);mxEval(MZ.SSH_c,Sub1Fit)
mxEval(MZ.NSSH_e,Sub1Fit);mxEval(MZ.SSH_e,Sub1Fit)
mxEval(MZ.path_a,Sub1Fit);mxEval(MZ.path_c,Sub1Fit);mxEval(MZ.path_e,Sub1Fit)
mxEval(MZ.Ra,Sub1Fit);mxEval(MZ.Rc,Sub1Fit);mxEval(MZ.Re,Sub1Fit)
mxEval(MZ.h2,Sub1Fit)
### compare with ACE model
comparison <- mxCompare(AceFit1,Sub1Fit)
library(xlsx)
## 6) save the results
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_cANX_SLSQP_ACE_04_June_2020.RData")
# save the estimates and their confidence intervals
write.xlsx(tot_CI, file="trivariate_estimates_with_CI_04_June_2020.xlsx",
sheetName="cANX", append=TRUE)
# save the proportions
write.xlsx(proportion, file="trivariate_proportion_04_June_2020.xlsx",
sheetName="cANX", append=TRUE)
# save the results of the chi-square test
write.xlsx(comparison, file="trivariate_constrained_results_04_June_2020.xlsx",
sheetName="cANX", append=TRUE)
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
str(self_harm_data);class(self_harm_data)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,ppbhanxt1,ppbhanxt2,x3zygos,u1cage1,u1cage2,pcbhage1,pcbhage2, sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
self_harm_data_c <- mutate(self_harm_data_c, age_161 = ifelse(is.na(pcbhage1),pcbhage2 , pcbhage1))
self_harm_data_c <- mutate(self_harm_data_c, age_162 = ifelse(is.na(pcbhage2),pcbhage1 , pcbhage2))
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$SSH1)
table(self_harm_data_c$SSH2)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
str(self_harm_data_c)
#******************************************************
# Regress out age, sex and transform pANX variable
#******************************************************
#**Regressing out age & sex **#
self_harm_data_c$respANX1 <- residuals(lm(self_harm_data_c$ppbhanxt1 ~ self_harm_data_c$age_161 + self_harm_data_c$sex1, na.action="na.exclude"))
self_harm_data_c$respANX2 <- residuals(lm(self_harm_data_c$ppbhanxt2 ~ self_harm_data_c$age_162 + self_harm_data_c$sex2, na.action="na.exclude"))
hist(self_harm_data_c$ppbhanxt1)
hist(self_harm_data_c$respANX1)
describe(self_harm_data_c$respANX1)
# #transform the data to get a normal distribution
self_harm_data_c$trans_respANX1 <-((self_harm_data_c$respANX1)^(1/3))*2.5
self_harm_data_c$trans_respANX2 <-((self_harm_data_c$respANX2)^(1/3))*2.5
hist(self_harm_data_c$respANX1)
hist(self_harm_data_c$trans_respANX1)
describe(self_harm_data_c$trans_respANX1)
library(polycor) #check phenotypic correlation
hetcor(self_harm_data_c$trans_respANX1, self_harm_data_c$NSSH1)$correlations #0.13
hetcor(self_harm_data_c$respANX1, self_harm_data_c$NSSH1)$correlations #0.15
hetcor(self_harm_data_c$ppbhanxt1, self_harm_data_c$NSSH1)$correlations #without covariates, 0.17
hetcor(self_harm_data_c$SSH1, self_harm_data_c$NSSH1)$correlations # 0.87, same as in other less complex models.
vars <-c('pANX','NSSH', 'SSH')
selVars <-c('trans_respANX1', 'NSSH1', 'SSH1', 'trans_respANX2', 'NSSH2', 'SSH2')
useVars <-c('trans_respANX1', 'NSSH1', 'SSH1', 'trans_respANX2', 'NSSH2', 'SSH2', 'age1', 'age2', 'sex1','sex2')
# Select Data for Analysis
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars)
describe(mzData)
describe(dzData)
nv <- 3 # number of variables per twin
nvo <-2 #number of ordinal variables per twin
nvc <-nv-nvo #number of continuous variables per twin
poso <- nvc+1 #position where ordinal variables start
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
nlower <- ntv*(ntv+1)/2 # number of free elements in a lower matrix ntv*ntv
ncor <-(nv*(nv+1)/2)-nv # number of free elements in a correlation matrix nv*nv
ninc <- nth-1 #number of max increments
ncovariates <- 2 #number of covariates
### Create starting values for covariance matrix
SHData_for_stv<-self_harm_data_c%>%
select('trans_respANX1', 'NSSH1', 'SSH1', 'trans_respANX2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(SHData_for_stv)
mzData_for_stv<-mzData%>%
select('trans_respANX1', 'NSSH1', 'SSH1', 'trans_respANX2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(mzData_for_stv)
dzData_for_stv<-dzData%>%
select('trans_respANX1', 'NSSH1', 'SSH1', 'trans_respANX2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(dzData_for_stv)
jiggle <-rnorm(nlower, mean = 0, sd = .1)
MZmean <-colMeans(mzData_for_stv,na.rm=TRUE)
DZmean <-colMeans(dzData_for_stv,na.rm=TRUE)
StMZmean<- c(mean(MZmean[c(1,4)]),0,0,mean(MZmean[c(1,4)]),0,0)
StDZmean<- c(mean(DZmean[c(1,4)]),0,0,mean(DZmean[c(1,4)]),0,0)
Stsd <-mean(sapply(mzData_for_stv[,c(1,4)],sd, na.rm=TRUE))
StWithinperson <-vechs(cor(SHData_for_stv[,1:3],use="pairwise"))
StBetweenMZ <-vech(cor(mzData_for_stv[,1:3],mzData_for_stv[,4:6],use="pairwise"))
StBetweenDZ <-vech(cor(dzData_for_stv[,1:3],dzData_for_stv[,4:6],use="pairwise"))
str(self_harm_data_c)
# 2) Specify ACE Model, with ONE overall set of Means, ONE overall Threshold on IQ liability
# To create Labels for Lower Triangular Matrices
StTH <-c(-0.32,0.45,0.19,0.15,0.70,0.54,0.24,0.15)
aLabs <- paste("a", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
cLabs <- paste("c", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
eLabs <- paste("e", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13','Tmz_21','imz_21','imz_22','imz_23') # THs for var 1 and 2 for a
LabCovA <-c('BageThNSSH', 'BageThNSSH','BageThNSSH', 'BageThNSSH', 'BageThSSH', 'BageThSSH','BageThSSH', 'BageThSSH')
LabCovS <-c('BsexThNSSH', 'BsexThNSSH','BsexThNSSH', 'BsexThNSSH', 'BsexThSSH', 'BsexThSSH','BsexThSSH', 'BsexThSSH')
# Matrices to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.64,0.25,0.14,0.72,0.62,0.23), labels=aLabs, name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.30,0.15,0.19,0.01,0.01,0.01), labels=cLabs, name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.84,0.03,0.12,0.67,0.50,0.42), labels=eLabs, name="e" )
# # Define definition variables to hold the Covariates
obsAge1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Age1")
obsAge2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Age2")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#effect of age and sex on ordinal variable
betaA <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovA, name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovS, name="BsexTH" )
#mean and thresholds
Mean <-mxMatrix( "Full", 1, ntv, free=c(T,F,F,T,F,F), values=StMZmean, labels=c("m1", NA,NA, "m1", NA,NA), name="ExpMean" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=StTH, lbound=c(-4,0.001,0.001,0.001), ubound=c(4,4),
labels=LabThMZ, name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH%x%Age1 + BsexTH%x%Sex1,
Low%*%Th + BageTH%x%Age2 + BsexTH%x%Sex2),
name="ExpThres")
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
# Algebra to compute standardized variance components
covP <- mxAlgebra( expression=A+C+E, name="V" )
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Constraint on total variance of Ordinal variable (A+C+E=1)
varL1 <- mxConstraint( expression=V[2,2]==1, name="L1" )
varL2 <- mxConstraint( expression=V[3,3]==1, name="L2" )
# Algebra to compute Rph-A, Rph-C & Rph-E between pANX-NSSH
rphace_pANX_NSSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE_pANX_NSSH" )
rphace_pANX_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[3,1]*sqrt(h2[3,3])),
(sqrt(c2[1,1])*Rc[3,1]*sqrt(c2[3,3])),
(sqrt(e2[1,1])*Re[3,1]*sqrt(e2[3,3])) ), name="RphACE_pANX_SSH" )
rphace_NSSH_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[2,2])*Ra[3,2]*sqrt(h2[3,3])),
(sqrt(c2[2,2])*Rc[3,2]*sqrt(c2[3,3])),
(sqrt(e2[2,2])*Re[3,2]*sqrt(e2[3,3])) ), name="RphACE_NSSH_SSH" )
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[2,2], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[3,3], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[2,2], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[3,3], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[2,2], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[3,3], name="SSH_e")
#rA
raNSSHpANX<-mxAlgebra(expression=Ra[2,1], name="rA_NSSH_pANX")
raSSHpANX<-mxAlgebra(expression=Ra[3,1], name="rA_SSH_pANX")
#rC
rcNSSHpANX<-mxAlgebra(expression=Rc[2,1], name="rC_NSSH_pANX")
rcSSHpANX<-mxAlgebra(expression=Rc[3,1], name="rC_SSH_pANX")
#rE
reNSSHpANX<-mxAlgebra(expression=Re[2,1], name="rE_NSSH_pANX")
reSSHpANX<-mxAlgebra(expression=Re[3,1], name="rE_SSH_pANX")
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="ExpCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, StA, StC, StE, matI, rph, rA, rC, rE,
rphace_pANX_NSSH,rphace_pANX_SSH,rphace_NSSH_SSH,
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2,
raNSSHpANX,raSSHpANX,rcNSSHpANX,rcSSHpANX,reNSSHpANX,reSSHpANX)
modelMZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covMZ, dataMZ, objMZ, fitFunction, varL1, varL2, name="MZ" )
modelDZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
#confidence intervals
Conf1 <- mxCI (c('Rph[2,1]','Rph[3,1]'))
Conf2 <- mxCI ('Ra[2,1]')
Conf3 <- mxCI ('Ra[3,1]')
Conf4 <- mxCI ('Rc[2,1]')
Conf5 <- mxCI ('Rc[3,1]')
Conf6 <- mxCI ('Re[2,1]')
Conf7 <- mxCI ('Re[3,1]')
AceModel1 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf1) #
AceModel2 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf2) #
AceModel3 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf3) #
AceModel4 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf4) #
AceModel5 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf5) #
AceModel6 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf6) #
AceModel7 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf7) #
# 3) RUN AceModel
AceFit1 <- mxTryHardOrdinal(AceModel1, intervals=T) #best fit -2lnL should be 40393.31
AceFit2 <- mxTryHardOrdinal(AceModel2, intervals=T) #best fit -2lnL should be 40393.31
AceFit3 <- mxTryHardOrdinal(AceModel3, intervals=T) #best fit -2lnL should be 40393.31
AceFit4 <- mxTryHardOrdinal(AceModel4, intervals=T) #best fit -2lnL should be 40393.31
AceFit5 <- mxTryHardOrdinal(AceModel5, intervals=T) #best fit -2lnL should be 40393.31
AceFit6 <- mxTryHardOrdinal(AceModel6, intervals=T) #best fit -2lnL should be 40393.31
AceFit7 <- mxTryHardOrdinal(AceModel7, intervals=T) #best fit -2lnL should be 40393.31
(AceSum1 <- summary(AceFit1,verbose=T))
(AceSum2 <- summary(AceFit2,verbose=T))
(AceSum3 <- summary(AceFit3,verbose=T))
(AceSum4 <- summary(AceFit4,verbose=T))
(AceSum5 <- summary(AceFit5,verbose=T))
(AceSum6 <- summary(AceFit6,verbose=T))
(AceSum7 <- summary(AceFit7,verbose=T))
#get the estimates and CIs
CI1 <- AceSum1$CI
CI2 <- AceSum2$CI
CI3 <- AceSum3$CI
CI4 <- AceSum4$CI
CI5 <- AceSum5$CI
CI6 <- AceSum6$CI
CI7 <- AceSum7$CI
tot_CI<-rbind(CI1,CI2,CI3,CI4,CI5,CI6,CI7)
#evaluate the contents
mxEval(MZ.ExpCovMZ, AceFit1)
mxEval(DZ.ExpCovDZ, AceFit1)
mxEval(ACE.h2, AceFit1)
mxEval(ACE.c2, AceFit1)
mxEval(ACE.e2, AceFit1)
mxEval(ACE.Ra, AceFit1)
mxEval(ACE.Rc, AceFit1)
mxEval(ACE.Re, AceFit1)
mxEval(ACE.Rph, AceFit1)
mxEval(ACE.RphACE_pANX_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1]*100
mxEval(ACE.RphACE_pANX_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1]*100
mxEval(ACE.V,AceFit1)
#get the proportion explained by A,C and E in the phenotypic correlation
proportion<-as.data.frame(rbind((mxEval(ACE.RphACE_pANX_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1])*100,
(mxEval(ACE.RphACE_pANX_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1])*100,
mxEval(ACE.RphACE_pANX_NSSH, AceFit1),
mxEval(ACE.RphACE_pANX_SSH, AceFit1)),
row.names=c("NSSH%","SSH%", "NSSH","SSH"))
colnames(proportion)<-c("A","C","E")
proportion
#constrain the model
Sub1Model <- mxModel(AceModel1, name="sub1",
mxConstraint(MZ.rA_NSSH_pANX==MZ.rA_SSH_pANX, name="rA_con"),
mxConstraint(MZ.rC_NSSH_pANX==MZ.rC_SSH_pANX, name="rC_con"),
mxConstraint(MZ.rE_NSSH_pANX==MZ.rE_SSH_pANX, name="rE_con"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = F)
(Sub1Sum <- summary(Sub1Fit))
mxEval(MZ.NSSH_a,Sub1Fit);mxEval(MZ.SSH_a,Sub1Fit)
mxEval(MZ.NSSH_c,Sub1Fit);mxEval(MZ.SSH_c,Sub1Fit)
mxEval(MZ.NSSH_e,Sub1Fit);mxEval(MZ.SSH_e,Sub1Fit)
mxEval(MZ.path_a,Sub1Fit);mxEval(MZ.path_c,Sub1Fit);mxEval(MZ.path_e,Sub1Fit)
mxEval(MZ.Ra,Sub1Fit);mxEval(MZ.Rc,Sub1Fit);mxEval(MZ.Re,Sub1Fit)
mxEval(MZ.h2,Sub1Fit)
### compare with ACE model
comparison <- mxCompare(AceFit1,Sub1Fit)
library(xlsx)
## 6) save the results
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_pANX_SLSQP_ACE_04_June_2020.RData")
# save the estimates and their confidence intervals
write.xlsx(tot_CI, file="trivariate_estimates_with_CI_04_June_2020.xlsx",
sheetName="pANX", append=TRUE)
# save the proportions
write.xlsx(proportion, file="trivariate_proportion_04_June_2020.xlsx",
sheetName="pANX", append=TRUE)
# save the results of the chi-square test
write.xlsx(comparison, file="trivariate_constrained_results_04_June_2020.xlsx",
sheetName="pANX", append=TRUE)
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
str(self_harm_data);class(self_harm_data)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,pcbhinsomt1,pcbhinsomt2,x3zygos,u1cage1,u1cage2,pcbhage1,pcbhage2, sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
self_harm_data_c <- mutate(self_harm_data_c, age_161 = ifelse(is.na(pcbhage1),pcbhage2 , pcbhage1))
self_harm_data_c <- mutate(self_harm_data_c, age_162 = ifelse(is.na(pcbhage2),pcbhage1 , pcbhage2))
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$SSH1)
table(self_harm_data_c$SSH2)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
str(self_harm_data_c)
#******************************************************
# Regress out age, sex and transform cINSOM variable
#******************************************************
#**Regressing out age & sex **#
self_harm_data_c$rescINSOM1 <- residuals(lm(self_harm_data_c$pcbhinsomt1 ~ self_harm_data_c$age_161 + self_harm_data_c$sex1, na.action="na.exclude"))
self_harm_data_c$rescINSOM2 <- residuals(lm(self_harm_data_c$pcbhinsomt2 ~ self_harm_data_c$age_162 + self_harm_data_c$sex2, na.action="na.exclude"))
hist(self_harm_data_c$pcbhinsomt1)
hist(self_harm_data_c$rescINSOM1)
describe(self_harm_data_c$rescINSOM1)
# #transform the data to get a normal distribution
self_harm_data_c$trans_rescINSOM1 <-log(self_harm_data_c$rescINSOM1+5.5)*1.5
self_harm_data_c$trans_rescINSOM2 <-log(self_harm_data_c$rescINSOM2+5.5)*1.5
hist(self_harm_data_c$rescINSOM1)
hist(self_harm_data_c$trans_rescINSOM1)
boxplot(self_harm_data_c$trans_rescINSOM1) #there is one outlier?
boxplot(self_harm_data_c$rescINSOM1)
describe(self_harm_data_c$trans_rescINSOM1)
library(polycor) #check phenotypic correlation
hetcor(self_harm_data_c$trans_rescINSOM1, self_harm_data_c$NSSH1)$correlations #0.23
hetcor(self_harm_data_c$rescINSOM1, self_harm_data_c$NSSH1)$correlations #0.22
hetcor(self_harm_data_c$pcbhinsomt1, self_harm_data_c$NSSH1)$correlations #without covariates, 0.25
hetcor(self_harm_data_c$SSH1, self_harm_data_c$NSSH1)$correlations # 0.87, same as in other less complex models.
vars <-c('cINSOM','NSSH', 'SSH')
selVars <-c('trans_rescINSOM1', 'NSSH1', 'SSH1', 'trans_rescINSOM2', 'NSSH2', 'SSH2')
useVars <-c('trans_rescINSOM1', 'NSSH1', 'SSH1', 'trans_rescINSOM2', 'NSSH2', 'SSH2', 'age1', 'age2', 'sex1','sex2')
# Select Data for Analysis
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars)
describe(mzData)
describe(dzData)
nv <- 3 # number of variables per twin
nvo <-2 #number of ordinal variables per twin
nvc <-nv-nvo #number of continuous variables per twin
poso <- nvc+1 #position where ordinal variables start
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
nlower <- ntv*(ntv+1)/2 # number of free elements in a lower matrix ntv*ntv
ncor <-(nv*(nv+1)/2)-nv # number of free elements in a correlation matrix nv*nv
ninc <- nth-1 #number of max increments
ncovariates <- 2 #number of covariates
### Create starting values for covariance matrix
SHData_for_stv<-self_harm_data_c%>%
select('trans_rescINSOM1', 'NSSH1', 'SSH1', 'trans_rescINSOM2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(SHData_for_stv)
mzData_for_stv<-mzData%>%
select('trans_rescINSOM1', 'NSSH1', 'SSH1', 'trans_rescINSOM2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(mzData_for_stv)
dzData_for_stv<-dzData%>%
select('trans_rescINSOM1', 'NSSH1', 'SSH1', 'trans_rescINSOM2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(dzData_for_stv)
jiggle <-rnorm(nlower, mean = 0, sd = .1)
MZmean <-colMeans(mzData_for_stv,na.rm=TRUE)
DZmean <-colMeans(dzData_for_stv,na.rm=TRUE)
StMZmean<- c(mean(MZmean[c(1,4)]),0,0,mean(MZmean[c(1,4)]),0,0)
StDZmean<- c(mean(DZmean[c(1,4)]),0,0,mean(DZmean[c(1,4)]),0,0)
Stsd <-mean(sapply(mzData_for_stv[,c(1,4)],sd, na.rm=TRUE))
StWithinperson <-vechs(cor(SHData_for_stv[,1:3],use="pairwise"))
StBetweenMZ <-vech(cor(mzData_for_stv[,1:3],mzData_for_stv[,4:6],use="pairwise"))
StBetweenDZ <-vech(cor(dzData_for_stv[,1:3],dzData_for_stv[,4:6],use="pairwise"))
str(self_harm_data_c)
# 2) Specify ACE Model, with ONE overall set of Means, ONE overall Threshold on IQ liability
# To create Labels for Lower Triangular Matrices
StTH <-c(-0.32,0.45,0.19,0.15,0.70,0.54,0.24,0.15)
aLabs <- paste("a", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
cLabs <- paste("c", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
eLabs <- paste("e", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13','Tmz_21','imz_21','imz_22','imz_23') # THs for var 1 and 2 for a
LabCovA <-c('BageThNSSH', 'BageThNSSH','BageThNSSH', 'BageThNSSH', 'BageThSSH', 'BageThSSH','BageThSSH', 'BageThSSH')
LabCovS <-c('BsexThNSSH', 'BsexThNSSH','BsexThNSSH', 'BsexThNSSH', 'BsexThSSH', 'BsexThSSH','BsexThSSH', 'BsexThSSH')
# Matrices to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.64,0.25,0.14,0.72,0.62,0.23), labels=aLabs, name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.30,0.15,0.19,0.01,0.01,0.01), labels=cLabs, name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.84,0.03,0.12,0.67,0.50,0.42), labels=eLabs, name="e" )
# # Define definition variables to hold the Covariates
obsAge1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Age1")
obsAge2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Age2")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#effect of age and sex on ordinal variable
betaA <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovA, name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovS, name="BsexTH" )
#mean and thresholds
Mean <-mxMatrix( "Full", 1, ntv, free=c(T,F,F,T,F,F), values=StMZmean, labels=c("m1", NA,NA, "m1", NA,NA), name="ExpMean" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=StTH, lbound=c(-4,0.001,0.001,0.001), ubound=c(4,4),
labels=LabThMZ, name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH%x%Age1 + BsexTH%x%Sex1,
Low%*%Th + BageTH%x%Age2 + BsexTH%x%Sex2),
name="ExpThres")
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
# Algebra to compute standardized variance components
covP <- mxAlgebra( expression=A+C+E, name="V" )
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Constraint on total variance of Ordinal variable (A+C+E=1)
varL1 <- mxConstraint( expression=V[2,2]==1, name="L1" )
varL2 <- mxConstraint( expression=V[3,3]==1, name="L2" )
# Algebra to compute Rph-A, Rph-C & Rph-E between cINSOM-NSSH
rphace_cINSOM_NSSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE_cINSOM_NSSH" )
rphace_cINSOM_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[3,1]*sqrt(h2[3,3])),
(sqrt(c2[1,1])*Rc[3,1]*sqrt(c2[3,3])),
(sqrt(e2[1,1])*Re[3,1]*sqrt(e2[3,3])) ), name="RphACE_cINSOM_SSH" )
rphace_NSSH_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[2,2])*Ra[3,2]*sqrt(h2[3,3])),
(sqrt(c2[2,2])*Rc[3,2]*sqrt(c2[3,3])),
(sqrt(e2[2,2])*Re[3,2]*sqrt(e2[3,3])) ), name="RphACE_NSSH_SSH" )
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[2,2], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[3,3], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[2,2], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[3,3], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[2,2], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[3,3], name="SSH_e")
#rA
raNSSHcINSOM<-mxAlgebra(expression=Ra[2,1], name="rA_NSSH_cINSOM")
raSSHcINSOM<-mxAlgebra(expression=Ra[3,1], name="rA_SSH_cINSOM")
#rC
rcNSSHcINSOM<-mxAlgebra(expression=Rc[2,1], name="rC_NSSH_cINSOM")
rcSSHcINSOM<-mxAlgebra(expression=Rc[3,1], name="rC_SSH_cINSOM")
#rE
reNSSHcINSOM<-mxAlgebra(expression=Re[2,1], name="rE_NSSH_cINSOM")
reSSHcINSOM<-mxAlgebra(expression=Re[3,1], name="rE_SSH_cINSOM")
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="ExpCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, StA, StC, StE, matI, rph, rA, rC, rE,
rphace_cINSOM_NSSH,rphace_cINSOM_SSH,rphace_NSSH_SSH,
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2,
raNSSHcINSOM,raSSHcINSOM,rcNSSHcINSOM,rcSSHcINSOM,reNSSHcINSOM,reSSHcINSOM)
modelMZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covMZ, dataMZ, objMZ, fitFunction, varL1, varL2, name="MZ" )
modelDZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
#confidence intervals
Conf1 <- mxCI (c('Rph[2,1]','Rph[3,1]'))
Conf2 <- mxCI ('Ra[2,1]')
Conf3 <- mxCI ('Ra[3,1]')
Conf4 <- mxCI ('Rc[2,1]')
Conf5 <- mxCI ('Rc[3,1]')
Conf6 <- mxCI ('Re[2,1]')
Conf7 <- mxCI ('Re[3,1]')
AceModel1 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf1) #
AceModel2 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf2) #
AceModel3 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf3) #
AceModel4 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf4) #
AceModel5 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf5) #
AceModel6 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf6) #
AceModel7 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf7) #
# 3) RUN AceModel
AceFit1 <- mxTryHardOrdinal(AceModel1, intervals=T) #best fit -2lnL should be 40393.31
AceFit2 <- mxTryHardOrdinal(AceModel2, intervals=T) #best fit -2lnL should be 40393.31
AceFit3 <- mxTryHardOrdinal(AceModel3, intervals=T) #best fit -2lnL should be 40393.31
AceFit4 <- mxTryHardOrdinal(AceModel4, intervals=T) #best fit -2lnL should be 40393.31
AceFit5 <- mxTryHardOrdinal(AceModel5, intervals=T) #best fit -2lnL should be 40393.31
AceFit6 <- mxTryHardOrdinal(AceModel6, intervals=T) #best fit -2lnL should be 40393.31
AceFit7 <- mxTryHardOrdinal(AceModel7, intervals=T) #best fit -2lnL should be 40393.31
(AceSum1 <- summary(AceFit1,verbose=T))
(AceSum2 <- summary(AceFit2,verbose=T))
(AceSum3 <- summary(AceFit3,verbose=T))
(AceSum4 <- summary(AceFit4,verbose=T))
(AceSum5 <- summary(AceFit5,verbose=T))
(AceSum6 <- summary(AceFit6,verbose=T))
(AceSum7 <- summary(AceFit7,verbose=T))
#get the estimates and CIs
CI1 <- AceSum1$CI
CI2 <- AceSum2$CI
CI3 <- AceSum3$CI
CI4 <- AceSum4$CI
CI5 <- AceSum5$CI
CI6 <- AceSum6$CI
CI7 <- AceSum7$CI
tot_CI<-rbind(CI1,CI2,CI3,CI4,CI5,CI6,CI7)
#evaluate the contents
mxEval(MZ.ExpCovMZ, AceFit1)
mxEval(DZ.ExpCovDZ, AceFit1)
mxEval(ACE.h2, AceFit1)
mxEval(ACE.c2, AceFit1)
mxEval(ACE.e2, AceFit1)
mxEval(ACE.Ra, AceFit1)
mxEval(ACE.Rc, AceFit1)
mxEval(ACE.Re, AceFit1)
mxEval(ACE.Rph, AceFit1)
mxEval(ACE.RphACE_cINSOM_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1]*100
mxEval(ACE.RphACE_cINSOM_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1]*100
mxEval(ACE.V,AceFit1)
#get the proportion explained by A,C and E in the phenotypic correlation
proportion<-as.data.frame(rbind((mxEval(ACE.RphACE_cINSOM_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1])*100,
(mxEval(ACE.RphACE_cINSOM_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1])*100,
mxEval(ACE.RphACE_cINSOM_NSSH, AceFit1),
mxEval(ACE.RphACE_cINSOM_SSH, AceFit1)),
row.names=c("NSSH%","SSH%", "NSSH","SSH"))
colnames(proportion)<-c("A","C","E")
proportion
#constrain the model
Sub1Model <- mxModel(AceModel1, name="sub1",
mxConstraint(MZ.rA_NSSH_cINSOM==MZ.rA_SSH_cINSOM, name="rA_con"),
mxConstraint(MZ.rC_NSSH_cINSOM==MZ.rC_SSH_cINSOM, name="rC_con"),
mxConstraint(MZ.rE_NSSH_cINSOM==MZ.rE_SSH_cINSOM, name="rE_con"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = F)
(Sub1Sum <- summary(Sub1Fit))
mxEval(MZ.NSSH_a,Sub1Fit);mxEval(MZ.SSH_a,Sub1Fit)
mxEval(MZ.NSSH_c,Sub1Fit);mxEval(MZ.SSH_c,Sub1Fit)
mxEval(MZ.NSSH_e,Sub1Fit);mxEval(MZ.SSH_e,Sub1Fit)
mxEval(MZ.path_a,Sub1Fit);mxEval(MZ.path_c,Sub1Fit);mxEval(MZ.path_e,Sub1Fit)
mxEval(MZ.Ra,Sub1Fit);mxEval(MZ.Rc,Sub1Fit);mxEval(MZ.Re,Sub1Fit)
mxEval(MZ.h2,Sub1Fit)
### compare with ACE model
comparison <- mxCompare(AceFit1,Sub1Fit)
library(xlsx)
## 6) save the results
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_cINSOM_SLSQP_ACE_04_June_2020.RData")
# save the estimates and their confidence intervals
write.xlsx(tot_CI, file="trivariate_estimates_with_CI_04_June_2020.xlsx",
sheetName="cINSOM", append=TRUE)
# save the proportions
write.xlsx(proportion, file="trivariate_proportion_04_June_2020.xlsx",
sheetName="cINSOM", append=TRUE)
# save the results of the chi-square test
write.xlsx(comparison, file="trivariate_constrained_results_04_June_2020.xlsx",
sheetName="cINSOM", append=TRUE)
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
str(self_harm_data);class(self_harm_data)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,pcbheddsm1,pcbheddsm2,x3zygos,u1cage1,u1cage2,pcbhage1,pcbhage2, sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
self_harm_data_c <- mutate(self_harm_data_c, age_161 = ifelse(is.na(pcbhage1),pcbhage2 , pcbhage1))
self_harm_data_c <- mutate(self_harm_data_c, age_162 = ifelse(is.na(pcbhage2),pcbhage1 , pcbhage2))
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$SSH1)
table(self_harm_data_c$SSH2)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
str(self_harm_data_c)
#******************************************************
# Regress out age, sex and transform cEAT variable
#******************************************************
#**Regressing out age & sex **#
self_harm_data_c$rescEAT1 <- residuals(lm(self_harm_data_c$pcbheddsm1 ~ self_harm_data_c$age_161 + self_harm_data_c$sex1, na.action="na.exclude"))
self_harm_data_c$rescEAT2 <- residuals(lm(self_harm_data_c$pcbheddsm2 ~ self_harm_data_c$age_162 + self_harm_data_c$sex2, na.action="na.exclude"))
hist(self_harm_data_c$pcbheddsm1)
hist(self_harm_data_c$rescEAT1)
describe(self_harm_data_c$rescEAT1)
# #transform the data to get a normal distribution
self_harm_data_c$trans_rescEAT1 <-(self_harm_data_c$rescEAT1)
self_harm_data_c$trans_rescEAT2 <-(self_harm_data_c$rescEAT2)
hist(self_harm_data_c$rescEAT1)
hist(self_harm_data_c$trans_rescEAT1)
describe(self_harm_data_c$trans_rescEAT1)
library(polycor) #check phenotypic correlation
hetcor(self_harm_data_c$trans_rescEAT1, self_harm_data_c$NSSH1)$correlations #0.23
hetcor(self_harm_data_c$rescEAT1, self_harm_data_c$NSSH1)$correlations #0.22
hetcor(self_harm_data_c$pcbheddsm1, self_harm_data_c$NSSH1)$correlations #without covariates, 0.25
hetcor(self_harm_data_c$SSH1, self_harm_data_c$NSSH1)$correlations # 0.87, same as in other less complex models.
vars <-c('cEAT','NSSH', 'SSH')
selVars <-c('trans_rescEAT1', 'NSSH1', 'SSH1', 'trans_rescEAT2', 'NSSH2', 'SSH2')
useVars <-c('trans_rescEAT1', 'NSSH1', 'SSH1', 'trans_rescEAT2', 'NSSH2', 'SSH2', 'age1', 'age2', 'sex1','sex2')
# Select Data for Analysis
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars)
describe(mzData)
describe(dzData)
nv <- 3 # number of variables per twin
nvo <-2 #number of ordinal variables per twin
nvc <-nv-nvo #number of continuous variables per twin
poso <- nvc+1 #position where ordinal variables start
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
nlower <- ntv*(ntv+1)/2 # number of free elements in a lower matrix ntv*ntv
ncor <-(nv*(nv+1)/2)-nv # number of free elements in a correlation matrix nv*nv
ninc <- nth-1 #number of max increments
ncovariates <- 2 #number of covariates
### Create starting values for covariance matrix
SHData_for_stv<-self_harm_data_c%>%
select('trans_rescEAT1', 'NSSH1', 'SSH1', 'trans_rescEAT2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(SHData_for_stv)
mzData_for_stv<-mzData%>%
select('trans_rescEAT1', 'NSSH1', 'SSH1', 'trans_rescEAT2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(mzData_for_stv)
dzData_for_stv<-dzData%>%
select('trans_rescEAT1', 'NSSH1', 'SSH1', 'trans_rescEAT2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(dzData_for_stv)
jiggle <-rnorm(nlower, mean = 0, sd = .1)
MZmean <-colMeans(mzData_for_stv,na.rm=TRUE)
DZmean <-colMeans(dzData_for_stv,na.rm=TRUE)
StMZmean<- c(mean(MZmean[c(1,4)]),0,0,mean(MZmean[c(1,4)]),0,0)
StDZmean<- c(mean(DZmean[c(1,4)]),0,0,mean(DZmean[c(1,4)]),0,0)
Stsd <-mean(sapply(mzData_for_stv[,c(1,4)],sd, na.rm=TRUE))
StWithinperson <-vechs(cor(SHData_for_stv[,1:3],use="pairwise"))
StBetweenMZ <-vech(cor(mzData_for_stv[,1:3],mzData_for_stv[,4:6],use="pairwise"))
StBetweenDZ <-vech(cor(dzData_for_stv[,1:3],dzData_for_stv[,4:6],use="pairwise"))
str(self_harm_data_c)
# 2) Specify ACE Model, with ONE overall set of Means, ONE overall Threshold on IQ liability
# To create Labels for Lower Triangular Matrices
StTH <-c(-0.32,0.45,0.19,0.15,0.70,0.54,0.24,0.15)
aLabs <- paste("a", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
cLabs <- paste("c", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
eLabs <- paste("e", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13','Tmz_21','imz_21','imz_22','imz_23') # THs for var 1 and 2 for a
LabCovA <-c('BageThNSSH', 'BageThNSSH','BageThNSSH', 'BageThNSSH', 'BageThSSH', 'BageThSSH','BageThSSH', 'BageThSSH')
LabCovS <-c('BsexThNSSH', 'BsexThNSSH','BsexThNSSH', 'BsexThNSSH', 'BsexThSSH', 'BsexThSSH','BsexThSSH', 'BsexThSSH')
# Matrices to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.64,0.25,0.14,0.72,0.62,0.23), labels=aLabs, name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.30,0.15,0.19,0.01,0.01,0.01), labels=cLabs, name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.84,0.03,0.12,0.67,0.50,0.42), labels=eLabs, name="e" )
# # Define definition variables to hold the Covariates
obsAge1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Age1")
obsAge2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Age2")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#effect of age and sex on ordinal variable
betaA <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovA, name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovS, name="BsexTH" )
#mean and thresholds
Mean <-mxMatrix( "Full", 1, ntv, free=c(T,F,F,T,F,F), values=StMZmean, labels=c("m1", NA,NA, "m1", NA,NA), name="ExpMean" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=StTH, lbound=c(-4,0.001,0.001,0.001), ubound=c(4,4),
labels=LabThMZ, name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH%x%Age1 + BsexTH%x%Sex1,
Low%*%Th + BageTH%x%Age2 + BsexTH%x%Sex2),
name="ExpThres")
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
# Algebra to compute standardized variance components
covP <- mxAlgebra( expression=A+C+E, name="V" )
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Constraint on total variance of Ordinal variable (A+C+E=1)
varL1 <- mxConstraint( expression=V[2,2]==1, name="L1" )
varL2 <- mxConstraint( expression=V[3,3]==1, name="L2" )
# Algebra to compute Rph-A, Rph-C & Rph-E between cEAT-NSSH
rphace_cEAT_NSSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE_cEAT_NSSH" )
rphace_cEAT_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[3,1]*sqrt(h2[3,3])),
(sqrt(c2[1,1])*Rc[3,1]*sqrt(c2[3,3])),
(sqrt(e2[1,1])*Re[3,1]*sqrt(e2[3,3])) ), name="RphACE_cEAT_SSH" )
rphace_NSSH_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[2,2])*Ra[3,2]*sqrt(h2[3,3])),
(sqrt(c2[2,2])*Rc[3,2]*sqrt(c2[3,3])),
(sqrt(e2[2,2])*Re[3,2]*sqrt(e2[3,3])) ), name="RphACE_NSSH_SSH" )
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[2,2], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[3,3], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[2,2], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[3,3], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[2,2], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[3,3], name="SSH_e")
#rA
raNSSHcEAT<-mxAlgebra(expression=Ra[2,1], name="rA_NSSH_cEAT")
raSSHcEAT<-mxAlgebra(expression=Ra[3,1], name="rA_SSH_cEAT")
#rC
rcNSSHcEAT<-mxAlgebra(expression=Rc[2,1], name="rC_NSSH_cEAT")
rcSSHcEAT<-mxAlgebra(expression=Rc[3,1], name="rC_SSH_cEAT")
#rE
reNSSHcEAT<-mxAlgebra(expression=Re[2,1], name="rE_NSSH_cEAT")
reSSHcEAT<-mxAlgebra(expression=Re[3,1], name="rE_SSH_cEAT")
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="ExpCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, StA, StC, StE, matI, rph, rA, rC, rE,
rphace_cEAT_NSSH,rphace_cEAT_SSH,rphace_NSSH_SSH,
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2,
raNSSHcEAT,raSSHcEAT,rcNSSHcEAT,rcSSHcEAT,reNSSHcEAT,reSSHcEAT)
modelMZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covMZ, dataMZ, objMZ, fitFunction, varL1, varL2, name="MZ" )
modelDZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
#confidence intervals
Conf1 <- mxCI (c('Rph[2,1]','Rph[3,1]'))
Conf2 <- mxCI ('Ra[2,1]')
Conf3 <- mxCI ('Ra[3,1]')
Conf4 <- mxCI ('Rc[2,1]')
Conf5 <- mxCI ('Rc[3,1]')
Conf6 <- mxCI ('Re[2,1]')
Conf7 <- mxCI ('Re[3,1]')
AceModel1 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf1) #
AceModel2 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf2) #
AceModel3 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf3) #
AceModel4 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf4) #
AceModel5 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf5) #
AceModel6 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf6) #
AceModel7 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf7) #
# 3) RUN AceModel
AceFit1 <- mxTryHardOrdinal(AceModel1, intervals=T) #best fit -2lnL should be 40393.31
AceFit2 <- mxTryHardOrdinal(AceModel2, intervals=T) #best fit -2lnL should be 40393.31
AceFit3 <- mxTryHardOrdinal(AceModel3, intervals=T) #best fit -2lnL should be 40393.31
AceFit4 <- mxTryHardOrdinal(AceModel4, intervals=T) #best fit -2lnL should be 40393.31
AceFit5 <- mxTryHardOrdinal(AceModel5, intervals=T) #best fit -2lnL should be 40393.31
AceFit6 <- mxTryHardOrdinal(AceModel6, intervals=T) #best fit -2lnL should be 40393.31
AceFit7 <- mxTryHardOrdinal(AceModel7, intervals=T) #best fit -2lnL should be 40393.31
(AceSum1 <- summary(AceFit1,verbose=T))
(AceSum2 <- summary(AceFit2,verbose=T))
(AceSum3 <- summary(AceFit3,verbose=T))
(AceSum4 <- summary(AceFit4,verbose=T))
(AceSum5 <- summary(AceFit5,verbose=T))
(AceSum6 <- summary(AceFit6,verbose=T))
(AceSum7 <- summary(AceFit7,verbose=T))
#get the estimates and CIs
CI1 <- AceSum1$CI
CI2 <- AceSum2$CI
CI3 <- AceSum3$CI
CI4 <- AceSum4$CI
CI5 <- AceSum5$CI
CI6 <- AceSum6$CI
CI7 <- AceSum7$CI
tot_CI<-rbind(CI1,CI2,CI3,CI4,CI5,CI6,CI7)
#evaluate the contents
mxEval(MZ.ExpCovMZ, AceFit1)
mxEval(DZ.ExpCovDZ, AceFit1)
mxEval(ACE.h2, AceFit1)
mxEval(ACE.c2, AceFit1)
mxEval(ACE.e2, AceFit1)
mxEval(ACE.Ra, AceFit1)
mxEval(ACE.Rc, AceFit1)
mxEval(ACE.Re, AceFit1)
mxEval(ACE.Rph, AceFit1)
mxEval(ACE.RphACE_cEAT_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1]*100
mxEval(ACE.RphACE_cEAT_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1]*100
mxEval(ACE.V,AceFit1)
#get the proportion explained by A,C and E in the phenotypic correlation
proportion<-as.data.frame(rbind((mxEval(ACE.RphACE_cEAT_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1])*100,
(mxEval(ACE.RphACE_cEAT_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1])*100,
mxEval(ACE.RphACE_cEAT_NSSH, AceFit1),
mxEval(ACE.RphACE_cEAT_SSH, AceFit1)),
row.names=c("NSSH%","SSH%", "NSSH","SSH"))
colnames(proportion)<-c("A","C","E")
proportion
#constrain the model
Sub1Model <- mxModel(AceModel1, name="sub1",
mxConstraint(MZ.rA_NSSH_cEAT==MZ.rA_SSH_cEAT, name="rA_con"),
mxConstraint(MZ.rC_NSSH_cEAT==MZ.rC_SSH_cEAT, name="rC_con"),
mxConstraint(MZ.rE_NSSH_cEAT==MZ.rE_SSH_cEAT, name="rE_con"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = F)
(Sub1Sum <- summary(Sub1Fit))
mxEval(MZ.NSSH_a,Sub1Fit);mxEval(MZ.SSH_a,Sub1Fit)
mxEval(MZ.NSSH_c,Sub1Fit);mxEval(MZ.SSH_c,Sub1Fit)
mxEval(MZ.NSSH_e,Sub1Fit);mxEval(MZ.SSH_e,Sub1Fit)
mxEval(MZ.path_a,Sub1Fit);mxEval(MZ.path_c,Sub1Fit);mxEval(MZ.path_e,Sub1Fit)
mxEval(MZ.Ra,Sub1Fit);mxEval(MZ.Rc,Sub1Fit);mxEval(MZ.Re,Sub1Fit)
mxEval(MZ.h2,Sub1Fit)
### compare with ACE model
comparison <- mxCompare(AceFit1,Sub1Fit)
library(xlsx)
## 6) save the results
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_cEAT_SLSQP_ACE_04_June_2020.RData")
# save the estimates and their confidence intervals
write.xlsx(tot_CI, file="trivariate_estimates_with_CI_04_June_2020.xlsx",
sheetName="cEAT", append=TRUE)
# save the proportions
write.xlsx(proportion, file="trivariate_proportion_04_June_2020.xlsx",
sheetName="cEAT", append=TRUE)
# save the results of the chi-square test
write.xlsx(comparison, file="trivariate_constrained_results_04_June_2020.xlsx",
sheetName="cEAT", append=TRUE)
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
str(self_harm_data);class(self_harm_data)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,pcbhswanm1,pcbhswanm2,x3zygos,u1cage1,u1cage2,pcbhage1,pcbhage2, sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
self_harm_data_c <- mutate(self_harm_data_c, age_161 = ifelse(is.na(pcbhage1),pcbhage2 , pcbhage1))
self_harm_data_c <- mutate(self_harm_data_c, age_162 = ifelse(is.na(pcbhage2),pcbhage1 , pcbhage2))
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$SSH1)
table(self_harm_data_c$SSH2)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
str(self_harm_data_c)
#******************************************************
# Regress out age, sex and transform cSWAN variable
#******************************************************
#**Regressing out age & sex **#
self_harm_data_c$rescSWAN1 <- residuals(lm(self_harm_data_c$pcbhswanm1 ~ self_harm_data_c$age_161 + self_harm_data_c$sex1, na.action="na.exclude"))
self_harm_data_c$rescSWAN2 <- residuals(lm(self_harm_data_c$pcbhswanm2 ~ self_harm_data_c$age_162 + self_harm_data_c$sex2, na.action="na.exclude"))
hist(self_harm_data_c$pcbhswanm1)
hist(self_harm_data_c$rescSWAN1)
describe(self_harm_data_c$rescSWAN1)
# #transform the data to get a normal distribution
self_harm_data_c$trans_rescSWAN1 <-(self_harm_data_c$rescSWAN1)
self_harm_data_c$trans_rescSWAN2 <-(self_harm_data_c$rescSWAN2)
hist(self_harm_data_c$rescSWAN1)
hist(self_harm_data_c$trans_rescSWAN1)
describe(self_harm_data_c$trans_rescSWAN1)
library(polycor) #check phenotypic correlation
hetcor(self_harm_data_c$trans_rescSWAN1, self_harm_data_c$NSSH1)$correlations #0.23
hetcor(self_harm_data_c$rescSWAN1, self_harm_data_c$NSSH1)$correlations #0.22
hetcor(self_harm_data_c$pcbhswanm1, self_harm_data_c$NSSH1)$correlations #without covariates, 0.25
hetcor(self_harm_data_c$SSH1, self_harm_data_c$NSSH1)$correlations # 0.87, same as in other less complex models.
vars <-c('cSWAN','NSSH', 'SSH')
selVars <-c('trans_rescSWAN1', 'NSSH1', 'SSH1', 'trans_rescSWAN2', 'NSSH2', 'SSH2')
useVars <-c('trans_rescSWAN1', 'NSSH1', 'SSH1', 'trans_rescSWAN2', 'NSSH2', 'SSH2', 'age1', 'age2', 'sex1','sex2')
# Select Data for Analysis
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars)
describe(mzData)
describe(dzData)
nv <- 3 # number of variables per twin
nvo <-2 #number of ordinal variables per twin
nvc <-nv-nvo #number of continuous variables per twin
poso <- nvc+1 #position where ordinal variables start
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
nlower <- ntv*(ntv+1)/2 # number of free elements in a lower matrix ntv*ntv
ncor <-(nv*(nv+1)/2)-nv # number of free elements in a correlation matrix nv*nv
ninc <- nth-1 #number of max increments
ncovariates <- 2 #number of covariates
### Create starting values for covariance matrix
SHData_for_stv<-self_harm_data_c%>%
select('trans_rescSWAN1', 'NSSH1', 'SSH1', 'trans_rescSWAN2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(SHData_for_stv)
mzData_for_stv<-mzData%>%
select('trans_rescSWAN1', 'NSSH1', 'SSH1', 'trans_rescSWAN2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(mzData_for_stv)
dzData_for_stv<-dzData%>%
select('trans_rescSWAN1', 'NSSH1', 'SSH1', 'trans_rescSWAN2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(dzData_for_stv)
jiggle <-rnorm(nlower, mean = 0, sd = .1)
MZmean <-colMeans(mzData_for_stv,na.rm=TRUE)
DZmean <-colMeans(dzData_for_stv,na.rm=TRUE)
StMZmean<- c(mean(MZmean[c(1,4)]),0,0,mean(MZmean[c(1,4)]),0,0)
StDZmean<- c(mean(DZmean[c(1,4)]),0,0,mean(DZmean[c(1,4)]),0,0)
Stsd <-mean(sapply(mzData_for_stv[,c(1,4)],sd, na.rm=TRUE))
StWithinperson <-vechs(cor(SHData_for_stv[,1:3],use="pairwise"))
StBetweenMZ <-vech(cor(mzData_for_stv[,1:3],mzData_for_stv[,4:6],use="pairwise"))
StBetweenDZ <-vech(cor(dzData_for_stv[,1:3],dzData_for_stv[,4:6],use="pairwise"))
str(self_harm_data_c)
# 2) Specify ACE Model, with ONE overall set of Means, ONE overall Threshold on IQ liability
# To create Labels for Lower Triangular Matrices
StTH <-c(-0.32,0.45,0.19,0.15,0.70,0.54,0.24,0.15)
aLabs <- paste("a", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
cLabs <- paste("c", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
eLabs <- paste("e", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13','Tmz_21','imz_21','imz_22','imz_23') # THs for var 1 and 2 for a
LabCovA <-c('BageThNSSH', 'BageThNSSH','BageThNSSH', 'BageThNSSH', 'BageThSSH', 'BageThSSH','BageThSSH', 'BageThSSH')
LabCovS <-c('BsexThNSSH', 'BsexThNSSH','BsexThNSSH', 'BsexThNSSH', 'BsexThSSH', 'BsexThSSH','BsexThSSH', 'BsexThSSH')
# Matrices to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.64,0.25,0.14,0.72,0.62,0.23), labels=aLabs, name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.30,0.15,0.19,0.01,0.01,0.01), labels=cLabs, name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.84,0.03,0.12,0.67,0.50,0.42), labels=eLabs, name="e" )
# # Define definition variables to hold the Covariates
obsAge1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Age1")
obsAge2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Age2")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#effect of age and sex on ordinal variable
betaA <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovA, name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovS, name="BsexTH" )
#mean and thresholds
Mean <-mxMatrix( "Full", 1, ntv, free=c(T,F,F,T,F,F), values=StMZmean, labels=c("m1", NA,NA, "m1", NA,NA), name="ExpMean" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=StTH, lbound=c(-4,0.001,0.001,0.001), ubound=c(4,4),
labels=LabThMZ, name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH%x%Age1 + BsexTH%x%Sex1,
Low%*%Th + BageTH%x%Age2 + BsexTH%x%Sex2),
name="ExpThres")
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
# Algebra to compute standardized variance components
covP <- mxAlgebra( expression=A+C+E, name="V" )
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Constraint on total variance of Ordinal variable (A+C+E=1)
varL1 <- mxConstraint( expression=V[2,2]==1, name="L1" )
varL2 <- mxConstraint( expression=V[3,3]==1, name="L2" )
# Algebra to compute Rph-A, Rph-C & Rph-E between cSWAN-NSSH
rphace_cSWAN_NSSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE_cSWAN_NSSH" )
rphace_cSWAN_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[3,1]*sqrt(h2[3,3])),
(sqrt(c2[1,1])*Rc[3,1]*sqrt(c2[3,3])),
(sqrt(e2[1,1])*Re[3,1]*sqrt(e2[3,3])) ), name="RphACE_cSWAN_SSH" )
rphace_NSSH_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[2,2])*Ra[3,2]*sqrt(h2[3,3])),
(sqrt(c2[2,2])*Rc[3,2]*sqrt(c2[3,3])),
(sqrt(e2[2,2])*Re[3,2]*sqrt(e2[3,3])) ), name="RphACE_NSSH_SSH" )
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[2,2], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[3,3], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[2,2], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[3,3], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[2,2], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[3,3], name="SSH_e")
#rA
raNSSHcSWAN<-mxAlgebra(expression=Ra[2,1], name="rA_NSSH_cSWAN")
raSSHcSWAN<-mxAlgebra(expression=Ra[3,1], name="rA_SSH_cSWAN")
#rC
rcNSSHcSWAN<-mxAlgebra(expression=Rc[2,1], name="rC_NSSH_cSWAN")
rcSSHcSWAN<-mxAlgebra(expression=Rc[3,1], name="rC_SSH_cSWAN")
#rE
reNSSHcSWAN<-mxAlgebra(expression=Re[2,1], name="rE_NSSH_cSWAN")
reSSHcSWAN<-mxAlgebra(expression=Re[3,1], name="rE_SSH_cSWAN")
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="ExpCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, StA, StC, StE, matI, rph, rA, rC, rE,
rphace_cSWAN_NSSH,rphace_cSWAN_SSH,rphace_NSSH_SSH,
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2,
raNSSHcSWAN,raSSHcSWAN,rcNSSHcSWAN,rcSSHcSWAN,reNSSHcSWAN,reSSHcSWAN)
modelMZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covMZ, dataMZ, objMZ, fitFunction, varL1, varL2, name="MZ" )
modelDZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
#confidence intervals
Conf1 <- mxCI (c('Rph[2,1]','Rph[3,1]'))
Conf2 <- mxCI ('Ra[2,1]')
Conf3 <- mxCI ('Ra[3,1]')
Conf4 <- mxCI ('Rc[2,1]')
Conf5 <- mxCI ('Rc[3,1]')
Conf6 <- mxCI ('Re[2,1]')
Conf7 <- mxCI ('Re[3,1]')
AceModel1 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf1) #
AceModel2 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf2) #
AceModel3 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf3) #
AceModel4 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf4) #
AceModel5 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf5) #
AceModel6 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf6) #
AceModel7 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf7) #
# 3) RUN AceModel
AceFit1 <- mxTryHardOrdinal(AceModel1, intervals=T) #best fit -2lnL should be 40393.31
AceFit2 <- mxTryHardOrdinal(AceModel2, intervals=T) #best fit -2lnL should be 40393.31
AceFit3 <- mxTryHardOrdinal(AceModel3, intervals=T) #best fit -2lnL should be 40393.31
AceFit4 <- mxTryHardOrdinal(AceModel4, intervals=T) #best fit -2lnL should be 40393.31
AceFit5 <- mxTryHardOrdinal(AceModel5, intervals=T) #best fit -2lnL should be 40393.31
AceFit6 <- mxTryHardOrdinal(AceModel6, intervals=T) #best fit -2lnL should be 40393.31
AceFit7 <- mxTryHardOrdinal(AceModel7, intervals=T) #best fit -2lnL should be 40393.31
(AceSum1 <- summary(AceFit1,verbose=T))
(AceSum2 <- summary(AceFit2,verbose=T))
(AceSum3 <- summary(AceFit3,verbose=T))
(AceSum4 <- summary(AceFit4,verbose=T))
(AceSum5 <- summary(AceFit5,verbose=T))
(AceSum6 <- summary(AceFit6,verbose=T))
(AceSum7 <- summary(AceFit7,verbose=T))
#get the estimates and CIs
CI1 <- AceSum1$CI
CI2 <- AceSum2$CI
CI3 <- AceSum3$CI
CI4 <- AceSum4$CI
CI5 <- AceSum5$CI
CI6 <- AceSum6$CI
CI7 <- AceSum7$CI
tot_CI<-rbind(CI1,CI2,CI3,CI4,CI5,CI6,CI7)
#evaluate the contents
mxEval(MZ.ExpCovMZ, AceFit1)
mxEval(DZ.ExpCovDZ, AceFit1)
mxEval(ACE.h2, AceFit1)
mxEval(ACE.c2, AceFit1)
mxEval(ACE.e2, AceFit1)
mxEval(ACE.Ra, AceFit1)
mxEval(ACE.Rc, AceFit1)
mxEval(ACE.Re, AceFit1)
mxEval(ACE.Rph, AceFit1)
mxEval(ACE.RphACE_cSWAN_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1]*100
mxEval(ACE.RphACE_cSWAN_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1]*100
mxEval(ACE.V,AceFit1)
#get the proportion explained by A,C and E in the phenotypic correlation
proportion<-as.data.frame(rbind((mxEval(ACE.RphACE_cSWAN_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1])*100,
(mxEval(ACE.RphACE_cSWAN_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1])*100,
mxEval(ACE.RphACE_cSWAN_NSSH, AceFit1),
mxEval(ACE.RphACE_cSWAN_SSH, AceFit1)),
row.names=c("NSSH%","SSH%", "NSSH","SSH"))
colnames(proportion)<-c("A","C","E")
proportion
#constrain the model
Sub1Model <- mxModel(AceModel1, name="sub1",
mxConstraint(MZ.rA_NSSH_cSWAN==MZ.rA_SSH_cSWAN, name="rA_con"),
mxConstraint(MZ.rC_NSSH_cSWAN==MZ.rC_SSH_cSWAN, name="rC_con"),
mxConstraint(MZ.rE_NSSH_cSWAN==MZ.rE_SSH_cSWAN, name="rE_con"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = F)
(Sub1Sum <- summary(Sub1Fit))
mxEval(MZ.NSSH_a,Sub1Fit);mxEval(MZ.SSH_a,Sub1Fit)
mxEval(MZ.NSSH_c,Sub1Fit);mxEval(MZ.SSH_c,Sub1Fit)
mxEval(MZ.NSSH_e,Sub1Fit);mxEval(MZ.SSH_e,Sub1Fit)
mxEval(MZ.path_a,Sub1Fit);mxEval(MZ.path_c,Sub1Fit);mxEval(MZ.path_e,Sub1Fit)
mxEval(MZ.Ra,Sub1Fit);mxEval(MZ.Rc,Sub1Fit);mxEval(MZ.Re,Sub1Fit)
mxEval(MZ.h2,Sub1Fit)
### compare with ACE model
comparison <- mxCompare(AceFit1,Sub1Fit)
library(xlsx)
## 6) save the results
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_cSWAN_SLSQP_ACE_04_June_2020.RData")
# save the estimates and their confidence intervals
write.xlsx(tot_CI, file="trivariate_estimates_with_CI_04_June_2020.xlsx",
sheetName="cSWAN", append=TRUE)
# save the proportions
write.xlsx(proportion, file="trivariate_proportion_04_June_2020.xlsx",
sheetName="cSWAN", append=TRUE)
# save the results of the chi-square test
write.xlsx(comparison, file="trivariate_constrained_results_04_June_2020.xlsx",
sheetName="cSWAN", append=TRUE)
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
str(self_harm_data);class(self_harm_data)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,ppbhconnt1,ppbhconnt2,x3zygos,u1cage1,u1cage2,pcbhage1,pcbhage2, sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
self_harm_data_c <- mutate(self_harm_data_c, age_161 = ifelse(is.na(pcbhage1),pcbhage2 , pcbhage1))
self_harm_data_c <- mutate(self_harm_data_c, age_162 = ifelse(is.na(pcbhage2),pcbhage1 , pcbhage2))
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$SSH1)
table(self_harm_data_c$SSH2)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
str(self_harm_data_c)
#******************************************************
# Regress out age, sex and transform pCONN variable
#******************************************************
#**Regressing out age & sex **#
self_harm_data_c$respCONN1 <- residuals(lm(self_harm_data_c$ppbhconnt1 ~ self_harm_data_c$age_161 + self_harm_data_c$sex1, na.action="na.exclude"))
self_harm_data_c$respCONN2 <- residuals(lm(self_harm_data_c$ppbhconnt2 ~ self_harm_data_c$age_162 + self_harm_data_c$sex2, na.action="na.exclude"))
hist(self_harm_data_c$ppbhconnt1)
hist(self_harm_data_c$respCONN1)
describe(self_harm_data_c$respCONN1)
# #transform the data to get a normal distribution
self_harm_data_c$trans_respCONN1 <-log(self_harm_data_c$respCONN1+10.5)*2
self_harm_data_c$trans_respCONN2 <-log(self_harm_data_c$respCONN2+10.5)*2
hist(self_harm_data_c$respCONN1)
hist(self_harm_data_c$trans_respCONN1)
describe(self_harm_data_c$trans_respCONN1)
library(polycor) #check phenotypic correlation
hetcor(self_harm_data_c$trans_respCONN1, self_harm_data_c$NSSH1)$correlations #0.13
hetcor(self_harm_data_c$ppbhconnt1, self_harm_data_c$NSSH1)$correlations #without covariates, 0.07
hetcor(self_harm_data_c$SSH1, self_harm_data_c$NSSH1)$correlations # 0.87, same as in other less complex models.
vars <-c('pCONN','NSSH', 'SSH')
selVars <-c('trans_respCONN1', 'NSSH1', 'SSH1', 'trans_respCONN2', 'NSSH2', 'SSH2')
useVars <-c('trans_respCONN1', 'NSSH1', 'SSH1', 'trans_respCONN2', 'NSSH2', 'SSH2', 'age1', 'age2', 'sex1','sex2')
# Select Data for Analysis
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars)
describe(mzData)
describe(dzData)
nv <- 3 # number of variables per twin
nvo <-2 #number of ordinal variables per twin
nvc <-nv-nvo #number of continuous variables per twin
poso <- nvc+1 #position where ordinal variables start
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
nlower <- ntv*(ntv+1)/2 # number of free elements in a lower matrix ntv*ntv
ncor <-(nv*(nv+1)/2)-nv # number of free elements in a correlation matrix nv*nv
ninc <- nth-1 #number of max increments
ncovariates <- 2 #number of covariates
### Create starting values for covariance matrix
SHData_for_stv<-self_harm_data_c%>%
select('trans_respCONN1', 'NSSH1', 'SSH1', 'trans_respCONN2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(SHData_for_stv)
mzData_for_stv<-mzData%>%
select('trans_respCONN1', 'NSSH1', 'SSH1', 'trans_respCONN2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(mzData_for_stv)
dzData_for_stv<-dzData%>%
select('trans_respCONN1', 'NSSH1', 'SSH1', 'trans_respCONN2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(dzData_for_stv)
jiggle <-rnorm(nlower, mean = 0, sd = .1)
MZmean <-colMeans(mzData_for_stv,na.rm=TRUE)
DZmean <-colMeans(dzData_for_stv,na.rm=TRUE)
StMZmean<- c(mean(MZmean[c(1,4)]),0,0,mean(MZmean[c(1,4)]),0,0)
StDZmean<- c(mean(DZmean[c(1,4)]),0,0,mean(DZmean[c(1,4)]),0,0)
Stsd <-mean(sapply(mzData_for_stv[,c(1,4)],sd, na.rm=TRUE))
StWithinperson <-vechs(cor(SHData_for_stv[,1:3],use="pairwise"))
StBetweenMZ <-vech(cor(mzData_for_stv[,1:3],mzData_for_stv[,4:6],use="pairwise"))
StBetweenDZ <-vech(cor(dzData_for_stv[,1:3],dzData_for_stv[,4:6],use="pairwise"))
str(self_harm_data_c)
# 2) Specify ACE Model, with ONE overall set of Means, ONE overall Threshold on IQ liability
# To create Labels for Lower Triangular Matrices
StTH <-c(-0.27,0.45,0.19,0.15,0.75,0.55,0.25,0.16)
aLabs <- paste("a", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
cLabs <- paste("c", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
eLabs <- paste("e", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13','Tmz_21','imz_21','imz_22','imz_23') # THs for var 1 and 2 for a
LabCovA <-c('BageThNSSH', 'BageThNSSH','BageThNSSH', 'BageThNSSH', 'BageThSSH', 'BageThSSH','BageThSSH', 'BageThSSH')
LabCovS <-c('BsexThNSSH', 'BsexThNSSH','BsexThNSSH', 'BsexThNSSH', 'BsexThSSH', 'BsexThSSH','BsexThSSH', 'BsexThSSH')
# Matrices to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(1.05,0.07,0.10,0.72,0.64,0.23), labels=aLabs, name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.43,0.09,0.14,0.001,0.001,0.001), labels=cLabs, name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.48,0.03,0.03,0.57,0.57,0.42), labels=eLabs, name="e" )
# # Define definition variables to hold the Covariates
obsAge1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Age1")
obsAge2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Age2")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#effect of age and sex on ordinal variable
betaA <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovA, name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovS, name="BsexTH" )
#mean and thresholds
Mean <-mxMatrix( "Full", 1, ntv, free=c(T,F,F,T,F,F), values=StMZmean, labels=c("m1", NA,NA, "m1", NA,NA), name="ExpMean" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=StTH, lbound=c(-4,0.001,0.001,0.001), ubound=c(4,4),
labels=LabThMZ, name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH%x%Age1 + BsexTH%x%Sex1,
Low%*%Th + BageTH%x%Age2 + BsexTH%x%Sex2),
name="ExpThres")
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
# Algebra to compute standardized variance components
covP <- mxAlgebra( expression=A+C+E, name="V" )
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Constraint on total variance of Ordinal variable (A+C+E=1)
varL1 <- mxConstraint( expression=V[2,2]==1, name="L1" )
varL2 <- mxConstraint( expression=V[3,3]==1, name="L2" )
# Algebra to compute Rph-A, Rph-C & Rph-E between pCONN-NSSH
rphace_pCONN_NSSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE_pCONN_NSSH" )
rphace_pCONN_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[3,1]*sqrt(h2[3,3])),
(sqrt(c2[1,1])*Rc[3,1]*sqrt(c2[3,3])),
(sqrt(e2[1,1])*Re[3,1]*sqrt(e2[3,3])) ), name="RphACE_pCONN_SSH" )
rphace_NSSH_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[2,2])*Ra[3,2]*sqrt(h2[3,3])),
(sqrt(c2[2,2])*Rc[3,2]*sqrt(c2[3,3])),
(sqrt(e2[2,2])*Re[3,2]*sqrt(e2[3,3])) ), name="RphACE_NSSH_SSH" )
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[2,2], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[3,3], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[2,2], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[3,3], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[2,2], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[3,3], name="SSH_e")
#rA
raNSSHpCONN<-mxAlgebra(expression=Ra[2,1], name="rA_NSSH_pCONN")
raSSHpCONN<-mxAlgebra(expression=Ra[3,1], name="rA_SSH_pCONN")
#rC
rcNSSHpCONN<-mxAlgebra(expression=Rc[2,1], name="rC_NSSH_pCONN")
rcSSHpCONN<-mxAlgebra(expression=Rc[3,1], name="rC_SSH_pCONN")
#rE
reNSSHpCONN<-mxAlgebra(expression=Re[2,1], name="rE_NSSH_pCONN")
reSSHpCONN<-mxAlgebra(expression=Re[3,1], name="rE_SSH_pCONN")
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="ExpCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, StA, StC, StE, matI, rph, rA, rC, rE,
rphace_pCONN_NSSH,rphace_pCONN_SSH,rphace_NSSH_SSH,
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2,
raNSSHpCONN,raSSHpCONN,rcNSSHpCONN,rcSSHpCONN,reNSSHpCONN,reSSHpCONN)
modelMZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covMZ, dataMZ, objMZ, fitFunction, varL1, varL2, name="MZ" )
modelDZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
#confidence intervals
Conf1 <- mxCI (c('Rph[2,1]','Rph[3,1]'))
Conf2 <- mxCI ('Ra[2,1]')
Conf3 <- mxCI ('Ra[3,1]')
Conf4 <- mxCI ('Rc[2,1]')
Conf5 <- mxCI ('Rc[3,1]')
Conf6 <- mxCI ('Re[2,1]')
Conf7 <- mxCI ('Re[3,1]')
AceModel1 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf1) #
AceModel2 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf2) #
AceModel3 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf3) #
AceModel4 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf4) #
AceModel5 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf5) #
AceModel6 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf6) #
AceModel7 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf7) #
# ------------------------------------------------------------------------------
# 3) RUN AceModel
AceFit1 <- mxTryHardOrdinal(AceModel1, intervals=T) #best fit -2lnL should be 40393.31
AceFit2 <- mxTryHardOrdinal(AceModel2, intervals=T) #best fit -2lnL should be 40393.31
AceFit3 <- mxTryHardOrdinal(AceModel3, intervals=T) #best fit -2lnL should be 40393.31
AceFit4 <- mxTryHardOrdinal(AceModel4, intervals=T) #best fit -2lnL should be 40393.31
AceFit5 <- mxTryHardOrdinal(AceModel5, intervals=T) #best fit -2lnL should be 40393.31
AceFit6 <- mxTryHardOrdinal(AceModel6, intervals=T) #best fit -2lnL should be 40393.31
AceFit7 <- mxTryHardOrdinal(AceModel7, intervals=T) #best fit -2lnL should be 40393.31
(AceSum1 <- summary(AceFit1,verbose=T))
(AceSum2 <- summary(AceFit2,verbose=T))
(AceSum3 <- summary(AceFit3,verbose=T))
(AceSum4 <- summary(AceFit4,verbose=T))
(AceSum5 <- summary(AceFit5,verbose=T))
(AceSum6 <- summary(AceFit6,verbose=T))
(AceSum7 <- summary(AceFit7,verbose=T))
#get the estimates and CIs
CI1 <- AceSum1$CI
CI2 <- AceSum2$CI
CI3 <- AceSum3$CI
CI4 <- AceSum4$CI
CI5 <- AceSum5$CI
CI6 <- AceSum6$CI
CI7 <- AceSum7$CI
tot_CI<-rbind(CI1,CI2,CI3,CI4,CI5,CI6,CI7)
#evaluate the contents
mxEval(MZ.ExpCovMZ, AceFit1)
mxEval(DZ.ExpCovDZ, AceFit1)
mxEval(ACE.h2, AceFit1)
mxEval(ACE.c2, AceFit1)
mxEval(ACE.e2, AceFit1)
mxEval(ACE.Ra, AceFit1)
mxEval(ACE.Rc, AceFit1)
mxEval(ACE.Re, AceFit1)
mxEval(ACE.Rph, AceFit1)
mxEval(ACE.RphACE_pCONN_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1]*100
mxEval(ACE.RphACE_pCONN_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1]*100
mxEval(ACE.V,AceFit1)
#get the proportion explained by A,C and E in the phenotypic correlation
proportion<-as.data.frame(rbind((mxEval(ACE.RphACE_pCONN_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1])*100,
(mxEval(ACE.RphACE_pCONN_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1])*100,
mxEval(ACE.RphACE_pCONN_NSSH, AceFit1),
mxEval(ACE.RphACE_pCONN_SSH, AceFit1)),
row.names=c("NSSH%","SSH%", "NSSH","SSH"))
colnames(proportion)<-c("A","C","E")
proportion
#constrain the model
Sub1Model <- mxModel(AceModel1, name="sub1",
mxConstraint(MZ.rA_NSSH_pCONN==MZ.rA_SSH_pCONN, name="rA_con"),
mxConstraint(MZ.rC_NSSH_pCONN==MZ.rC_SSH_pCONN, name="rC_con"),
mxConstraint(MZ.rE_NSSH_pCONN==MZ.rE_SSH_pCONN, name="rE_con"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = F)
(Sub1Sum <- summary(Sub1Fit))
mxEval(MZ.NSSH_a,Sub1Fit);mxEval(MZ.SSH_a,Sub1Fit)
mxEval(MZ.NSSH_c,Sub1Fit);mxEval(MZ.SSH_c,Sub1Fit)
mxEval(MZ.NSSH_e,Sub1Fit);mxEval(MZ.SSH_e,Sub1Fit)
mxEval(MZ.path_a,Sub1Fit);mxEval(MZ.path_c,Sub1Fit);mxEval(MZ.path_e,Sub1Fit)
mxEval(MZ.Ra,Sub1Fit);mxEval(MZ.Rc,Sub1Fit);mxEval(MZ.Re,Sub1Fit)
mxEval(MZ.h2,Sub1Fit)
### compare with ACE model
comparison <- mxCompare(AceFit1,Sub1Fit)
library(xlsx)
## 6) save the results
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_pCONN_SLSQP_ACE_04_June_2020.RData")
# save the estimates and their confidence intervals
write.xlsx(tot_CI, file="trivariate_estimates_with_CI_04_June_2020.xlsx",
sheetName="pCONN", append=TRUE)
# save the proportions
write.xlsx(proportion, file="trivariate_proportion_04_June_2020.xlsx",
sheetName="pCONN", append=TRUE)
# save the results of the chi-square test
write.xlsx(comparison, file="trivariate_constrained_results_04_June_2020.xlsx",
sheetName="pCONN", append=TRUE)
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
str(self_harm_data);class(self_harm_data)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,ppbhconninat1,ppbhconninat2,x3zygos,u1cage1,u1cage2,pcbhage1,pcbhage2, sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
self_harm_data_c <- mutate(self_harm_data_c, age_161 = ifelse(is.na(pcbhage1),pcbhage2 , pcbhage1))
self_harm_data_c <- mutate(self_harm_data_c, age_162 = ifelse(is.na(pcbhage2),pcbhage1 , pcbhage2))
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$SSH1)
table(self_harm_data_c$SSH2)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
str(self_harm_data_c)
#******************************************************
# Regress out age, sex and transform pINAT variable
#******************************************************
#**Regressing out age & sex **#
self_harm_data_c$respINAT1 <- residuals(lm(self_harm_data_c$ppbhconninat1 ~ self_harm_data_c$age_161 + self_harm_data_c$sex1, na.action="na.exclude"))
self_harm_data_c$respINAT2 <- residuals(lm(self_harm_data_c$ppbhconninat2 ~ self_harm_data_c$age_162 + self_harm_data_c$sex2, na.action="na.exclude"))
hist(self_harm_data_c$ppbhconninat1)
hist(self_harm_data_c$respINAT1)
describe(self_harm_data_c$respINAT1)
# #transform the data to get a normal distribution
self_harm_data_c$trans_respINAT1 <-log(self_harm_data_c$respINAT1+6.9)*2
self_harm_data_c$trans_respINAT2 <-log(self_harm_data_c$respINAT2+6.9)*2
hist(self_harm_data_c$respINAT1)
hist(self_harm_data_c$trans_respINAT1)
describe(self_harm_data_c$trans_respINAT1)
library(polycor) #check phenotypic correlation
hetcor(self_harm_data_c$trans_respINAT1, self_harm_data_c$NSSH1)$correlations #0.15
hetcor(self_harm_data_c$ppbhconninat1, self_harm_data_c$NSSH1)$correlations #without covariates, 0.08
hetcor(self_harm_data_c$SSH1, self_harm_data_c$NSSH1)$correlations # 0.87, same as in other less complex models.
vars <-c('pINAT','NSSH', 'SSH')
selVars <-c('trans_respINAT1', 'NSSH1', 'SSH1', 'trans_respINAT2', 'NSSH2', 'SSH2')
useVars <-c('trans_respINAT1', 'NSSH1', 'SSH1', 'trans_respINAT2', 'NSSH2', 'SSH2', 'age1', 'age2', 'sex1','sex2')
# Select Data for Analysis
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars)
describe(mzData)
describe(dzData)
nv <- 3 # number of variables per twin
nvo <-2 #number of ordinal variables per twin
nvc <-nv-nvo #number of continuous variables per twin
poso <- nvc+1 #position where ordinal variables start
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
nlower <- ntv*(ntv+1)/2 # number of free elements in a lower matrix ntv*ntv
ncor <-(nv*(nv+1)/2)-nv # number of free elements in a correlation matrix nv*nv
ninc <- nth-1 #number of max increments
ncovariates <- 2 #number of covariates
### Create starting values for covariance matrix
SHData_for_stv<-self_harm_data_c%>%
select('trans_respINAT1', 'NSSH1', 'SSH1', 'trans_respINAT2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(SHData_for_stv)
mzData_for_stv<-mzData%>%
select('trans_respINAT1', 'NSSH1', 'SSH1', 'trans_respINAT2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(mzData_for_stv)
dzData_for_stv<-dzData%>%
select('trans_respINAT1', 'NSSH1', 'SSH1', 'trans_respINAT2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(dzData_for_stv)
jiggle <-rnorm(nlower, mean = 0, sd = .1)
MZmean <-colMeans(mzData_for_stv,na.rm=TRUE)
DZmean <-colMeans(dzData_for_stv,na.rm=TRUE)
StMZmean<- c(mean(MZmean[c(1,4)]),0,0,mean(MZmean[c(1,4)]),0,0)
StDZmean<- c(mean(DZmean[c(1,4)]),0,0,mean(DZmean[c(1,4)]),0,0)
Stsd <-mean(sapply(mzData_for_stv[,c(1,4)],sd, na.rm=TRUE))
StWithinperson <-vechs(cor(SHData_for_stv[,1:3],use="pairwise"))
StBetweenMZ <-vech(cor(mzData_for_stv[,1:3],mzData_for_stv[,4:6],use="pairwise"))
StBetweenDZ <-vech(cor(dzData_for_stv[,1:3],dzData_for_stv[,4:6],use="pairwise"))
str(self_harm_data_c)
# 2) Specify ACE Model, with ONE overall set of Means, ONE overall Threshold on IQ liability
# To create Labels for Lower Triangular Matrices
StTH <-c(-0.2,0.45,0.19,0.15,0.77,0.54,0.25,0.16)
aLabs <- paste("a", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
cLabs <- paste("c", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
eLabs <- paste("e", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13','Tmz_21','imz_21','imz_22','imz_23') # THs for var 1 and 2 for a
LabCovA <-c('BageThNSSH', 'BageThNSSH','BageThNSSH', 'BageThNSSH', 'BageThSSH', 'BageThSSH','BageThSSH', 'BageThSSH')
LabCovS <-c('BsexThNSSH', 'BsexThNSSH','BsexThNSSH', 'BsexThNSSH', 'BsexThSSH', 'BsexThSSH','BsexThSSH', 'BsexThSSH')
# Matrices to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(1.14,0.12,0.14,0.72,0.63,0.22), labels=aLabs, name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.03,0.13,0.11,0.02,0.02,.001), labels=cLabs, name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.37,0.03,0.13,0.67,0.56,0.42), labels=eLabs, name="e" )
# # Define definition variables to hold the Covariates
obsAge1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Age1")
obsAge2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Age2")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#effect of age and sex on ordinal variable
betaA <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovA, name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovS, name="BsexTH" )
#mean and thresholds
Mean <-mxMatrix( "Full", 1, ntv, free=c(T,F,F,T,F,F), values=StMZmean, labels=c("m1", NA,NA, "m1", NA,NA), name="ExpMean" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=StTH, lbound=c(-4,-4), ubound=c(4,4),
labels=LabThMZ, name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH%x%Age1 + BsexTH%x%Sex1,
Low%*%Th + BageTH%x%Age2 + BsexTH%x%Sex2),
name="ExpThres")
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
# Algebra to compute standardized variance components
covP <- mxAlgebra( expression=A+C+E, name="V" )
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Constraint on total variance of Ordinal variable (A+C+E=1)
varL1 <- mxConstraint( expression=V[2,2]==1, name="L1" )
varL2 <- mxConstraint( expression=V[3,3]==1, name="L2" )
# Algebra to compute Rph-A, Rph-C & Rph-E between pINAT-NSSH
rphace_pINAT_NSSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE_pINAT_NSSH" )
rphace_pINAT_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[3,1]*sqrt(h2[3,3])),
(sqrt(c2[1,1])*Rc[3,1]*sqrt(c2[3,3])),
(sqrt(e2[1,1])*Re[3,1]*sqrt(e2[3,3])) ), name="RphACE_pINAT_SSH" )
rphace_NSSH_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[2,2])*Ra[3,2]*sqrt(h2[3,3])),
(sqrt(c2[2,2])*Rc[3,2]*sqrt(c2[3,3])),
(sqrt(e2[2,2])*Re[3,2]*sqrt(e2[3,3])) ), name="RphACE_NSSH_SSH" )
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[2,2], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[3,3], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[2,2], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[3,3], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[2,2], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[3,3], name="SSH_e")
#rA
raNSSHpINAT<-mxAlgebra(expression=Ra[2,1], name="rA_NSSH_pINAT")
raSSHpINAT<-mxAlgebra(expression=Ra[3,1], name="rA_SSH_pINAT")
#rC
rcNSSHpINAT<-mxAlgebra(expression=Rc[2,1], name="rC_NSSH_pINAT")
rcSSHpINAT<-mxAlgebra(expression=Rc[3,1], name="rC_SSH_pINAT")
#rE
reNSSHpINAT<-mxAlgebra(expression=Re[2,1], name="rE_NSSH_pINAT")
reSSHpINAT<-mxAlgebra(expression=Re[3,1], name="rE_SSH_pINAT")
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="ExpCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, StA, StC, StE, matI, rph, rA, rC, rE,
rphace_pINAT_NSSH,rphace_pINAT_SSH,rphace_NSSH_SSH,
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2,
raNSSHpINAT,raSSHpINAT,rcNSSHpINAT,rcSSHpINAT,reNSSHpINAT,reSSHpINAT)
modelMZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covMZ, dataMZ, objMZ, fitFunction, varL1, varL2, name="MZ" )
modelDZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
#confidence intervals
Conf1 <- mxCI (c('Rph[2,1]','Rph[3,1]'))
Conf2 <- mxCI ('Ra[2,1]')
Conf3 <- mxCI ('Ra[3,1]')
Conf4 <- mxCI ('Rc[2,1]')
Conf5 <- mxCI ('Rc[3,1]')
Conf6 <- mxCI ('Re[2,1]')
Conf7 <- mxCI ('Re[3,1]')
AceModel1 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf1) #
AceModel2 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf2) #
AceModel3 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf3) #
AceModel4 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf4) #
AceModel5 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf5) #
AceModel6 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf6) #
AceModel7 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf7) #
# 3) RUN AceModel
AceFit1 <- mxTryHardOrdinal(AceModel1, intervals=T) #best fit -2lnL should be 40393.31
AceFit2 <- mxTryHardOrdinal(AceModel2, intervals=T) #best fit -2lnL should be 40393.31
AceFit3 <- mxTryHardOrdinal(AceModel3, intervals=T) #best fit -2lnL should be 40393.31
AceFit4 <- mxTryHardOrdinal(AceModel4, intervals=T) #best fit -2lnL should be 40393.31
AceFit5 <- mxTryHardOrdinal(AceModel5, intervals=T) #best fit -2lnL should be 40393.31
AceFit6 <- mxTryHardOrdinal(AceModel6, intervals=T) #best fit -2lnL should be 40393.31
AceFit7 <- mxTryHardOrdinal(AceModel7, intervals=T) #best fit -2lnL should be 40393.31
(AceSum1 <- summary(AceFit1,verbose=T))
(AceSum2 <- summary(AceFit2,verbose=T))
(AceSum3 <- summary(AceFit3,verbose=T))
(AceSum4 <- summary(AceFit4,verbose=T))
(AceSum5 <- summary(AceFit5,verbose=T))
(AceSum6 <- summary(AceFit6,verbose=T))
(AceSum7 <- summary(AceFit7,verbose=T))
#get the estimates and CIs
CI1 <- AceSum1$CI
CI2 <- AceSum2$CI
CI3 <- AceSum3$CI
CI4 <- AceSum4$CI
CI5 <- AceSum5$CI
CI6 <- AceSum6$CI
CI7 <- AceSum7$CI
tot_CI<-rbind(CI1,CI2,CI3,CI4,CI5,CI6,CI7)
#evaluate the contents
mxEval(MZ.ExpCovMZ, AceFit1)
mxEval(DZ.ExpCovDZ, AceFit1)
mxEval(ACE.h2, AceFit1)
mxEval(ACE.c2, AceFit1)
mxEval(ACE.e2, AceFit1)
mxEval(ACE.Ra, AceFit1)
mxEval(ACE.Rc, AceFit1)
mxEval(ACE.Re, AceFit1)
mxEval(ACE.Rph, AceFit1)
mxEval(ACE.RphACE_pINAT_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1]*100
mxEval(ACE.RphACE_pINAT_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1]*100
mxEval(ACE.V,AceFit1)
#get the proportion explained by A,C and E in the phenotypic correlation
proportion<-as.data.frame(rbind((mxEval(ACE.RphACE_pINAT_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1])*100,
(mxEval(ACE.RphACE_pINAT_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1])*100,
mxEval(ACE.RphACE_pINAT_NSSH, AceFit1),
mxEval(ACE.RphACE_pINAT_SSH, AceFit1)),
row.names=c("NSSH%","SSH%", "NSSH","SSH"))
colnames(proportion)<-c("A","C","E")
proportion
#constrain the model
Sub1Model <- mxModel(AceModel1, name="sub1",
mxConstraint(MZ.rA_NSSH_pINAT==MZ.rA_SSH_pINAT, name="rA_con"),
mxConstraint(MZ.rC_NSSH_pINAT==MZ.rC_SSH_pINAT, name="rC_con"),
mxConstraint(MZ.rE_NSSH_pINAT==MZ.rE_SSH_pINAT, name="rE_con"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = F)
(Sub1Sum <- summary(Sub1Fit))
mxEval(MZ.NSSH_a,Sub1Fit);mxEval(MZ.SSH_a,Sub1Fit)
mxEval(MZ.NSSH_c,Sub1Fit);mxEval(MZ.SSH_c,Sub1Fit)
mxEval(MZ.NSSH_e,Sub1Fit);mxEval(MZ.SSH_e,Sub1Fit)
mxEval(MZ.path_a,Sub1Fit);mxEval(MZ.path_c,Sub1Fit);mxEval(MZ.path_e,Sub1Fit)
mxEval(MZ.Ra,Sub1Fit);mxEval(MZ.Rc,Sub1Fit);mxEval(MZ.Re,Sub1Fit)
mxEval(MZ.h2,Sub1Fit)
### compare with ACE model
comparison <- mxCompare(AceFit1,Sub1Fit)
library(xlsx)
## 6) save the results
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_pINAT_SLSQP_ACE_04_June_2020.RData")
# save the estimates and their confidence intervals
write.xlsx(tot_CI, file="trivariate_estimates_with_CI_04_June_2020.xlsx",
sheetName="pINAT", append=TRUE)
# save the proportions
write.xlsx(proportion, file="trivariate_proportion_04_June_2020.xlsx",
sheetName="pINAT", append=TRUE)
# save the results of the chi-square test
write.xlsx(comparison, file="trivariate_constrained_results_04_June_2020.xlsx",
sheetName="pINAT", append=TRUE)
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
str(self_harm_data);class(self_harm_data)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,ppbhconnimpt1,ppbhconnimpt2,x3zygos,u1cage1,u1cage2,pcbhage1,pcbhage2, sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
self_harm_data_c <- mutate(self_harm_data_c, age_161 = ifelse(is.na(pcbhage1),pcbhage2 , pcbhage1))
self_harm_data_c <- mutate(self_harm_data_c, age_162 = ifelse(is.na(pcbhage2),pcbhage1 , pcbhage2))
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$SSH1)
table(self_harm_data_c$SSH2)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
str(self_harm_data_c)
#******************************************************
# Regress out age, sex and transform pHYPER variable
#******************************************************
#**Regressing out age & sex **#
self_harm_data_c$respHYPER1 <- residuals(lm(self_harm_data_c$ppbhconnimpt1 ~ self_harm_data_c$age_161 + self_harm_data_c$sex1, na.action="na.exclude"))
self_harm_data_c$respHYPER2 <- residuals(lm(self_harm_data_c$ppbhconnimpt2 ~ self_harm_data_c$age_162 + self_harm_data_c$sex2, na.action="na.exclude"))
hist(self_harm_data_c$ppbhconnimpt1)
hist(self_harm_data_c$respHYPER1)
describe(self_harm_data_c$respHYPER1)
# #transform the data to get a normal distribution
self_harm_data_c$trans_respHYPER1 <-log(self_harm_data_c$respHYPER1+3.49)*1.5
self_harm_data_c$trans_respHYPER2 <-log(self_harm_data_c$respHYPER2+3.49)*1.5
hist(self_harm_data_c$respHYPER1)
hist(self_harm_data_c$trans_respHYPER1)
describe(self_harm_data_c$trans_respHYPER1)
library(polycor) #check phenotypic correlation
hetcor(self_harm_data_c$trans_respHYPER1, self_harm_data_c$NSSH1)$correlations #0.07
hetcor(self_harm_data_c$ppbhconnimpt1, self_harm_data_c$NSSH1)$correlations #without covariates, 0.04
hetcor(self_harm_data_c$SSH1, self_harm_data_c$NSSH1)$correlations # 0.87, same as in other less complex models.
vars <-c('pHYPER','NSSH', 'SSH')
selVars <-c('trans_respHYPER1', 'NSSH1', 'SSH1', 'trans_respHYPER2', 'NSSH2', 'SSH2')
useVars <-c('trans_respHYPER1', 'NSSH1', 'SSH1', 'trans_respHYPER2', 'NSSH2', 'SSH2', 'age1', 'age2', 'sex1','sex2')
# Select Data for Analysis
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars)
describe(mzData)
describe(dzData)
nv <- 3 # number of variables per twin
nvo <-2 #number of ordinal variables per twin
nvc <-nv-nvo #number of continuous variables per twin
poso <- nvc+1 #position where ordinal variables start
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
nlower <- ntv*(ntv+1)/2 # number of free elements in a lower matrix ntv*ntv
ncor <-(nv*(nv+1)/2)-nv # number of free elements in a correlation matrix nv*nv
ninc <- nth-1 #number of max increments
ncovariates <- 2 #number of covariates
### Create starting values for covariance matrix
SHData_for_stv<-self_harm_data_c%>%
select('trans_respHYPER1', 'NSSH1', 'SSH1', 'trans_respHYPER2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(SHData_for_stv)
mzData_for_stv<-mzData%>%
select('trans_respHYPER1', 'NSSH1', 'SSH1', 'trans_respHYPER2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(mzData_for_stv)
dzData_for_stv<-dzData%>%
select('trans_respHYPER1', 'NSSH1', 'SSH1', 'trans_respHYPER2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(dzData_for_stv)
jiggle <-rnorm(nlower, mean = 0, sd = .1)
MZmean <-colMeans(mzData_for_stv,na.rm=TRUE)
DZmean <-colMeans(dzData_for_stv,na.rm=TRUE)
StMZmean<- c(mean(MZmean[c(1,4)]),0,0,mean(MZmean[c(1,4)]),0,0)
StDZmean<- c(mean(DZmean[c(1,4)]),0,0,mean(DZmean[c(1,4)]),0,0)
Stsd <-mean(sapply(mzData_for_stv[,c(1,4)],sd, na.rm=TRUE))
StWithinperson <-vechs(cor(SHData_for_stv[,1:3],use="pairwise"))
StBetweenMZ <-vech(cor(mzData_for_stv[,1:3],mzData_for_stv[,4:6],use="pairwise"))
StBetweenDZ <-vech(cor(dzData_for_stv[,1:3],dzData_for_stv[,4:6],use="pairwise"))
str(self_harm_data_c)
# 2) Specify ACE Model, with ONE overall set of Means, ONE overall Threshold on IQ liability
# To create Labels for Lower Triangular Matrices
StTH <-c(-0.2,0.45,0.19,0.15,0.56,0.54,0.24,0.15)
aLabs <- paste("a", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
cLabs <- paste("c", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
eLabs <- paste("e", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13','Tmz_21','imz_21','imz_22','imz_23') # THs for var 1 and 2 for a
LabCovA <-c('BageThNSSH', 'BageThNSSH','BageThNSSH', 'BageThNSSH', 'BageThSSH', 'BageThSSH','BageThSSH', 'BageThSSH')
LabCovS <-c('BsexThNSSH', 'BsexThNSSH','BsexThNSSH', 'BsexThNSSH', 'BsexThSSH', 'BsexThSSH','BsexThSSH', 'BsexThSSH')
# Matrices to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(1.30,0.05,0.04,0.72,0.62,0.43), labels=aLabs, name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.30,0.15,0.09,0.01,0.01,0.01), labels=cLabs, name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.64,0.03,0.01,0.67,0.50,0.42), labels=eLabs, name="e" )
# # Define definition variables to hold the Covariates
obsAge1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Age1")
obsAge2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Age2")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#effect of age and sex on ordinal variable
betaA <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovA, name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovS, name="BsexTH" )
#mean and thresholds
Mean <-mxMatrix( "Full", 1, ntv, free=c(T,F,F,T,F,F), values=StMZmean, labels=c("m1", NA,NA, "m1", NA,NA), name="ExpMean" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=StTH, lbound=c(-4,-4), ubound=c(4,4),
labels=LabThMZ, name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH%x%Age1 + BsexTH%x%Sex1,
Low%*%Th + BageTH%x%Age2 + BsexTH%x%Sex2),
name="ExpThres")
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
# Algebra to compute standardized variance components
covP <- mxAlgebra( expression=A+C+E, name="V" )
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Constraint on total variance of Ordinal variable (A+C+E=1)
varL1 <- mxConstraint( expression=V[2,2]==1, name="L1" )
varL2 <- mxConstraint( expression=V[3,3]==1, name="L2" )
# Algebra to compute Rph-A, Rph-C & Rph-E between pHYPER-NSSH
rphace_pHYPER_NSSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE_pHYPER_NSSH" )
rphace_pHYPER_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[3,1]*sqrt(h2[3,3])),
(sqrt(c2[1,1])*Rc[3,1]*sqrt(c2[3,3])),
(sqrt(e2[1,1])*Re[3,1]*sqrt(e2[3,3])) ), name="RphACE_pHYPER_SSH" )
rphace_NSSH_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[2,2])*Ra[3,2]*sqrt(h2[3,3])),
(sqrt(c2[2,2])*Rc[3,2]*sqrt(c2[3,3])),
(sqrt(e2[2,2])*Re[3,2]*sqrt(e2[3,3])) ), name="RphACE_NSSH_SSH" )
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[2,2], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[3,3], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[2,2], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[3,3], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[2,2], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[3,3], name="SSH_e")
#rA
raNSSHpHYPER<-mxAlgebra(expression=Ra[2,1], name="rA_NSSH_pHYPER")
raSSHpHYPER<-mxAlgebra(expression=Ra[3,1], name="rA_SSH_pHYPER")
#rC
rcNSSHpHYPER<-mxAlgebra(expression=Rc[2,1], name="rC_NSSH_pHYPER")
rcSSHpHYPER<-mxAlgebra(expression=Rc[3,1], name="rC_SSH_pHYPER")
#rE
reNSSHpHYPER<-mxAlgebra(expression=Re[2,1], name="rE_NSSH_pHYPER")
reSSHpHYPER<-mxAlgebra(expression=Re[3,1], name="rE_SSH_pHYPER")
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="ExpCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, StA, StC, StE, matI, rph, rA, rC, rE,
rphace_pHYPER_NSSH,rphace_pHYPER_SSH,rphace_NSSH_SSH,
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2,
raNSSHpHYPER,raSSHpHYPER,rcNSSHpHYPER,rcSSHpHYPER,reNSSHpHYPER,reSSHpHYPER)
modelMZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covMZ, dataMZ, objMZ, fitFunction, varL1, varL2, name="MZ" )
modelDZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
#confidence intervals
Conf1 <- mxCI (c('Rph[2,1]','Rph[3,1]'))
Conf2 <- mxCI ('Ra[2,1]')
Conf3 <- mxCI ('Ra[3,1]')
Conf4 <- mxCI ('Rc[2,1]')
Conf5 <- mxCI ('Rc[3,1]')
Conf6 <- mxCI ('Re[2,1]')
Conf7 <- mxCI ('Re[3,1]')
AceModel1 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf1) #
AceModel2 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf2) #
AceModel3 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf3) #
AceModel4 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf4) #
AceModel5 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf5) #
AceModel6 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf6) #
AceModel7 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf7) #
# 3) RUN AceModel
AceFit1 <- mxTryHardOrdinal(AceModel1, intervals=T) #best fit -2lnL should be 40393.31
AceFit2 <- mxTryHardOrdinal(AceModel2, intervals=T) #best fit -2lnL should be 40393.31
AceFit3 <- mxTryHardOrdinal(AceModel3, intervals=T) #best fit -2lnL should be 40393.31
AceFit4 <- mxTryHardOrdinal(AceModel4, intervals=T) #best fit -2lnL should be 40393.31
AceFit5 <- mxTryHardOrdinal(AceModel5, intervals=T) #best fit -2lnL should be 40393.31
AceFit6 <- mxTryHardOrdinal(AceModel6, intervals=T) #best fit -2lnL should be 40393.31
AceFit7 <- mxTryHardOrdinal(AceModel7, intervals=T) #best fit -2lnL should be 40393.31
(AceSum1 <- summary(AceFit1,verbose=T))
(AceSum2 <- summary(AceFit2,verbose=T))
(AceSum3 <- summary(AceFit3,verbose=T))
(AceSum4 <- summary(AceFit4,verbose=T))
(AceSum5 <- summary(AceFit5,verbose=T))
(AceSum6 <- summary(AceFit6,verbose=T))
(AceSum7 <- summary(AceFit7,verbose=T))
#get the estimates and CIs
CI1 <- AceSum1$CI
CI2 <- AceSum2$CI
CI3 <- AceSum3$CI
CI4 <- AceSum4$CI
CI5 <- AceSum5$CI
CI6 <- AceSum6$CI
CI7 <- AceSum7$CI
tot_CI<-rbind(CI1,CI2,CI3,CI4,CI5,CI6,CI7)
#evaluate the contents
mxEval(MZ.ExpCovMZ, AceFit1)
mxEval(DZ.ExpCovDZ, AceFit1)
mxEval(ACE.h2, AceFit1)
mxEval(ACE.c2, AceFit1)
mxEval(ACE.e2, AceFit1)
mxEval(ACE.Ra, AceFit1)
mxEval(ACE.Rc, AceFit1)
mxEval(ACE.Re, AceFit1)
mxEval(ACE.Rph, AceFit1)
mxEval(ACE.RphACE_pHYPER_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1]*100
mxEval(ACE.RphACE_pHYPER_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1]*100
mxEval(ACE.V,AceFit1)
#get the proportion explained by A,C and E in the phenotypic correlation
proportion<-as.data.frame(rbind((mxEval(ACE.RphACE_pHYPER_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1])*100,
(mxEval(ACE.RphACE_pHYPER_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1])*100,
mxEval(ACE.RphACE_pHYPER_NSSH, AceFit1),
mxEval(ACE.RphACE_pHYPER_SSH, AceFit1)),
row.names=c("NSSH%","SSH%", "NSSH","SSH"))
colnames(proportion)<-c("A","C","E")
proportion
#constrain the model
Sub1Model <- mxModel(AceModel1, name="sub1",
mxConstraint(MZ.rA_NSSH_pHYPER==MZ.rA_SSH_pHYPER, name="rA_con"),
mxConstraint(MZ.rC_NSSH_pHYPER==MZ.rC_SSH_pHYPER, name="rC_con"),
mxConstraint(MZ.rE_NSSH_pHYPER==MZ.rE_SSH_pHYPER, name="rE_con"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = F)
(Sub1Sum <- summary(Sub1Fit))
mxEval(MZ.NSSH_a,Sub1Fit);mxEval(MZ.SSH_a,Sub1Fit)
mxEval(MZ.NSSH_c,Sub1Fit);mxEval(MZ.SSH_c,Sub1Fit)
mxEval(MZ.NSSH_e,Sub1Fit);mxEval(MZ.SSH_e,Sub1Fit)
mxEval(MZ.path_a,Sub1Fit);mxEval(MZ.path_c,Sub1Fit);mxEval(MZ.path_e,Sub1Fit)
mxEval(MZ.Ra,Sub1Fit);mxEval(MZ.Rc,Sub1Fit);mxEval(MZ.Re,Sub1Fit)
mxEval(MZ.h2,Sub1Fit)
### compare with ACE model
comparison <- mxCompare(AceFit1,Sub1Fit)
library(xlsx)
## 6) save the results
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_pHYPER_SLSQP_ACE_04_June_2020.RData")
# save the estimates and their confidence intervals
write.xlsx(tot_CI, file="trivariate_estimates_with_CI_04_June_2020.xlsx",
sheetName="pHYPER", append=TRUE)
# save the proportions
write.xlsx(proportion, file="trivariate_proportion_04_June_2020.xlsx",
sheetName="pHYPER", append=TRUE)
# save the results of the chi-square test
write.xlsx(comparison, file="trivariate_constrained_results_04_June_2020.xlsx",
sheetName="pHYPER", append=TRUE)
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
str(self_harm_data);class(self_harm_data)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,ppbhconnemlt1,ppbhconnemlt2,x3zygos,u1cage1,u1cage2,pcbhage1,pcbhage2, sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
self_harm_data_c <- mutate(self_harm_data_c, age_161 = ifelse(is.na(pcbhage1),pcbhage2 , pcbhage1))
self_harm_data_c <- mutate(self_harm_data_c, age_162 = ifelse(is.na(pcbhage2),pcbhage1 , pcbhage2))
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$SSH1)
table(self_harm_data_c$SSH2)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
str(self_harm_data_c)
#******************************************************
# Regress out age, sex and transform pEMOLv2 variable
#******************************************************
#**Regressing out age & sex **#
self_harm_data_c$respEMOLv21 <- residuals(lm(self_harm_data_c$ppbhconnemlt1 ~ self_harm_data_c$age_161 + self_harm_data_c$sex1, na.action="na.exclude"))
self_harm_data_c$respEMOLv22 <- residuals(lm(self_harm_data_c$ppbhconnemlt2 ~ self_harm_data_c$age_162 + self_harm_data_c$sex2, na.action="na.exclude"))
hist(self_harm_data_c$ppbhconnemlt1)
hist(self_harm_data_c$respEMOLv21)
describe(self_harm_data_c$respEMOLv21)
# #transform the data to get a normal distribution
self_harm_data_c$trans_respEMOLv21 <-log(self_harm_data_c$respEMOLv21+1.71)
self_harm_data_c$trans_respEMOLv22 <-log(self_harm_data_c$respEMOLv22+1.71)
hist(self_harm_data_c$respEMOLv21)
hist(self_harm_data_c$trans_respEMOLv21)
describe(self_harm_data_c$trans_respEMOLv21)
library(polycor) #check phenotypic correlation
hetcor(self_harm_data_c$trans_respEMOLv21, self_harm_data_c$NSSH1)$correlations #0.15
hetcor(self_harm_data_c$ppbhconnemlt1, self_harm_data_c$NSSH1)$correlations #without covariates, 0.16
hetcor(self_harm_data_c$SSH1, self_harm_data_c$NSSH1)$correlations # 0.87, same as in other less complex models.
vars <-c('pEMOLv2','NSSH', 'SSH')
selVars <-c('trans_respEMOLv21', 'NSSH1', 'SSH1', 'trans_respEMOLv22', 'NSSH2', 'SSH2')
useVars <-c('trans_respEMOLv21', 'NSSH1', 'SSH1', 'trans_respEMOLv22', 'NSSH2', 'SSH2', 'age1', 'age2', 'sex1','sex2')
# Select Data for Analysis
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars)
describe(mzData)
describe(dzData)
nv <- 3 # number of variables per twin
nvo <-2 #number of ordinal variables per twin
nvc <-nv-nvo #number of continuous variables per twin
poso <- nvc+1 #position where ordinal variables start
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
nlower <- ntv*(ntv+1)/2 # number of free elements in a lower matrix ntv*ntv
ncor <-(nv*(nv+1)/2)-nv # number of free elements in a correlation matrix nv*nv
ninc <- nth-1 #number of max increments
ncovariates <- 2 #number of covariates
### Create starting values for covariance matrix
SHData_for_stv<-self_harm_data_c%>%
select('trans_respEMOLv21', 'NSSH1', 'SSH1', 'trans_respEMOLv22', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(SHData_for_stv)
mzData_for_stv<-mzData%>%
select('trans_respEMOLv21', 'NSSH1', 'SSH1', 'trans_respEMOLv22', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(mzData_for_stv)
dzData_for_stv<-dzData%>%
select('trans_respEMOLv21', 'NSSH1', 'SSH1', 'trans_respEMOLv22', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(dzData_for_stv)
jiggle <-rnorm(nlower, mean = 0, sd = .1)
MZmean <-colMeans(mzData_for_stv,na.rm=TRUE)
DZmean <-colMeans(dzData_for_stv,na.rm=TRUE)
StMZmean<- c(mean(MZmean[c(1,4)]),0,0,mean(MZmean[c(1,4)]),0,0)
StDZmean<- c(mean(DZmean[c(1,4)]),0,0,mean(DZmean[c(1,4)]),0,0)
Stsd <-mean(sapply(mzData_for_stv[,c(1,4)],sd, na.rm=TRUE))
StWithinperson <-vechs(cor(SHData_for_stv[,1:3],use="pairwise"))
StBetweenMZ <-vech(cor(mzData_for_stv[,1:3],mzData_for_stv[,4:6],use="pairwise"))
StBetweenDZ <-vech(cor(dzData_for_stv[,1:3],dzData_for_stv[,4:6],use="pairwise"))
str(self_harm_data_c)
# 2) Specify ACE Model, with ONE overall set of Means, ONE overall Threshold on IQ liability
# To create Labels for Lower Triangular Matrices
StTH <-c(-0.47,0.45,0.19,0.15,0.56,0.56,0.25,0.16)
aLabs <- paste("a", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
cLabs <- paste("c", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
eLabs <- paste("e", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13','Tmz_21','imz_21','imz_22','imz_23') # THs for var 1 and 2 for a
LabCovA <-c('BageThNSSH', 'BageThNSSH','BageThNSSH', 'BageThNSSH', 'BageThSSH', 'BageThSSH','BageThSSH', 'BageThSSH')
LabCovS <-c('BsexThNSSH', 'BsexThNSSH','BsexThNSSH', 'BsexThNSSH', 'BsexThSSH', 'BsexThSSH','BsexThSSH', 'BsexThSSH')
# Matrices to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.30,0.06,0.34,0.02,0.23,0.23), labels=aLabs, name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.80,0.20,0.14,0.001,0.001,0.001), labels=cLabs, name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.14,0.03,0.06,0.55,0.07,0.42), labels=eLabs, name="e" )
# # Define definition variables to hold the Covariates
obsAge1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Age1")
obsAge2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Age2")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#effect of age and sex on ordinal variable
betaA <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovA, name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovS, name="BsexTH" )
#mean and thresholds
Mean <-mxMatrix( "Full", 1, ntv, free=c(T,F,F,T,F,F), values=StMZmean, labels=c("m1", NA,NA, "m1", NA,NA), name="ExpMean" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=StTH, lbound=c(-4,-4), ubound=c(4,4),
labels=LabThMZ, name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH%x%Age1 + BsexTH%x%Sex1,
Low%*%Th + BageTH%x%Age2 + BsexTH%x%Sex2),
name="ExpThres")
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
# Algebra to compute standardized variance components
covP <- mxAlgebra( expression=A+C+E, name="V" )
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Constraint on total variance of Ordinal variable (A+C+E=1)
varL1 <- mxConstraint( expression=V[2,2]==1, name="L1" )
varL2 <- mxConstraint( expression=V[3,3]==1, name="L2" )
# Algebra to compute Rph-A, Rph-C & Rph-E between pEMOLv2-NSSH
rphace_pEMOLv2_NSSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE_pEMOLv2_NSSH" )
rphace_pEMOLv2_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[3,1]*sqrt(h2[3,3])),
(sqrt(c2[1,1])*Rc[3,1]*sqrt(c2[3,3])),
(sqrt(e2[1,1])*Re[3,1]*sqrt(e2[3,3])) ), name="RphACE_pEMOLv2_SSH" )
rphace_NSSH_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[2,2])*Ra[3,2]*sqrt(h2[3,3])),
(sqrt(c2[2,2])*Rc[3,2]*sqrt(c2[3,3])),
(sqrt(e2[2,2])*Re[3,2]*sqrt(e2[3,3])) ), name="RphACE_NSSH_SSH" )
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[2,2], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[3,3], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[2,2], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[3,3], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[2,2], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[3,3], name="SSH_e")
#rA
raNSSHpEMOLv2<-mxAlgebra(expression=Ra[2,1], name="rA_NSSH_pEMOLv2")
raSSHpEMOLv2<-mxAlgebra(expression=Ra[3,1], name="rA_SSH_pEMOLv2")
#rC
rcNSSHpEMOLv2<-mxAlgebra(expression=Rc[2,1], name="rC_NSSH_pEMOLv2")
rcSSHpEMOLv2<-mxAlgebra(expression=Rc[3,1], name="rC_SSH_pEMOLv2")
#rE
reNSSHpEMOLv2<-mxAlgebra(expression=Re[2,1], name="rE_NSSH_pEMOLv2")
reSSHpEMOLv2<-mxAlgebra(expression=Re[3,1], name="rE_SSH_pEMOLv2")
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="ExpCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, StA, StC, StE, matI, rph, rA, rC, rE,
rphace_pEMOLv2_NSSH,rphace_pEMOLv2_SSH,rphace_NSSH_SSH,
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2,
raNSSHpEMOLv2,raSSHpEMOLv2,rcNSSHpEMOLv2,rcSSHpEMOLv2,reNSSHpEMOLv2,reSSHpEMOLv2)
modelMZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covMZ, dataMZ, objMZ, fitFunction, varL1, varL2, name="MZ" )
modelDZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
#confidence intervals
Conf1 <- mxCI (c('Rph[2,1]','Rph[3,1]'))
Conf2 <- mxCI ('Ra[2,1]')
Conf3 <- mxCI ('Ra[3,1]')
Conf4 <- mxCI ('Rc[2,1]')
Conf5 <- mxCI ('Rc[3,1]')
Conf6 <- mxCI ('Re[2,1]')
Conf7 <- mxCI ('Re[3,1]')
AceModel1 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf1) #
AceModel2 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf2) #
AceModel3 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf3) #
AceModel4 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf4) #
AceModel5 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf5) #
AceModel6 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf6) #
AceModel7 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf7) #
# 3) RUN AceModel
AceFit1 <- mxTryHardOrdinal(AceModel1, intervals=T) #best fit -2lnL should be 40393.31
AceFit2 <- mxTryHardOrdinal(AceModel2, intervals=T) #best fit -2lnL should be 40393.31
AceFit3 <- mxTryHardOrdinal(AceModel3, intervals=T) #best fit -2lnL should be 40393.31
AceFit4 <- mxTryHardOrdinal(AceModel4, intervals=T) #best fit -2lnL should be 40393.31
AceFit5 <- mxTryHardOrdinal(AceModel5, intervals=T) #best fit -2lnL should be 40393.31
AceFit6 <- mxTryHardOrdinal(AceModel6, intervals=T) #best fit -2lnL should be 40393.31
AceFit7 <- mxTryHardOrdinal(AceModel7, intervals=T) #best fit -2lnL should be 40393.31
(AceSum1 <- summary(AceFit1,verbose=T))
(AceSum2 <- summary(AceFit2,verbose=T))
(AceSum3 <- summary(AceFit3,verbose=T))
(AceSum4 <- summary(AceFit4,verbose=T))
(AceSum5 <- summary(AceFit5,verbose=T))
(AceSum6 <- summary(AceFit6,verbose=T))
(AceSum7 <- summary(AceFit7,verbose=T))
#get the estimates and CIs
CI1 <- AceSum1$CI
CI2 <- AceSum2$CI
CI3 <- AceSum3$CI
CI4 <- AceSum4$CI
CI5 <- AceSum5$CI
CI6 <- AceSum6$CI
CI7 <- AceSum7$CI
tot_CI<-rbind(CI1,CI2,CI3,CI4,CI5,CI6,CI7)
#evaluate the contents
mxEval(MZ.ExpCovMZ, AceFit1)
mxEval(DZ.ExpCovDZ, AceFit1)
mxEval(ACE.h2, AceFit1)
mxEval(ACE.c2, AceFit1)
mxEval(ACE.e2, AceFit1)
mxEval(ACE.Ra, AceFit1)
mxEval(ACE.Rc, AceFit1)
mxEval(ACE.Re, AceFit1)
mxEval(ACE.Rph, AceFit1)
mxEval(ACE.RphACE_pEMOLv2_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1]*100
mxEval(ACE.RphACE_pEMOLv2_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1]*100
mxEval(ACE.V,AceFit1)
#get the proportion explained by A,C and E in the phenotypic correlation
proportion<-as.data.frame(rbind((mxEval(ACE.RphACE_pEMOLv2_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1])*100,
(mxEval(ACE.RphACE_pEMOLv2_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1])*100,
mxEval(ACE.RphACE_pEMOLv2_NSSH, AceFit1),
mxEval(ACE.RphACE_pEMOLv2_SSH, AceFit1)),
row.names=c("NSSH%","SSH%", "NSSH","SSH"))
colnames(proportion)<-c("A","C","E")
proportion
#constrain the model
Sub1Model <- mxModel(AceModel1, name="sub1",
mxConstraint(MZ.rA_NSSH_pEMOLv2==MZ.rA_SSH_pEMOLv2, name="rA_con"),
mxConstraint(MZ.rC_NSSH_pEMOLv2==MZ.rC_SSH_pEMOLv2, name="rC_con"),
mxConstraint(MZ.rE_NSSH_pEMOLv2==MZ.rE_SSH_pEMOLv2, name="rE_con"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = F)
(Sub1Sum <- summary(Sub1Fit))
mxEval(MZ.NSSH_a,Sub1Fit);mxEval(MZ.SSH_a,Sub1Fit)
mxEval(MZ.NSSH_c,Sub1Fit);mxEval(MZ.SSH_c,Sub1Fit)
mxEval(MZ.NSSH_e,Sub1Fit);mxEval(MZ.SSH_e,Sub1Fit)
mxEval(MZ.path_a,Sub1Fit);mxEval(MZ.path_c,Sub1Fit);mxEval(MZ.path_e,Sub1Fit)
mxEval(MZ.Ra,Sub1Fit);mxEval(MZ.Rc,Sub1Fit);mxEval(MZ.Re,Sub1Fit)
mxEval(MZ.h2,Sub1Fit)
### compare with ACE model
comparison <- mxCompare(AceFit1,Sub1Fit)
library(xlsx)
## 6) save the results
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_pEMOLv2_SLSQP_ACE_04_June_2020.RData")
# save the estimates and their confidence intervals
write.xlsx(tot_CI, file="trivariate_estimates_with_CI_04_June_2020.xlsx",
sheetName="pEMOLv2", append=TRUE)
# save the proportions
write.xlsx(proportion, file="trivariate_proportion_04_June_2020.xlsx",
sheetName="pEMOLv2", append=TRUE)
# save the results of the chi-square test
write.xlsx(comparison, file="trivariate_constrained_results_04_June_2020.xlsx",
sheetName="pEMOLv2", append=TRUE)
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
str(self_harm_data);class(self_harm_data)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,pcbhprndt1,pcbhprndt2,x3zygos,u1cage1,u1cage2,pcbhage1,pcbhage2, sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
self_harm_data_c <- mutate(self_harm_data_c, age_161 = ifelse(is.na(pcbhage1),pcbhage2 , pcbhage1))
self_harm_data_c <- mutate(self_harm_data_c, age_162 = ifelse(is.na(pcbhage2),pcbhage1 , pcbhage2))
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$SSH1)
table(self_harm_data_c$SSH2)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
str(self_harm_data_c)
#******************************************************
# Regress out age, sex and transform cPRND variable
#******************************************************
#**Regressing out age & sex **#
self_harm_data_c$rescPRND1 <- residuals(lm(self_harm_data_c$pcbhprndt1 ~ self_harm_data_c$age_161 + self_harm_data_c$sex1, na.action="na.exclude"))
self_harm_data_c$rescPRND2 <- residuals(lm(self_harm_data_c$pcbhprndt2 ~ self_harm_data_c$age_162 + self_harm_data_c$sex2, na.action="na.exclude"))
hist(self_harm_data_c$pcbhprndt1)
hist(self_harm_data_c$rescPRND1)
describe(self_harm_data_c$rescPRND1)
# #transform the data to get a normal distribution
self_harm_data_c$trans_rescPRND1 <-((self_harm_data_c$rescPRND1+12.69)^(1/3))*2
self_harm_data_c$trans_rescPRND2 <-((self_harm_data_c$rescPRND2+12.69)^(1/3))*2
hist(self_harm_data_c$rescPRND1)
hist(self_harm_data_c$trans_rescPRND1)
describe(self_harm_data_c$trans_rescPRND1)
library(polycor) #check phenotypic correlation
hetcor(self_harm_data_c$trans_rescPRND1, self_harm_data_c$NSSH1)$correlations #0.31
hetcor(self_harm_data_c$pcbhprndt1, self_harm_data_c$NSSH1)$correlations #without covariates, 0.29
hetcor(self_harm_data_c$SSH1, self_harm_data_c$NSSH1)$correlations # 0.87, same as in other less complex models.
vars <-c('cPRND','NSSH', 'SSH')
selVars <-c('trans_rescPRND1', 'NSSH1', 'SSH1', 'trans_rescPRND2', 'NSSH2', 'SSH2')
useVars <-c('trans_rescPRND1', 'NSSH1', 'SSH1', 'trans_rescPRND2', 'NSSH2', 'SSH2', 'age1', 'age2', 'sex1','sex2')
# Select Data for Analysis
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars)
describe(mzData)
describe(dzData)
nv <- 3 # number of variables per twin
nvo <-2 #number of ordinal variables per twin
nvc <-nv-nvo #number of continuous variables per twin
poso <- nvc+1 #position where ordinal variables start
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
nlower <- ntv*(ntv+1)/2 # number of free elements in a lower matrix ntv*ntv
ncor <-(nv*(nv+1)/2)-nv # number of free elements in a correlation matrix nv*nv
ninc <- nth-1 #number of max increments
ncovariates <- 2 #number of covariates
### Create starting values for covariance matrix
SHData_for_stv<-self_harm_data_c%>%
select('trans_rescPRND1', 'NSSH1', 'SSH1', 'trans_rescPRND2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(SHData_for_stv)
mzData_for_stv<-mzData%>%
select('trans_rescPRND1', 'NSSH1', 'SSH1', 'trans_rescPRND2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(mzData_for_stv)
dzData_for_stv<-dzData%>%
select('trans_rescPRND1', 'NSSH1', 'SSH1', 'trans_rescPRND2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(dzData_for_stv)
jiggle <-rnorm(nlower, mean = 0, sd = .1)
MZmean <-colMeans(mzData_for_stv,na.rm=TRUE)
DZmean <-colMeans(dzData_for_stv,na.rm=TRUE)
StMZmean<- c(mean(MZmean[c(1,4)]),0,0,mean(MZmean[c(1,4)]),0,0)
StDZmean<- c(mean(DZmean[c(1,4)]),0,0,mean(DZmean[c(1,4)]),0,0)
Stsd <-mean(sapply(mzData_for_stv[,c(1,4)],sd, na.rm=TRUE))
StWithinperson <-vechs(cor(SHData_for_stv[,1:3],use="pairwise"))
StBetweenMZ <-vech(cor(mzData_for_stv[,1:3],mzData_for_stv[,4:6],use="pairwise"))
StBetweenDZ <-vech(cor(dzData_for_stv[,1:3],dzData_for_stv[,4:6],use="pairwise"))
str(self_harm_data_c)
# 2) Specify ACE Model, with ONE overall set of Means, ONE overall Threshold on IQ liability
# To create Labels for Lower Triangular Matrices
StTH <-c(-0.32,0.45,0.19,0.15,0.70,0.54,0.24,0.15)
aLabs <- paste("a", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
cLabs <- paste("c", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
eLabs <- paste("e", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13','Tmz_21','imz_21','imz_22','imz_23') # THs for var 1 and 2 for a
LabCovA <-c('BageThNSSH', 'BageThNSSH','BageThNSSH', 'BageThNSSH', 'BageThSSH', 'BageThSSH','BageThSSH', 'BageThSSH')
LabCovS <-c('BsexThNSSH', 'BsexThNSSH','BsexThNSSH', 'BsexThNSSH', 'BsexThSSH', 'BsexThSSH','BsexThSSH', 'BsexThSSH')
# Matrices to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.64,0.25,0.14,0.72,0.62,0.23), labels=aLabs, name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.30,0.15,0.19,0.01,0.01,0.01), labels=cLabs, name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.84,0.03,0.12,0.67,0.50,0.42), labels=eLabs, name="e" )
# # Define definition variables to hold the Covariates
obsAge1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Age1")
obsAge2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Age2")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#effect of age and sex on ordinal variable
betaA <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovA, name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovS, name="BsexTH" )
#mean and thresholds
Mean <-mxMatrix( "Full", 1, ntv, free=c(T,F,F,T,F,F), values=StMZmean, labels=c("m1", NA,NA, "m1", NA,NA), name="ExpMean" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=StTH, lbound=c(-4,0.001,0.001,0.001), ubound=c(4,4),
labels=LabThMZ, name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH%x%Age1 + BsexTH%x%Sex1,
Low%*%Th + BageTH%x%Age2 + BsexTH%x%Sex2),
name="ExpThres")
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
# Algebra to compute standardized variance components
covP <- mxAlgebra( expression=A+C+E, name="V" )
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Constraint on total variance of Ordinal variable (A+C+E=1)
varL1 <- mxConstraint( expression=V[2,2]==1, name="L1" )
varL2 <- mxConstraint( expression=V[3,3]==1, name="L2" )
# Algebra to compute Rph-A, Rph-C & Rph-E between cPRND-NSSH
rphace_cPRND_NSSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE_cPRND_NSSH" )
rphace_cPRND_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[3,1]*sqrt(h2[3,3])),
(sqrt(c2[1,1])*Rc[3,1]*sqrt(c2[3,3])),
(sqrt(e2[1,1])*Re[3,1]*sqrt(e2[3,3])) ), name="RphACE_cPRND_SSH" )
rphace_NSSH_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[2,2])*Ra[3,2]*sqrt(h2[3,3])),
(sqrt(c2[2,2])*Rc[3,2]*sqrt(c2[3,3])),
(sqrt(e2[2,2])*Re[3,2]*sqrt(e2[3,3])) ), name="RphACE_NSSH_SSH" )
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[2,2], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[3,3], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[2,2], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[3,3], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[2,2], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[3,3], name="SSH_e")
#rA
raNSSHcPRND<-mxAlgebra(expression=Ra[2,1], name="rA_NSSH_cPRND")
raSSHcPRND<-mxAlgebra(expression=Ra[3,1], name="rA_SSH_cPRND")
#rC
rcNSSHcPRND<-mxAlgebra(expression=Rc[2,1], name="rC_NSSH_cPRND")
rcSSHcPRND<-mxAlgebra(expression=Rc[3,1], name="rC_SSH_cPRND")
#rE
reNSSHcPRND<-mxAlgebra(expression=Re[2,1], name="rE_NSSH_cPRND")
reSSHcPRND<-mxAlgebra(expression=Re[3,1], name="rE_SSH_cPRND")
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="ExpCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, StA, StC, StE, matI, rph, rA, rC, rE,
rphace_cPRND_NSSH,rphace_cPRND_SSH,rphace_NSSH_SSH,
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2,
raNSSHcPRND,raSSHcPRND,rcNSSHcPRND,rcSSHcPRND,reNSSHcPRND,reSSHcPRND)
modelMZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covMZ, dataMZ, objMZ, fitFunction, varL1, varL2, name="MZ" )
modelDZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
#confidence intervals
Conf1 <- mxCI (c('Rph[2,1]','Rph[3,1]'))
Conf2 <- mxCI ('Ra[2,1]')
Conf3 <- mxCI ('Ra[3,1]')
Conf4 <- mxCI ('Rc[2,1]')
Conf5 <- mxCI ('Rc[3,1]')
Conf6 <- mxCI ('Re[2,1]')
Conf7 <- mxCI ('Re[3,1]')
AceModel1 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf1) #
AceModel2 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf2) #
AceModel3 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf3) #
AceModel4 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf4) #
AceModel5 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf5) #
AceModel6 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf6) #
AceModel7 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf7) #
# 3) RUN AceModel
AceFit1 <- mxTryHardOrdinal(AceModel1, intervals=T) #best fit -2lnL should be 40393.31
AceFit2 <- mxTryHardOrdinal(AceModel2, intervals=T) #best fit -2lnL should be 40393.31
AceFit3 <- mxTryHardOrdinal(AceModel3, intervals=T) #best fit -2lnL should be 40393.31
AceFit4 <- mxTryHardOrdinal(AceModel4, intervals=T) #best fit -2lnL should be 40393.31
AceFit5 <- mxTryHardOrdinal(AceModel5, intervals=T) #best fit -2lnL should be 40393.31
AceFit6 <- mxTryHardOrdinal(AceModel6, intervals=T) #best fit -2lnL should be 40393.31
AceFit7 <- mxTryHardOrdinal(AceModel7, intervals=T) #best fit -2lnL should be 40393.31
(AceSum1 <- summary(AceFit1,verbose=T))
(AceSum2 <- summary(AceFit2,verbose=T))
(AceSum3 <- summary(AceFit3,verbose=T))
(AceSum4 <- summary(AceFit4,verbose=T))
(AceSum5 <- summary(AceFit5,verbose=T))
(AceSum6 <- summary(AceFit6,verbose=T))
(AceSum7 <- summary(AceFit7,verbose=T))
#get the estimates and CIs
CI1 <- AceSum1$CI
CI2 <- AceSum2$CI
CI3 <- AceSum3$CI
CI4 <- AceSum4$CI
CI5 <- AceSum5$CI
CI6 <- AceSum6$CI
CI7 <- AceSum7$CI
tot_CI<-rbind(CI1,CI2,CI3,CI4,CI5,CI6,CI7)
#evaluate the contents
mxEval(MZ.ExpCovMZ, AceFit1)
mxEval(DZ.ExpCovDZ, AceFit1)
mxEval(ACE.h2, AceFit1)
mxEval(ACE.c2, AceFit1)
mxEval(ACE.e2, AceFit1)
mxEval(ACE.Ra, AceFit1)
mxEval(ACE.Rc, AceFit1)
mxEval(ACE.Re, AceFit1)
mxEval(ACE.Rph, AceFit1)
mxEval(ACE.RphACE_cPRND_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1]*100
mxEval(ACE.RphACE_cPRND_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1]*100
mxEval(ACE.V,AceFit1)
#get the proportion explained by A,C and E in the phenotypic correlation
proportion<-as.data.frame(rbind((mxEval(ACE.RphACE_cPRND_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1])*100,
(mxEval(ACE.RphACE_cPRND_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1])*100,
mxEval(ACE.RphACE_cPRND_NSSH, AceFit1),
mxEval(ACE.RphACE_cPRND_SSH, AceFit1)),
row.names=c("NSSH%","SSH%", "NSSH","SSH"))
colnames(proportion)<-c("A","C","E")
proportion
#constrain the model
Sub1Model <- mxModel(AceModel1, name="sub1",
mxConstraint(MZ.rA_NSSH_cPRND==MZ.rA_SSH_cPRND, name="rA_con"),
mxConstraint(MZ.rC_NSSH_cPRND==MZ.rC_SSH_cPRND, name="rC_con"),
mxConstraint(MZ.rE_NSSH_cPRND==MZ.rE_SSH_cPRND, name="rE_con"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = F)
(Sub1Sum <- summary(Sub1Fit))
mxEval(MZ.NSSH_a,Sub1Fit);mxEval(MZ.SSH_a,Sub1Fit)
mxEval(MZ.NSSH_c,Sub1Fit);mxEval(MZ.SSH_c,Sub1Fit)
mxEval(MZ.NSSH_e,Sub1Fit);mxEval(MZ.SSH_e,Sub1Fit)
mxEval(MZ.path_a,Sub1Fit);mxEval(MZ.path_c,Sub1Fit);mxEval(MZ.path_e,Sub1Fit)
mxEval(MZ.Ra,Sub1Fit);mxEval(MZ.Rc,Sub1Fit);mxEval(MZ.Re,Sub1Fit)
mxEval(MZ.h2,Sub1Fit)
### compare with ACE model
comparison <- mxCompare(AceFit1,Sub1Fit)
library(xlsx)
## 6) save the results
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_cPRND_SLSQP_ACE_04_June_2020.RData")
# save the estimates and their confidence intervals
write.xlsx(tot_CI, file="trivariate_estimates_with_CI_04_June_2020.xlsx",
sheetName="cPRND", append=TRUE)
# save the proportions
write.xlsx(proportion, file="trivariate_proportion_04_June_2020.xlsx",
sheetName="cPRND", append=TRUE)
# save the results of the chi-square test
write.xlsx(comparison, file="trivariate_constrained_results_04_June_2020.xlsx",
sheetName="cPRND", append=TRUE)
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
str(self_harm_data);class(self_harm_data)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,pcbhcapst1,pcbhcapst2,x3zygos,u1cage1,u1cage2,pcbhage1,pcbhage2, sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
self_harm_data_c <- mutate(self_harm_data_c, age_161 = ifelse(is.na(pcbhage1),pcbhage2 , pcbhage1))
self_harm_data_c <- mutate(self_harm_data_c, age_162 = ifelse(is.na(pcbhage2),pcbhage1 , pcbhage2))
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$SSH1)
table(self_harm_data_c$SSH2)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
str(self_harm_data_c)
#******************************************************
# Regress out age, sex and transform cCAPS variable
#******************************************************
#**Regressing out age & sex **#
self_harm_data_c$rescCAPS1 <- residuals(lm(self_harm_data_c$pcbhcapst1 ~ self_harm_data_c$age_161 + self_harm_data_c$sex1, na.action="na.exclude"))
self_harm_data_c$rescCAPS2 <- residuals(lm(self_harm_data_c$pcbhcapst2 ~ self_harm_data_c$age_162 + self_harm_data_c$sex2, na.action="na.exclude"))
hist(self_harm_data_c$pcbhcapst1)
hist(self_harm_data_c$rescCAPS1)
describe(self_harm_data_c$rescCAPS1)
# #transform the data to get a normal distribution
self_harm_data_c$trans_rescCAPS1 <-log(self_harm_data_c$rescCAPS1+5.5)
self_harm_data_c$trans_rescCAPS2 <-log(self_harm_data_c$rescCAPS2+5.5)
hist(self_harm_data_c$rescCAPS1)
hist(self_harm_data_c$trans_rescCAPS1)
describe(self_harm_data_c$trans_rescCAPS1)
library(polycor) #check phenotypic correlation
hetcor(self_harm_data_c$trans_rescCAPS1, self_harm_data_c$NSSH1)$correlations #0.21
hetcor(self_harm_data_c$pcbhcapst1, self_harm_data_c$NSSH1)$correlations #without covariates, 0.23
hetcor(self_harm_data_c$SSH1, self_harm_data_c$NSSH1)$correlations # 0.87, same as in other less complex models.
vars <-c('cCAPS','NSSH', 'SSH')
selVars <-c('trans_rescCAPS1', 'NSSH1', 'SSH1', 'trans_rescCAPS2', 'NSSH2', 'SSH2')
useVars <-c('trans_rescCAPS1', 'NSSH1', 'SSH1', 'trans_rescCAPS2', 'NSSH2', 'SSH2', 'age1', 'age2', 'sex1','sex2')
# Select Data for Analysis
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars)
describe(mzData)
describe(dzData)
nv <- 3 # number of variables per twin
nvo <-2 #number of ordinal variables per twin
nvc <-nv-nvo #number of continuous variables per twin
poso <- nvc+1 #position where ordinal variables start
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
nlower <- ntv*(ntv+1)/2 # number of free elements in a lower matrix ntv*ntv
ncor <-(nv*(nv+1)/2)-nv # number of free elements in a correlation matrix nv*nv
ninc <- nth-1 #number of max increments
ncovariates <- 2 #number of covariates
### Create starting values for covariance matrix
SHData_for_stv<-self_harm_data_c%>%
select('trans_rescCAPS1', 'NSSH1', 'SSH1', 'trans_rescCAPS2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(SHData_for_stv)
mzData_for_stv<-mzData%>%
select('trans_rescCAPS1', 'NSSH1', 'SSH1', 'trans_rescCAPS2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(mzData_for_stv)
dzData_for_stv<-dzData%>%
select('trans_rescCAPS1', 'NSSH1', 'SSH1', 'trans_rescCAPS2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(dzData_for_stv)
jiggle <-rnorm(nlower, mean = 0, sd = .1)
MZmean <-colMeans(mzData_for_stv,na.rm=TRUE)
DZmean <-colMeans(dzData_for_stv,na.rm=TRUE)
StMZmean<- c(mean(MZmean[c(1,4)]),0,0,mean(MZmean[c(1,4)]),0,0)
StDZmean<- c(mean(DZmean[c(1,4)]),0,0,mean(DZmean[c(1,4)]),0,0)
Stsd <-mean(sapply(mzData_for_stv[,c(1,4)],sd, na.rm=TRUE))
StWithinperson <-vechs(cor(SHData_for_stv[,1:3],use="pairwise"))
StBetweenMZ <-vech(cor(mzData_for_stv[,1:3],mzData_for_stv[,4:6],use="pairwise"))
StBetweenDZ <-vech(cor(dzData_for_stv[,1:3],dzData_for_stv[,4:6],use="pairwise"))
str(self_harm_data_c)
# 2) Specify ACE Model, with ONE overall set of Means, ONE overall Threshold on IQ liability
# To create Labels for Lower Triangular Matrices
StTH <-c(-0.32,0.45,0.19,0.15,0.70,0.54,0.24,0.15)
aLabs <- paste("a", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
cLabs <- paste("c", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
eLabs <- paste("e", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13','Tmz_21','imz_21','imz_22','imz_23') # THs for var 1 and 2 for a
LabCovA <-c('BageThNSSH', 'BageThNSSH','BageThNSSH', 'BageThNSSH', 'BageThSSH', 'BageThSSH','BageThSSH', 'BageThSSH')
LabCovS <-c('BsexThNSSH', 'BsexThNSSH','BsexThNSSH', 'BsexThNSSH', 'BsexThSSH', 'BsexThSSH','BsexThSSH', 'BsexThSSH')
# Matrices to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.64,0.25,0.14,0.72,0.62,0.23), labels=aLabs, name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.30,0.15,0.19,0.01,0.01,0.01), labels=cLabs, name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.84,0.03,0.12,0.67,0.50,0.42), labels=eLabs, name="e" )
# # Define definition variables to hold the Covariates
obsAge1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Age1")
obsAge2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Age2")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#effect of age and sex on ordinal variable
betaA <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovA, name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovS, name="BsexTH" )
#mean and thresholds
Mean <-mxMatrix( "Full", 1, ntv, free=c(T,F,F,T,F,F), values=StMZmean, labels=c("m1", NA,NA, "m1", NA,NA), name="ExpMean" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=StTH, lbound=c(-4,0.001,0.001,0.001), ubound=c(4,4),
labels=LabThMZ, name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH%x%Age1 + BsexTH%x%Sex1,
Low%*%Th + BageTH%x%Age2 + BsexTH%x%Sex2),
name="ExpThres")
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
# Algebra to compute standardized variance components
covP <- mxAlgebra( expression=A+C+E, name="V" )
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Constraint on total variance of Ordinal variable (A+C+E=1)
varL1 <- mxConstraint( expression=V[2,2]==1, name="L1" )
varL2 <- mxConstraint( expression=V[3,3]==1, name="L2" )
# Algebra to compute Rph-A, Rph-C & Rph-E between cCAPS-NSSH
rphace_cCAPS_NSSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE_cCAPS_NSSH" )
rphace_cCAPS_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[3,1]*sqrt(h2[3,3])),
(sqrt(c2[1,1])*Rc[3,1]*sqrt(c2[3,3])),
(sqrt(e2[1,1])*Re[3,1]*sqrt(e2[3,3])) ), name="RphACE_cCAPS_SSH" )
rphace_NSSH_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[2,2])*Ra[3,2]*sqrt(h2[3,3])),
(sqrt(c2[2,2])*Rc[3,2]*sqrt(c2[3,3])),
(sqrt(e2[2,2])*Re[3,2]*sqrt(e2[3,3])) ), name="RphACE_NSSH_SSH" )
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[2,2], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[3,3], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[2,2], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[3,3], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[2,2], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[3,3], name="SSH_e")
#rA
raNSSHcCAPS<-mxAlgebra(expression=Ra[2,1], name="rA_NSSH_cCAPS")
raSSHcCAPS<-mxAlgebra(expression=Ra[3,1], name="rA_SSH_cCAPS")
#rC
rcNSSHcCAPS<-mxAlgebra(expression=Rc[2,1], name="rC_NSSH_cCAPS")
rcSSHcCAPS<-mxAlgebra(expression=Rc[3,1], name="rC_SSH_cCAPS")
#rE
reNSSHcCAPS<-mxAlgebra(expression=Re[2,1], name="rE_NSSH_cCAPS")
reSSHcCAPS<-mxAlgebra(expression=Re[3,1], name="rE_SSH_cCAPS")
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="ExpCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, StA, StC, StE, matI, rph, rA, rC, rE,
rphace_cCAPS_NSSH,rphace_cCAPS_SSH,rphace_NSSH_SSH,
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2,
raNSSHcCAPS,raSSHcCAPS,rcNSSHcCAPS,rcSSHcCAPS,reNSSHcCAPS,reSSHcCAPS)
modelMZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covMZ, dataMZ, objMZ, fitFunction, varL1, varL2, name="MZ" )
modelDZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
#confidence intervals
Conf1 <- mxCI (c('Rph[2,1]','Rph[3,1]'))
Conf2 <- mxCI ('Ra[2,1]')
Conf3 <- mxCI ('Ra[3,1]')
Conf4 <- mxCI ('Rc[2,1]')
Conf5 <- mxCI ('Rc[3,1]')
Conf6 <- mxCI ('Re[2,1]')
Conf7 <- mxCI ('Re[3,1]')
AceModel1 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf1) #
AceModel2 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf2) #
AceModel3 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf3) #
AceModel4 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf4) #
AceModel5 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf5) #
AceModel6 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf6) #
AceModel7 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf7) #
# 3) RUN AceModel
AceFit1 <- mxTryHardOrdinal(AceModel1, intervals=T) #best fit -2lnL should be 40393.31
AceFit2 <- mxTryHardOrdinal(AceModel2, intervals=T) #best fit -2lnL should be 40393.31
AceFit3 <- mxTryHardOrdinal(AceModel3, intervals=T) #best fit -2lnL should be 40393.31
AceFit4 <- mxTryHardOrdinal(AceModel4, intervals=T) #best fit -2lnL should be 40393.31
AceFit5 <- mxTryHardOrdinal(AceModel5, intervals=T) #best fit -2lnL should be 40393.31
AceFit6 <- mxTryHardOrdinal(AceModel6, intervals=T) #best fit -2lnL should be 40393.31
AceFit7 <- mxTryHardOrdinal(AceModel7, intervals=T) #best fit -2lnL should be 40393.31
(AceSum1 <- summary(AceFit1,verbose=T))
(AceSum2 <- summary(AceFit2,verbose=T))
(AceSum3 <- summary(AceFit3,verbose=T))
(AceSum4 <- summary(AceFit4,verbose=T))
(AceSum5 <- summary(AceFit5,verbose=T))
(AceSum6 <- summary(AceFit6,verbose=T))
(AceSum7 <- summary(AceFit7,verbose=T))
#get the estimates and CIs
CI1 <- AceSum1$CI
CI2 <- AceSum2$CI
CI3 <- AceSum3$CI
CI4 <- AceSum4$CI
CI5 <- AceSum5$CI
CI6 <- AceSum6$CI
CI7 <- AceSum7$CI
tot_CI<-rbind(CI1,CI2,CI3,CI4,CI5,CI6,CI7)
#evaluate the contents
mxEval(MZ.ExpCovMZ, AceFit1)
mxEval(DZ.ExpCovDZ, AceFit1)
mxEval(ACE.h2, AceFit1)
mxEval(ACE.c2, AceFit1)
mxEval(ACE.e2, AceFit1)
mxEval(ACE.Ra, AceFit1)
mxEval(ACE.Rc, AceFit1)
mxEval(ACE.Re, AceFit1)
mxEval(ACE.Rph, AceFit1)
mxEval(ACE.RphACE_cCAPS_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1]*100
mxEval(ACE.RphACE_cCAPS_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1]*100
mxEval(ACE.V,AceFit1)
#get the proportion explained by A,C and E in the phenotypic correlation
proportion<-as.data.frame(rbind((mxEval(ACE.RphACE_cCAPS_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1])*100,
(mxEval(ACE.RphACE_cCAPS_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1])*100,
mxEval(ACE.RphACE_cCAPS_NSSH, AceFit1),
mxEval(ACE.RphACE_cCAPS_SSH, AceFit1)),
row.names=c("NSSH%","SSH%", "NSSH","SSH"))
colnames(proportion)<-c("A","C","E")
proportion
#constrain the model
Sub1Model <- mxModel(AceModel1, name="sub1",
mxConstraint(MZ.rA_NSSH_cCAPS==MZ.rA_SSH_cCAPS, name="rA_con"),
mxConstraint(MZ.rC_NSSH_cCAPS==MZ.rC_SSH_cCAPS, name="rC_con"),
mxConstraint(MZ.rE_NSSH_cCAPS==MZ.rE_SSH_cCAPS, name="rE_con"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = F)
(Sub1Sum <- summary(Sub1Fit))
mxEval(MZ.NSSH_a,Sub1Fit);mxEval(MZ.SSH_a,Sub1Fit)
mxEval(MZ.NSSH_c,Sub1Fit);mxEval(MZ.SSH_c,Sub1Fit)
mxEval(MZ.NSSH_e,Sub1Fit);mxEval(MZ.SSH_e,Sub1Fit)
mxEval(MZ.path_a,Sub1Fit);mxEval(MZ.path_c,Sub1Fit);mxEval(MZ.path_e,Sub1Fit)
mxEval(MZ.Ra,Sub1Fit);mxEval(MZ.Rc,Sub1Fit);mxEval(MZ.Re,Sub1Fit)
mxEval(MZ.h2,Sub1Fit)
### compare with ACE model
comparison <- mxCompare(AceFit1,Sub1Fit)
library(xlsx)
## 6) save the results
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_cCAPS_SLSQP_ACE_04_June_2020.RData")
# save the estimates and their confidence intervals
write.xlsx(tot_CI, file="trivariate_estimates_with_CI_04_June_2020.xlsx",
sheetName="cCAPS", append=TRUE)
# save the proportions
write.xlsx(proportion, file="trivariate_proportion_04_June_2020.xlsx",
sheetName="cCAPS", append=TRUE)
# save the results of the chi-square test
write.xlsx(comparison, file="trivariate_constrained_results_04_June_2020.xlsx",
sheetName="cCAPS", append=TRUE)
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
str(self_harm_data);class(self_harm_data)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,pcbhanhdt1,pcbhanhdt2,x3zygos,u1cage1,u1cage2,pcbhage1,pcbhage2, sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
self_harm_data_c <- mutate(self_harm_data_c, age_161 = ifelse(is.na(pcbhage1),pcbhage2 , pcbhage1))
self_harm_data_c <- mutate(self_harm_data_c, age_162 = ifelse(is.na(pcbhage2),pcbhage1 , pcbhage2))
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$SSH1)
table(self_harm_data_c$SSH2)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
str(self_harm_data_c)
#******************************************************
# Regress out age, sex and transform cANHE variable
#******************************************************
#**Regressing out age & sex **#
self_harm_data_c$rescANHE1 <- residuals(lm(self_harm_data_c$pcbhanhdt1 ~ self_harm_data_c$age_161 + self_harm_data_c$sex1, na.action="na.exclude"))
self_harm_data_c$rescANHE2 <- residuals(lm(self_harm_data_c$pcbhanhdt2 ~ self_harm_data_c$age_162 + self_harm_data_c$sex2, na.action="na.exclude"))
hist(self_harm_data_c$pcbhanhdt1)
hist(self_harm_data_c$rescANHE1)
describe(self_harm_data_c$rescANHE1)
# #transform the data to get a normal distribution
self_harm_data_c$trans_rescANHE1 <-(self_harm_data_c$rescANHE1+1.68)^(1/3)
self_harm_data_c$trans_rescANHE2 <-(self_harm_data_c$rescANHE2+1.68)^(1/3)
hist(self_harm_data_c$rescANHE1)
hist(self_harm_data_c$trans_rescANHE1)
describe(self_harm_data_c$trans_rescANHE1)
library(polycor) #check phenotypic correlation
hetcor(self_harm_data_c$trans_rescANHE1, self_harm_data_c$NSSH1)$correlations #0.18
hetcor(self_harm_data_c$pcbhanhdt1, self_harm_data_c$NSSH1)$correlations #without covariates, 0.17
hetcor(self_harm_data_c$SSH1, self_harm_data_c$NSSH1)$correlations # 0.87, same as in other less complex models.
vars <-c('cANHE','NSSH', 'SSH')
selVars <-c('trans_rescANHE1', 'NSSH1', 'SSH1', 'trans_rescANHE2', 'NSSH2', 'SSH2')
useVars <-c('trans_rescANHE1', 'NSSH1', 'SSH1', 'trans_rescANHE2', 'NSSH2', 'SSH2', 'age1', 'age2', 'sex1','sex2')
# Select Data for Analysis
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars)
describe(mzData)
describe(dzData)
nv <- 3 # number of variables per twin
nvo <-2 #number of ordinal variables per twin
nvc <-nv-nvo #number of continuous variables per twin
poso <- nvc+1 #position where ordinal variables start
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
nlower <- ntv*(ntv+1)/2 # number of free elements in a lower matrix ntv*ntv
ncor <-(nv*(nv+1)/2)-nv # number of free elements in a correlation matrix nv*nv
ninc <- nth-1 #number of max increments
ncovariates <- 2 #number of covariates
### Create starting values for covariance matrix
SHData_for_stv<-self_harm_data_c%>%
select('trans_rescANHE1', 'NSSH1', 'SSH1', 'trans_rescANHE2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(SHData_for_stv)
mzData_for_stv<-mzData%>%
select('trans_rescANHE1', 'NSSH1', 'SSH1', 'trans_rescANHE2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(mzData_for_stv)
dzData_for_stv<-dzData%>%
select('trans_rescANHE1', 'NSSH1', 'SSH1', 'trans_rescANHE2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(dzData_for_stv)
jiggle <-rnorm(nlower, mean = 0, sd = .1)
MZmean <-colMeans(mzData_for_stv,na.rm=TRUE)
DZmean <-colMeans(dzData_for_stv,na.rm=TRUE)
StMZmean<- c(mean(MZmean[c(1,4)]),0,0,mean(MZmean[c(1,4)]),0,0)
StDZmean<- c(mean(DZmean[c(1,4)]),0,0,mean(DZmean[c(1,4)]),0,0)
Stsd <-mean(sapply(mzData_for_stv[,c(1,4)],sd, na.rm=TRUE))
StWithinperson <-vechs(cor(SHData_for_stv[,1:3],use="pairwise"))
StBetweenMZ <-vech(cor(mzData_for_stv[,1:3],mzData_for_stv[,4:6],use="pairwise"))
StBetweenDZ <-vech(cor(dzData_for_stv[,1:3],dzData_for_stv[,4:6],use="pairwise"))
str(self_harm_data_c)
# 2) Specify ACE Model, with ONE overall set of Means, ONE overall Threshold on IQ liability
# To create Labels for Lower Triangular Matrices
StTH <-c(-0.32,0.45,0.19,0.15,0.70,0.54,0.24,0.15)
aLabs <- paste("a", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
cLabs <- paste("c", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
eLabs <- paste("e", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13','Tmz_21','imz_21','imz_22','imz_23') # THs for var 1 and 2 for a
LabCovA <-c('BageThNSSH', 'BageThNSSH','BageThNSSH', 'BageThNSSH', 'BageThSSH', 'BageThSSH','BageThSSH', 'BageThSSH')
LabCovS <-c('BsexThNSSH', 'BsexThNSSH','BsexThNSSH', 'BsexThNSSH', 'BsexThSSH', 'BsexThSSH','BsexThSSH', 'BsexThSSH')
# Matrices to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.64,0.25,0.14,0.72,0.62,0.23), labels=aLabs, name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.30,0.15,0.19,0.01,0.01,0.01), labels=cLabs, name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.84,0.03,0.12,0.67,0.50,0.42), labels=eLabs, name="e" )
# # Define definition variables to hold the Covariates
obsAge1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Age1")
obsAge2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Age2")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#effect of age and sex on ordinal variable
betaA <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovA, name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovS, name="BsexTH" )
#mean and thresholds
Mean <-mxMatrix( "Full", 1, ntv, free=c(T,F,F,T,F,F), values=StMZmean, labels=c("m1", NA,NA, "m1", NA,NA), name="ExpMean" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=StTH, lbound=c(-4,0.001,0.001,0.001), ubound=c(4,4),
labels=LabThMZ, name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH%x%Age1 + BsexTH%x%Sex1,
Low%*%Th + BageTH%x%Age2 + BsexTH%x%Sex2),
name="ExpThres")
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
# Algebra to compute standardized variance components
covP <- mxAlgebra( expression=A+C+E, name="V" )
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Constraint on total variance of Ordinal variable (A+C+E=1)
varL1 <- mxConstraint( expression=V[2,2]==1, name="L1" )
varL2 <- mxConstraint( expression=V[3,3]==1, name="L2" )
# Algebra to compute Rph-A, Rph-C & Rph-E between cANHE-NSSH
rphace_cANHE_NSSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE_cANHE_NSSH" )
rphace_cANHE_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[3,1]*sqrt(h2[3,3])),
(sqrt(c2[1,1])*Rc[3,1]*sqrt(c2[3,3])),
(sqrt(e2[1,1])*Re[3,1]*sqrt(e2[3,3])) ), name="RphACE_cANHE_SSH" )
rphace_NSSH_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[2,2])*Ra[3,2]*sqrt(h2[3,3])),
(sqrt(c2[2,2])*Rc[3,2]*sqrt(c2[3,3])),
(sqrt(e2[2,2])*Re[3,2]*sqrt(e2[3,3])) ), name="RphACE_NSSH_SSH" )
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[2,2], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[3,3], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[2,2], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[3,3], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[2,2], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[3,3], name="SSH_e")
#rA
raNSSHcANHE<-mxAlgebra(expression=Ra[2,1], name="rA_NSSH_cANHE")
raSSHcANHE<-mxAlgebra(expression=Ra[3,1], name="rA_SSH_cANHE")
#rC
rcNSSHcANHE<-mxAlgebra(expression=Rc[2,1], name="rC_NSSH_cANHE")
rcSSHcANHE<-mxAlgebra(expression=Rc[3,1], name="rC_SSH_cANHE")
#rE
reNSSHcANHE<-mxAlgebra(expression=Re[2,1], name="rE_NSSH_cANHE")
reSSHcANHE<-mxAlgebra(expression=Re[3,1], name="rE_SSH_cANHE")
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="ExpCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, StA, StC, StE, matI, rph, rA, rC, rE,
rphace_cANHE_NSSH,rphace_cANHE_SSH,rphace_NSSH_SSH,
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2,
raNSSHcANHE,raSSHcANHE,rcNSSHcANHE,rcSSHcANHE,reNSSHcANHE,reSSHcANHE)
modelMZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covMZ, dataMZ, objMZ, fitFunction, varL1, varL2, name="MZ" )
modelDZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
#confidence intervals
Conf1 <- mxCI (c('Rph[2,1]','Rph[3,1]'))
Conf2 <- mxCI ('Ra[2,1]')
Conf3 <- mxCI ('Ra[3,1]')
Conf4 <- mxCI ('Rc[2,1]')
Conf5 <- mxCI ('Rc[3,1]')
Conf6 <- mxCI ('Re[2,1]')
Conf7 <- mxCI ('Re[3,1]')
AceModel1 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf1) #
AceModel2 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf2) #
AceModel3 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf3) #
AceModel4 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf4) #
AceModel5 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf5) #
AceModel6 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf6) #
AceModel7 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf7) #
# 3) RUN AceModel
AceFit1 <- mxTryHardOrdinal(AceModel1, intervals=T) #best fit -2lnL should be 40393.31
AceFit2 <- mxTryHardOrdinal(AceModel2, intervals=T) #best fit -2lnL should be 40393.31
AceFit3 <- mxTryHardOrdinal(AceModel3, intervals=T) #best fit -2lnL should be 40393.31
AceFit4 <- mxTryHardOrdinal(AceModel4, intervals=T) #best fit -2lnL should be 40393.31
AceFit5 <- mxTryHardOrdinal(AceModel5, intervals=T) #best fit -2lnL should be 40393.31
AceFit6 <- mxTryHardOrdinal(AceModel6, intervals=T) #best fit -2lnL should be 40393.31
AceFit7 <- mxTryHardOrdinal(AceModel7, intervals=T) #best fit -2lnL should be 40393.31
(AceSum1 <- summary(AceFit1,verbose=T))
(AceSum2 <- summary(AceFit2,verbose=T))
(AceSum3 <- summary(AceFit3,verbose=T))
(AceSum4 <- summary(AceFit4,verbose=T))
(AceSum5 <- summary(AceFit5,verbose=T))
(AceSum6 <- summary(AceFit6,verbose=T))
(AceSum7 <- summary(AceFit7,verbose=T))
#get the estimates and CIs
CI1 <- AceSum1$CI
CI2 <- AceSum2$CI
CI3 <- AceSum3$CI
CI4 <- AceSum4$CI
CI5 <- AceSum5$CI
CI6 <- AceSum6$CI
CI7 <- AceSum7$CI
tot_CI<-rbind(CI1,CI2,CI3,CI4,CI5,CI6,CI7)
#evaluate the contents
mxEval(MZ.ExpCovMZ, AceFit1)
mxEval(DZ.ExpCovDZ, AceFit1)
mxEval(ACE.h2, AceFit1)
mxEval(ACE.c2, AceFit1)
mxEval(ACE.e2, AceFit1)
mxEval(ACE.Ra, AceFit1)
mxEval(ACE.Rc, AceFit1)
mxEval(ACE.Re, AceFit1)
mxEval(ACE.Rph, AceFit1)
mxEval(ACE.RphACE_cANHE_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1]*100
mxEval(ACE.RphACE_cANHE_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1]*100
mxEval(ACE.V,AceFit1)
#get the proportion explained by A,C and E in the phenotypic correlation
proportion<-as.data.frame(rbind((mxEval(ACE.RphACE_cANHE_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1])*100,
(mxEval(ACE.RphACE_cANHE_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1])*100,
mxEval(ACE.RphACE_cANHE_NSSH, AceFit1),
mxEval(ACE.RphACE_cANHE_SSH, AceFit1)),
row.names=c("NSSH%","SSH%", "NSSH","SSH"))
colnames(proportion)<-c("A","C","E")
proportion
#constrain the model
Sub1Model <- mxModel(AceModel1, name="sub1",
mxConstraint(MZ.rA_NSSH_cANHE==MZ.rA_SSH_cANHE, name="rA_con"),
mxConstraint(MZ.rC_NSSH_cANHE==MZ.rC_SSH_cANHE, name="rC_con"),
mxConstraint(MZ.rE_NSSH_cANHE==MZ.rE_SSH_cANHE, name="rE_con"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = F)
(Sub1Sum <- summary(Sub1Fit))
mxEval(MZ.NSSH_a,Sub1Fit);mxEval(MZ.SSH_a,Sub1Fit)
mxEval(MZ.NSSH_c,Sub1Fit);mxEval(MZ.SSH_c,Sub1Fit)
mxEval(MZ.NSSH_e,Sub1Fit);mxEval(MZ.SSH_e,Sub1Fit)
mxEval(MZ.path_a,Sub1Fit);mxEval(MZ.path_c,Sub1Fit);mxEval(MZ.path_e,Sub1Fit)
mxEval(MZ.Ra,Sub1Fit);mxEval(MZ.Rc,Sub1Fit);mxEval(MZ.Re,Sub1Fit)
mxEval(MZ.h2,Sub1Fit)
### compare with ACE model
comparison <- mxCompare(AceFit1,Sub1Fit)
# COMPARE MODELS: Print Comparative Fit Statistics
library(xlsx)
## 6) save the results
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_cANHE_SLSQP_ACE_04_June_2020.RData")
# save the estimates and their confidence intervals
write.xlsx(tot_CI, file="trivariate_estimates_with_CI_04_June_2020.xlsx",
sheetName="cANHE", append=TRUE)
# save the proportions
write.xlsx(proportion, file="trivariate_proportion_04_June_2020.xlsx",
sheetName="cANHE", append=TRUE)
# save the results of the chi-square test
write.xlsx(comparison, file="trivariate_constrained_results_04_June_2020.xlsx",
sheetName="cANHE", append=TRUE)
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
str(self_harm_data);class(self_harm_data)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,ppbhsanst1,ppbhsanst2,x3zygos,u1cage1,u1cage2,pcbhage1,pcbhage2, sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
self_harm_data_c <- mutate(self_harm_data_c, age_161 = ifelse(is.na(pcbhage1),pcbhage2 , pcbhage1))
self_harm_data_c <- mutate(self_harm_data_c, age_162 = ifelse(is.na(pcbhage2),pcbhage1 , pcbhage2))
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$SSH1)
table(self_harm_data_c$SSH2)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
str(self_harm_data_c)
#******************************************************
# Regress out age, sex and transform pSANS variable
#******************************************************
#**Regressing out age & sex **#
self_harm_data_c$respSANS1 <- residuals(lm(self_harm_data_c$ppbhsanst1 ~ self_harm_data_c$age_161 + self_harm_data_c$sex1, na.action="na.exclude"))
self_harm_data_c$respSANS2 <- residuals(lm(self_harm_data_c$ppbhsanst2 ~ self_harm_data_c$age_162 + self_harm_data_c$sex2, na.action="na.exclude"))
hist(self_harm_data_c$ppbhsanst1)
hist(self_harm_data_c$respSANS1)
describe(self_harm_data_c$respSANS1)
# #transform the data to get a normal distribution
self_harm_data_c$trans_respSANS1 <-log(self_harm_data_c$respSANS1+3.75)*2
self_harm_data_c$trans_respSANS2 <-log(self_harm_data_c$respSANS2+3.75)*2
hist(self_harm_data_c$respSANS1)
hist(self_harm_data_c$trans_respSANS1)
describe(self_harm_data_c$trans_respSANS1)
library(polycor) #check phenotypic correlation
hetcor(self_harm_data_c$trans_respSANS1, self_harm_data_c$NSSH1)$correlations #0.16
hetcor(self_harm_data_c$ppbhsanst1, self_harm_data_c$NSSH1)$correlations #without covariates, 0.12
hetcor(self_harm_data_c$SSH1, self_harm_data_c$NSSH1)$correlations # 0.87, same as in other less complex models.
vars <-c('pSANS','NSSH', 'SSH')
selVars <-c('trans_respSANS1', 'NSSH1', 'SSH1', 'trans_respSANS2', 'NSSH2', 'SSH2')
useVars <-c('trans_respSANS1', 'NSSH1', 'SSH1', 'trans_respSANS2', 'NSSH2', 'SSH2', 'age1', 'age2', 'sex1','sex2')
# Select Data for Analysis
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars)
describe(mzData)
describe(dzData)
nv <- 3 # number of variables per twin
nvo <-2 #number of ordinal variables per twin
nvc <-nv-nvo #number of continuous variables per twin
poso <- nvc+1 #position where ordinal variables start
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
nlower <- ntv*(ntv+1)/2 # number of free elements in a lower matrix ntv*ntv
ncor <-(nv*(nv+1)/2)-nv # number of free elements in a correlation matrix nv*nv
ninc <- nth-1 #number of max increments
ncovariates <- 2 #number of covariates
### Create starting values for covariance matrix
SHData_for_stv<-self_harm_data_c%>%
select('trans_respSANS1', 'NSSH1', 'SSH1', 'trans_respSANS2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(SHData_for_stv)
mzData_for_stv<-mzData%>%
select('trans_respSANS1', 'NSSH1', 'SSH1', 'trans_respSANS2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(mzData_for_stv)
dzData_for_stv<-dzData%>%
select('trans_respSANS1', 'NSSH1', 'SSH1', 'trans_respSANS2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(dzData_for_stv)
jiggle <-rnorm(nlower, mean = 0, sd = .1)
MZmean <-colMeans(mzData_for_stv,na.rm=TRUE)
DZmean <-colMeans(dzData_for_stv,na.rm=TRUE)
StMZmean<- c(mean(MZmean[c(1,4)]),0,0,mean(MZmean[c(1,4)]),0,0)
StDZmean<- c(mean(DZmean[c(1,4)]),0,0,mean(DZmean[c(1,4)]),0,0)
Stsd <-mean(sapply(mzData_for_stv[,c(1,4)],sd, na.rm=TRUE))
StWithinperson <-vechs(cor(SHData_for_stv[,1:3],use="pairwise"))
StBetweenMZ <-vech(cor(mzData_for_stv[,1:3],mzData_for_stv[,4:6],use="pairwise"))
StBetweenDZ <-vech(cor(dzData_for_stv[,1:3],dzData_for_stv[,4:6],use="pairwise"))
str(self_harm_data_c)
# 2) Specify ACE Model, with ONE overall set of Means, ONE overall Threshold on IQ liability
# To create Labels for Lower Triangular Matrices
StTH <-c(-0.32,0.45,0.19,0.15,0.70,0.54,0.24,0.15)
aLabs <- paste("a", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
cLabs <- paste("c", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
eLabs <- paste("e", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13','Tmz_21','imz_21','imz_22','imz_23') # THs for var 1 and 2 for a
LabCovA <-c('BageThNSSH', 'BageThNSSH','BageThNSSH', 'BageThNSSH', 'BageThSSH', 'BageThSSH','BageThSSH', 'BageThSSH')
LabCovS <-c('BsexThNSSH', 'BsexThNSSH','BsexThNSSH', 'BsexThNSSH', 'BsexThSSH', 'BsexThSSH','BsexThSSH', 'BsexThSSH')
# Matrices to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.64,0.25,0.14,0.72,0.62,0.23), labels=aLabs, name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.30,0.15,0.19,0.01,0.01,0.01), labels=cLabs, name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.84,0.03,0.12,0.67,0.50,0.42), labels=eLabs, name="e" )
# # Define definition variables to hold the Covariates
obsAge1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Age1")
obsAge2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Age2")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#effect of age and sex on ordinal variable
betaA <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovA, name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovS, name="BsexTH" )
#mean and thresholds
Mean <-mxMatrix( "Full", 1, ntv, free=c(T,F,F,T,F,F), values=StMZmean, labels=c("m1", NA,NA, "m1", NA,NA), name="ExpMean" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=StTH, lbound=c(-4,0.001,0.001,0.001), ubound=c(4,4),
labels=LabThMZ, name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH%x%Age1 + BsexTH%x%Sex1,
Low%*%Th + BageTH%x%Age2 + BsexTH%x%Sex2),
name="ExpThres")
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
# Algebra to compute standardized variance components
covP <- mxAlgebra( expression=A+C+E, name="V" )
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Constraint on total variance of Ordinal variable (A+C+E=1)
varL1 <- mxConstraint( expression=V[2,2]==1, name="L1" )
varL2 <- mxConstraint( expression=V[3,3]==1, name="L2" )
# Algebra to compute Rph-A, Rph-C & Rph-E between pSANS-NSSH
rphace_pSANS_NSSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE_pSANS_NSSH" )
rphace_pSANS_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[3,1]*sqrt(h2[3,3])),
(sqrt(c2[1,1])*Rc[3,1]*sqrt(c2[3,3])),
(sqrt(e2[1,1])*Re[3,1]*sqrt(e2[3,3])) ), name="RphACE_pSANS_SSH" )
rphace_NSSH_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[2,2])*Ra[3,2]*sqrt(h2[3,3])),
(sqrt(c2[2,2])*Rc[3,2]*sqrt(c2[3,3])),
(sqrt(e2[2,2])*Re[3,2]*sqrt(e2[3,3])) ), name="RphACE_NSSH_SSH" )
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[2,2], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[3,3], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[2,2], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[3,3], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[2,2], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[3,3], name="SSH_e")
#rA
raNSSHpSANS<-mxAlgebra(expression=Ra[2,1], name="rA_NSSH_pSANS")
raSSHpSANS<-mxAlgebra(expression=Ra[3,1], name="rA_SSH_pSANS")
#rC
rcNSSHpSANS<-mxAlgebra(expression=Rc[2,1], name="rC_NSSH_pSANS")
rcSSHpSANS<-mxAlgebra(expression=Rc[3,1], name="rC_SSH_pSANS")
#rE
reNSSHpSANS<-mxAlgebra(expression=Re[2,1], name="rE_NSSH_pSANS")
reSSHpSANS<-mxAlgebra(expression=Re[3,1], name="rE_SSH_pSANS")
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="ExpCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, StA, StC, StE, matI, rph, rA, rC, rE,
rphace_pSANS_NSSH,rphace_pSANS_SSH,rphace_NSSH_SSH,
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2,
raNSSHpSANS,raSSHpSANS,rcNSSHpSANS,rcSSHpSANS,reNSSHpSANS,reSSHpSANS)
modelMZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covMZ, dataMZ, objMZ, fitFunction, varL1, varL2, name="MZ" )
modelDZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
#confidence intervals
Conf1 <- mxCI (c('Rph[2,1]','Rph[3,1]'))
Conf2 <- mxCI ('Ra[2,1]')
Conf3 <- mxCI ('Ra[3,1]')
Conf4 <- mxCI ('Rc[2,1]')
Conf5 <- mxCI ('Rc[3,1]')
Conf6 <- mxCI ('Re[2,1]')
Conf7 <- mxCI ('Re[3,1]')
AceModel1 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf1) #
AceModel2 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf2) #
AceModel3 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf3) #
AceModel4 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf4) #
AceModel5 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf5) #
AceModel6 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf6) #
AceModel7 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf7) #
# 3) RUN AceModel
AceFit1 <- mxTryHardOrdinal(AceModel1, intervals=T) #best fit -2lnL should be 40393.31
AceFit2 <- mxTryHardOrdinal(AceModel2, intervals=T) #best fit -2lnL should be 40393.31
AceFit3 <- mxTryHardOrdinal(AceModel3, intervals=T) #best fit -2lnL should be 40393.31
AceFit4 <- mxTryHardOrdinal(AceModel4, intervals=T) #best fit -2lnL should be 40393.31
AceFit5 <- mxTryHardOrdinal(AceModel5, intervals=T) #best fit -2lnL should be 40393.31
AceFit6 <- mxTryHardOrdinal(AceModel6, intervals=T) #best fit -2lnL should be 40393.31
AceFit7 <- mxTryHardOrdinal(AceModel7, intervals=T) #best fit -2lnL should be 40393.31
(AceSum1 <- summary(AceFit1,verbose=T))
(AceSum2 <- summary(AceFit2,verbose=T))
(AceSum3 <- summary(AceFit3,verbose=T))
(AceSum4 <- summary(AceFit4,verbose=T))
(AceSum5 <- summary(AceFit5,verbose=T))
(AceSum6 <- summary(AceFit6,verbose=T))
(AceSum7 <- summary(AceFit7,verbose=T))
#get the estimates and CIs
CI1 <- AceSum1$CI
CI2 <- AceSum2$CI
CI3 <- AceSum3$CI
CI4 <- AceSum4$CI
CI5 <- AceSum5$CI
CI6 <- AceSum6$CI
CI7 <- AceSum7$CI
tot_CI<-rbind(CI1,CI2,CI3,CI4,CI5,CI6,CI7)
#evaluate the contents
mxEval(MZ.ExpCovMZ, AceFit1)
mxEval(DZ.ExpCovDZ, AceFit1)
mxEval(ACE.h2, AceFit1)
mxEval(ACE.c2, AceFit1)
mxEval(ACE.e2, AceFit1)
mxEval(ACE.Ra, AceFit1)
mxEval(ACE.Rc, AceFit1)
mxEval(ACE.Re, AceFit1)
mxEval(ACE.Rph, AceFit1)
mxEval(ACE.RphACE_pSANS_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1]*100
mxEval(ACE.RphACE_pSANS_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1]*100
mxEval(ACE.V,AceFit1)
#get the proportion explained by A,C and E in the phenotypic correlation
proportion<-as.data.frame(rbind((mxEval(ACE.RphACE_pSANS_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1])*100,
(mxEval(ACE.RphACE_pSANS_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1])*100,
mxEval(ACE.RphACE_pSANS_NSSH, AceFit1),
mxEval(ACE.RphACE_pSANS_SSH, AceFit1)),
row.names=c("NSSH%","SSH%", "NSSH","SSH"))
colnames(proportion)<-c("A","C","E")
proportion
#constrain the model
Sub1Model <- mxModel(AceModel1, name="sub1",
mxConstraint(MZ.rA_NSSH_pSANS==MZ.rA_SSH_pSANS, name="rA_con"),
mxConstraint(MZ.rC_NSSH_pSANS==MZ.rC_SSH_pSANS, name="rC_con"),
mxConstraint(MZ.rE_NSSH_pSANS==MZ.rE_SSH_pSANS, name="rE_con"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = F)
(Sub1Sum <- summary(Sub1Fit))
mxEval(MZ.NSSH_a,Sub1Fit);mxEval(MZ.SSH_a,Sub1Fit)
mxEval(MZ.NSSH_c,Sub1Fit);mxEval(MZ.SSH_c,Sub1Fit)
mxEval(MZ.NSSH_e,Sub1Fit);mxEval(MZ.SSH_e,Sub1Fit)
mxEval(MZ.path_a,Sub1Fit);mxEval(MZ.path_c,Sub1Fit);mxEval(MZ.path_e,Sub1Fit)
mxEval(MZ.Ra,Sub1Fit);mxEval(MZ.Rc,Sub1Fit);mxEval(MZ.Re,Sub1Fit)
mxEval(MZ.h2,Sub1Fit)
### compare with ACE model
comparison <- mxCompare(AceFit1,Sub1Fit)
# COMPARE MODELS: Print Comparative Fit Statistics
library(xlsx)
## 6) save the results
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_pSANS_SLSQP_ACE_04_June_2020.RData")
# save the estimates and their confidence intervals
write.xlsx(tot_CI, file="trivariate_estimates_with_CI_04_June_2020.xlsx",
sheetName="pSANS", append=TRUE)
# save the proportions
write.xlsx(proportion, file="trivariate_proportion_04_June_2020.xlsx",
sheetName="pSANS", append=TRUE)
# save the results of the chi-square test
write.xlsx(comparison, file="trivariate_constrained_results_04_June_2020.xlsx",
sheetName="pSANS", append=TRUE)
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
str(self_harm_data);class(self_harm_data)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,pcbhgrndt1,pcbhgrndt2,x3zygos,u1cage1,u1cage2,pcbhage1,pcbhage2, sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
self_harm_data_c <- mutate(self_harm_data_c, age_161 = ifelse(is.na(pcbhage1),pcbhage2 , pcbhage1))
self_harm_data_c <- mutate(self_harm_data_c, age_162 = ifelse(is.na(pcbhage2),pcbhage1 , pcbhage2))
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$SSH1)
table(self_harm_data_c$SSH2)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
str(self_harm_data_c)
#******************************************************
# Regress out age, sex and transform cGRAND variable
#******************************************************
#**Regressing out age & sex **#
self_harm_data_c$rescGRAND1 <- residuals(lm(self_harm_data_c$pcbhgrndt1 ~ self_harm_data_c$age_161 + self_harm_data_c$sex1, na.action="na.exclude"))
self_harm_data_c$rescGRAND2 <- residuals(lm(self_harm_data_c$pcbhgrndt2 ~ self_harm_data_c$age_162 + self_harm_data_c$sex2, na.action="na.exclude"))
hist(self_harm_data_c$pcbhgrndt1)
hist(self_harm_data_c$rescGRAND1)
describe(self_harm_data_c$rescGRAND1)
# #transform the data to get a normal distribution
self_harm_data_c$trans_rescGRAND1 <-sqrt(self_harm_data_c$rescGRAND1+6.24)*2
self_harm_data_c$trans_rescGRAND2 <-sqrt(self_harm_data_c$rescGRAND2+6.24)*2
hist(self_harm_data_c$rescGRAND1)
hist(self_harm_data_c$trans_rescGRAND1)
describe(self_harm_data_c$trans_rescGRAND1)
library(polycor) #check phenotypic correlation
hetcor(self_harm_data_c$trans_rescGRAND1, self_harm_data_c$NSSH1)$correlations #-0.04
hetcor(self_harm_data_c$pcbhgrndt1, self_harm_data_c$NSSH1)$correlations #without covariates, -0.06
hetcor(self_harm_data_c$SSH1, self_harm_data_c$NSSH1)$correlations # 0.87, same as in other less complex models.
vars <-c('cGRAND','NSSH', 'SSH')
selVars <-c('trans_rescGRAND1', 'NSSH1', 'SSH1', 'trans_rescGRAND2', 'NSSH2', 'SSH2')
useVars <-c('trans_rescGRAND1', 'NSSH1', 'SSH1', 'trans_rescGRAND2', 'NSSH2', 'SSH2', 'age1', 'age2', 'sex1','sex2')
# Select Data for Analysis
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars)
describe(mzData)
describe(dzData)
nv <- 3 # number of variables per twin
nvo <-2 #number of ordinal variables per twin
nvc <-nv-nvo #number of continuous variables per twin
poso <- nvc+1 #position where ordinal variables start
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
nlower <- ntv*(ntv+1)/2 # number of free elements in a lower matrix ntv*ntv
ncor <-(nv*(nv+1)/2)-nv # number of free elements in a correlation matrix nv*nv
ninc <- nth-1 #number of max increments
ncovariates <- 2 #number of covariates
### Create starting values for covariance matrix
SHData_for_stv<-self_harm_data_c%>%
select('trans_rescGRAND1', 'NSSH1', 'SSH1', 'trans_rescGRAND2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(SHData_for_stv)
mzData_for_stv<-mzData%>%
select('trans_rescGRAND1', 'NSSH1', 'SSH1', 'trans_rescGRAND2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(mzData_for_stv)
dzData_for_stv<-dzData%>%
select('trans_rescGRAND1', 'NSSH1', 'SSH1', 'trans_rescGRAND2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(dzData_for_stv)
jiggle <-rnorm(nlower, mean = 0, sd = .1)
MZmean <-colMeans(mzData_for_stv,na.rm=TRUE)
DZmean <-colMeans(dzData_for_stv,na.rm=TRUE)
StMZmean<- c(mean(MZmean[c(1,4)]),0,0,mean(MZmean[c(1,4)]),0,0)
StDZmean<- c(mean(DZmean[c(1,4)]),0,0,mean(DZmean[c(1,4)]),0,0)
Stsd <-mean(sapply(mzData_for_stv[,c(1,4)],sd, na.rm=TRUE))
StWithinperson <-vechs(cor(SHData_for_stv[,1:3],use="pairwise"))
StBetweenMZ <-vech(cor(mzData_for_stv[,1:3],mzData_for_stv[,4:6],use="pairwise"))
StBetweenDZ <-vech(cor(dzData_for_stv[,1:3],dzData_for_stv[,4:6],use="pairwise"))
str(self_harm_data_c)
# 2) Specify ACE Model, with ONE overall set of Means, ONE overall Threshold on IQ liability
# To create Labels for Lower Triangular Matrices
StTH <-c(-0.32,0.45,0.19,0.15,0.70,0.54,0.24,0.15)
aLabs <- paste("a", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
cLabs <- paste("c", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
eLabs <- paste("e", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13','Tmz_21','imz_21','imz_22','imz_23') # THs for var 1 and 2 for a
LabCovA <-c('BageThNSSH', 'BageThNSSH','BageThNSSH', 'BageThNSSH', 'BageThSSH', 'BageThSSH','BageThSSH', 'BageThSSH')
LabCovS <-c('BsexThNSSH', 'BsexThNSSH','BsexThNSSH', 'BsexThNSSH', 'BsexThSSH', 'BsexThSSH','BsexThSSH', 'BsexThSSH')
# Matrices to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.64,0.25,0.14,0.72,0.62,0.23), labels=aLabs, name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.30,0.15,0.19,0.01,0.01,0.01), labels=cLabs, name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.84,0.03,0.12,0.67,0.50,0.42), labels=eLabs, name="e" )
# # Define definition variables to hold the Covariates
obsAge1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Age1")
obsAge2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Age2")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#effect of age and sex on ordinal variable
betaA <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovA, name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovS, name="BsexTH" )
#mean and thresholds
Mean <-mxMatrix( "Full", 1, ntv, free=c(T,F,F,T,F,F), values=StMZmean, labels=c("m1", NA,NA, "m1", NA,NA), name="ExpMean" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=StTH, lbound=c(-4,0.001,0.001,0.001), ubound=c(4,4),
labels=LabThMZ, name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH%x%Age1 + BsexTH%x%Sex1,
Low%*%Th + BageTH%x%Age2 + BsexTH%x%Sex2),
name="ExpThres")
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
# Algebra to compute standardized variance components
covP <- mxAlgebra( expression=A+C+E, name="V" )
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Constraint on total variance of Ordinal variable (A+C+E=1)
varL1 <- mxConstraint( expression=V[2,2]==1, name="L1" )
varL2 <- mxConstraint( expression=V[3,3]==1, name="L2" )
# Algebra to compute Rph-A, Rph-C & Rph-E between cGRAND-NSSH
rphace_cGRAND_NSSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE_cGRAND_NSSH" )
rphace_cGRAND_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[3,1]*sqrt(h2[3,3])),
(sqrt(c2[1,1])*Rc[3,1]*sqrt(c2[3,3])),
(sqrt(e2[1,1])*Re[3,1]*sqrt(e2[3,3])) ), name="RphACE_cGRAND_SSH" )
rphace_NSSH_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[2,2])*Ra[3,2]*sqrt(h2[3,3])),
(sqrt(c2[2,2])*Rc[3,2]*sqrt(c2[3,3])),
(sqrt(e2[2,2])*Re[3,2]*sqrt(e2[3,3])) ), name="RphACE_NSSH_SSH" )
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[2,2], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[3,3], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[2,2], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[3,3], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[2,2], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[3,3], name="SSH_e")
#rA
raNSSHcGRAND<-mxAlgebra(expression=Ra[2,1], name="rA_NSSH_cGRAND")
raSSHcGRAND<-mxAlgebra(expression=Ra[3,1], name="rA_SSH_cGRAND")
#rC
rcNSSHcGRAND<-mxAlgebra(expression=Rc[2,1], name="rC_NSSH_cGRAND")
rcSSHcGRAND<-mxAlgebra(expression=Rc[3,1], name="rC_SSH_cGRAND")
#rE
reNSSHcGRAND<-mxAlgebra(expression=Re[2,1], name="rE_NSSH_cGRAND")
reSSHcGRAND<-mxAlgebra(expression=Re[3,1], name="rE_SSH_cGRAND")
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="ExpCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, StA, StC, StE, matI, rph, rA, rC, rE,
rphace_cGRAND_NSSH,rphace_cGRAND_SSH,rphace_NSSH_SSH,
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2,
raNSSHcGRAND,raSSHcGRAND,rcNSSHcGRAND,rcSSHcGRAND,reNSSHcGRAND,reSSHcGRAND)
modelMZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covMZ, dataMZ, objMZ, fitFunction, varL1, varL2, name="MZ" )
modelDZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
#confidence intervals
Conf1 <- mxCI (c('Rph[2,1]','Rph[3,1]'))
Conf2 <- mxCI ('Ra[2,1]')
Conf3 <- mxCI ('Ra[3,1]')
Conf4 <- mxCI ('Rc[2,1]')
Conf5 <- mxCI ('Rc[3,1]')
Conf6 <- mxCI ('Re[2,1]')
Conf7 <- mxCI ('Re[3,1]')
AceModel1 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf1) #
AceModel2 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf2) #
AceModel3 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf3) #
AceModel4 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf4) #
AceModel5 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf5) #
AceModel6 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf6) #
AceModel7 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf7) #
# 3) RUN AceModel
AceFit1 <- mxTryHardOrdinal(AceModel1, intervals=T) #best fit -2lnL should be 40393.31
AceFit2 <- mxTryHardOrdinal(AceModel2, intervals=T) #best fit -2lnL should be 40393.31
AceFit3 <- mxTryHardOrdinal(AceModel3, intervals=T) #best fit -2lnL should be 40393.31
AceFit4 <- mxTryHardOrdinal(AceModel4, intervals=T) #best fit -2lnL should be 40393.31
AceFit5 <- mxTryHardOrdinal(AceModel5, intervals=T) #best fit -2lnL should be 40393.31
AceFit6 <- mxTryHardOrdinal(AceModel6, intervals=T) #best fit -2lnL should be 40393.31
AceFit7 <- mxTryHardOrdinal(AceModel7, intervals=T) #best fit -2lnL should be 40393.31
(AceSum1 <- summary(AceFit1,verbose=T))
(AceSum2 <- summary(AceFit2,verbose=T))
(AceSum3 <- summary(AceFit3,verbose=T))
(AceSum4 <- summary(AceFit4,verbose=T))
(AceSum5 <- summary(AceFit5,verbose=T))
(AceSum6 <- summary(AceFit6,verbose=T))
(AceSum7 <- summary(AceFit7,verbose=T))
#get the estimates and CIs
CI1 <- AceSum1$CI
CI2 <- AceSum2$CI
CI3 <- AceSum3$CI
CI4 <- AceSum4$CI
CI5 <- AceSum5$CI
CI6 <- AceSum6$CI
CI7 <- AceSum7$CI
tot_CI<-rbind(CI1,CI2,CI3,CI4,CI5,CI6,CI7)
#evaluate the contents
mxEval(MZ.ExpCovMZ, AceFit1)
mxEval(DZ.ExpCovDZ, AceFit1)
mxEval(ACE.h2, AceFit1)
mxEval(ACE.c2, AceFit1)
mxEval(ACE.e2, AceFit1)
mxEval(ACE.Ra, AceFit1)
mxEval(ACE.Rc, AceFit1)
mxEval(ACE.Re, AceFit1)
mxEval(ACE.Rph, AceFit1)
mxEval(ACE.RphACE_cGRAND_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1]*100
mxEval(ACE.RphACE_cGRAND_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1]*100
mxEval(ACE.V,AceFit1)
#get the proportion explained by A,C and E in the phenotypic correlation
proportion<-as.data.frame(rbind((mxEval(ACE.RphACE_cGRAND_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1])*100,
(mxEval(ACE.RphACE_cGRAND_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1])*100,
mxEval(ACE.RphACE_cGRAND_NSSH, AceFit1),
mxEval(ACE.RphACE_cGRAND_SSH, AceFit1)),
row.names=c("NSSH%","SSH%", "NSSH","SSH"))
colnames(proportion)<-c("A","C","E")
proportion
#constrain the model
Sub1Model <- mxModel(AceModel1, name="sub1",
mxConstraint(MZ.rA_NSSH_cGRAND==MZ.rA_SSH_cGRAND, name="rA_con"),
mxConstraint(MZ.rC_NSSH_cGRAND==MZ.rC_SSH_cGRAND, name="rC_con"),
mxConstraint(MZ.rE_NSSH_cGRAND==MZ.rE_SSH_cGRAND, name="rE_con"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = F)
(Sub1Sum <- summary(Sub1Fit))
mxEval(MZ.NSSH_a,Sub1Fit);mxEval(MZ.SSH_a,Sub1Fit)
mxEval(MZ.NSSH_c,Sub1Fit);mxEval(MZ.SSH_c,Sub1Fit)
mxEval(MZ.NSSH_e,Sub1Fit);mxEval(MZ.SSH_e,Sub1Fit)
mxEval(MZ.path_a,Sub1Fit);mxEval(MZ.path_c,Sub1Fit);mxEval(MZ.path_e,Sub1Fit)
mxEval(MZ.Ra,Sub1Fit);mxEval(MZ.Rc,Sub1Fit);mxEval(MZ.Re,Sub1Fit)
mxEval(MZ.h2,Sub1Fit)
### compare with ACE model
comparison <- mxCompare(AceFit1,Sub1Fit)
library(xlsx)
## 6) save the results
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_cGRAND_SLSQP_ACE_04_June_2020.RData")
# save the estimates and their confidence intervals
write.xlsx(tot_CI, file="trivariate_estimates_with_CI_04_June_2020.xlsx",
sheetName="cGRAND", append=TRUE)
# save the proportions
write.xlsx(proportion, file="trivariate_proportion_04_June_2020.xlsx",
sheetName="cGRAND", append=TRUE)
# save the results of the chi-square test
write.xlsx(comparison, file="trivariate_constrained_results_04_June_2020.xlsx",
sheetName="cGRAND", append=TRUE)
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
str(self_harm_data);class(self_harm_data)
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,pcbhtepst1,pcbhtepst2,x3zygos,u1cage1,u1cage2,pcbhage1,pcbhage2, sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age1 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age2 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
self_harm_data_c <- mutate(self_harm_data_c, age_161 = ifelse(is.na(pcbhage1),pcbhage2 , pcbhage1))
self_harm_data_c <- mutate(self_harm_data_c, age_162 = ifelse(is.na(pcbhage2),pcbhage1 , pcbhage2))
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$SSH1)
table(self_harm_data_c$SSH2)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
str(self_harm_data_c)
#******************************************************
# Regress out age, sex and transform cTEPS variable
#******************************************************
#**Regressing out age & sex **#
self_harm_data_c$rescTEPS1 <- residuals(lm(self_harm_data_c$pcbhtepst1 ~ self_harm_data_c$age_161 + self_harm_data_c$sex1, na.action="na.exclude"))
self_harm_data_c$rescTEPS2 <- residuals(lm(self_harm_data_c$pcbhtepst2 ~ self_harm_data_c$age_162 + self_harm_data_c$sex2, na.action="na.exclude"))
hist(self_harm_data_c$pcbhtepst1)
hist(self_harm_data_c$rescTEPS1)
describe(self_harm_data_c$rescTEPS1)
# #transform the data to get a normal distribution
self_harm_data_c$trans_rescTEPS1 <-(self_harm_data_c$rescTEPS1)
self_harm_data_c$trans_rescTEPS2 <-(self_harm_data_c$rescTEPS2)
hist(self_harm_data_c$rescTEPS1)
hist(self_harm_data_c$trans_rescTEPS1)
describe(self_harm_data_c$trans_rescTEPS1)
library(polycor) #check phenotypic correlation
hetcor(self_harm_data_c$trans_rescTEPS1, self_harm_data_c$NSSH1)$correlations #0.23
hetcor(self_harm_data_c$rescTEPS1, self_harm_data_c$NSSH1)$correlations #0.22
hetcor(self_harm_data_c$pcbhtepst1, self_harm_data_c$NSSH1)$correlations #without covariates, 0.25
hetcor(self_harm_data_c$SSH1, self_harm_data_c$NSSH1)$correlations # 0.87, same as in other less complex models.
vars <-c('cTEPS','NSSH', 'SSH')
selVars <-c('trans_rescTEPS1', 'NSSH1', 'SSH1', 'trans_rescTEPS2', 'NSSH2', 'SSH2')
useVars <-c('trans_rescTEPS1', 'NSSH1', 'SSH1', 'trans_rescTEPS2', 'NSSH2', 'SSH2', 'age1', 'age2', 'sex1','sex2')
# Select Data for Analysis
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(age1&age2) &!is.na(sex1&sex2), useVars)
describe(mzData)
describe(dzData)
nv <- 3 # number of variables per twin
nvo <-2 #number of ordinal variables per twin
nvc <-nv-nvo #number of continuous variables per twin
poso <- nvc+1 #position where ordinal variables start
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
nlower <- ntv*(ntv+1)/2 # number of free elements in a lower matrix ntv*ntv
ncor <-(nv*(nv+1)/2)-nv # number of free elements in a correlation matrix nv*nv
ninc <- nth-1 #number of max increments
ncovariates <- 2 #number of covariates
### Create starting values for covariance matrix
SHData_for_stv<-self_harm_data_c%>%
select('trans_rescTEPS1', 'NSSH1', 'SSH1', 'trans_rescTEPS2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(SHData_for_stv)
mzData_for_stv<-mzData%>%
select('trans_rescTEPS1', 'NSSH1', 'SSH1', 'trans_rescTEPS2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(mzData_for_stv)
dzData_for_stv<-dzData%>%
select('trans_rescTEPS1', 'NSSH1', 'SSH1', 'trans_rescTEPS2', 'NSSH2', 'SSH2')%>%
mutate_if(is.factor, as.numeric)
str(dzData_for_stv)
jiggle <-rnorm(nlower, mean = 0, sd = .1)
MZmean <-colMeans(mzData_for_stv,na.rm=TRUE)
DZmean <-colMeans(dzData_for_stv,na.rm=TRUE)
StMZmean<- c(mean(MZmean[c(1,4)]),0,0,mean(MZmean[c(1,4)]),0,0)
StDZmean<- c(mean(DZmean[c(1,4)]),0,0,mean(DZmean[c(1,4)]),0,0)
Stsd <-mean(sapply(mzData_for_stv[,c(1,4)],sd, na.rm=TRUE))
StWithinperson <-vechs(cor(SHData_for_stv[,1:3],use="pairwise"))
StBetweenMZ <-vech(cor(mzData_for_stv[,1:3],mzData_for_stv[,4:6],use="pairwise"))
StBetweenDZ <-vech(cor(dzData_for_stv[,1:3],dzData_for_stv[,4:6],use="pairwise"))
str(self_harm_data_c)
# 2) Specify ACE Model, with ONE overall set of Means, ONE overall Threshold on IQ liability
# To create Labels for Lower Triangular Matrices
StTH <-c(-0.32,0.45,0.19,0.15,0.70,0.54,0.24,0.15)
aLabs <- paste("a", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
cLabs <- paste("c", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
eLabs <- paste("e", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13','Tmz_21','imz_21','imz_22','imz_23') # THs for var 1 and 2 for a twin individual (mz)
LabCovA <-c('BageThNSSH', 'BageThNSSH','BageThNSSH', 'BageThNSSH', 'BageThSSH', 'BageThSSH','BageThSSH', 'BageThSSH')
LabCovS <-c('BsexThNSSH', 'BsexThNSSH','BsexThNSSH', 'BsexThNSSH', 'BsexThSSH', 'BsexThSSH','BsexThSSH', 'BsexThSSH')
# Matrices to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.64,0.25,0.14,0.72,0.62,0.23), labels=aLabs, name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.30,0.15,0.19,0.01,0.01,0.01), labels=cLabs, name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.84,0.03,0.12,0.67,0.50,0.42), labels=eLabs, name="e" )
# # Define definition variables to hold the Covariates
obsAge1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age1"), name="Age1")
obsAge2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age2"), name="Age2")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#effect of age and sex on ordinal variable
betaA <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovA, name="BageTH" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=.2, labels=LabCovS, name="BsexTH" )
#mean and thresholds
Mean <-mxMatrix( "Full", 1, ntv, free=c(T,F,F,T,F,F), values=StMZmean, labels=c("m1", NA,NA, "m1", NA,NA), name="ExpMean" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=T, values=StTH, lbound=c(-4,0.001,0.001,0.001), ubound=c(4,4),
labels=LabThMZ, name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH%x%Age1 + BsexTH%x%Sex1,
Low%*%Th + BageTH%x%Age2 + BsexTH%x%Sex2),
name="ExpThres")
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
# Algebra to compute standardized variance components
covP <- mxAlgebra( expression=A+C+E, name="V" )
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Constraint on total variance of Ordinal variable (A+C+E=1)
varL1 <- mxConstraint( expression=V[2,2]==1, name="L1" )
varL2 <- mxConstraint( expression=V[3,3]==1, name="L2" )
# Algebra to compute Rph-A, Rph-C & Rph-E between cTEPS-NSSH
rphace_cTEPS_NSSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE_cTEPS_NSSH" )
rphace_cTEPS_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[3,1]*sqrt(h2[3,3])),
(sqrt(c2[1,1])*Rc[3,1]*sqrt(c2[3,3])),
(sqrt(e2[1,1])*Re[3,1]*sqrt(e2[3,3])) ), name="RphACE_cTEPS_SSH" )
rphace_NSSH_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[2,2])*Ra[3,2]*sqrt(h2[3,3])),
(sqrt(c2[2,2])*Rc[3,2]*sqrt(c2[3,3])),
(sqrt(e2[2,2])*Re[3,2]*sqrt(e2[3,3])) ), name="RphACE_NSSH_SSH" )
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[2,2], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[3,3], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[2,2], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[3,3], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[2,2], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[3,3], name="SSH_e")
#rA
raNSSHcTEPS<-mxAlgebra(expression=Ra[2,1], name="rA_NSSH_cTEPS")
raSSHcTEPS<-mxAlgebra(expression=Ra[3,1], name="rA_SSH_cTEPS")
#rC
rcNSSHcTEPS<-mxAlgebra(expression=Rc[2,1], name="rC_NSSH_cTEPS")
rcSSHcTEPS<-mxAlgebra(expression=Rc[3,1], name="rC_SSH_cTEPS")
#rE
reNSSHcTEPS<-mxAlgebra(expression=Re[2,1], name="rE_NSSH_cTEPS")
reSSHcTEPS<-mxAlgebra(expression=Re[3,1], name="rE_SSH_cTEPS")
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="ExpCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('NSSH1','SSH1','NSSH2', 'SSH2') )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, StA, StC, StE, matI, rph, rA, rC, rE,
rphace_cTEPS_NSSH,rphace_cTEPS_SSH,rphace_NSSH_SSH,
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2,
raNSSHcTEPS,raSSHcTEPS,rcNSSHcTEPS,rcSSHcTEPS,reNSSHcTEPS,reSSHcTEPS)
modelMZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covMZ, dataMZ, objMZ, fitFunction, varL1, varL2, name="MZ" )
modelDZ <- mxModel( pars, obsAge1, obsAge2, obsSex1, obsSex2 ,Mean, Tr, inc, Thres, betaA, betaS,
covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
#confidence intervals
Conf1 <- mxCI (c('Rph[2,1]','Rph[3,1]'))
Conf2 <- mxCI ('Ra[2,1]')
Conf3 <- mxCI ('Ra[3,1]')
Conf4 <- mxCI ('Rc[2,1]')
Conf5 <- mxCI ('Rc[3,1]')
Conf6 <- mxCI ('Re[2,1]')
Conf7 <- mxCI ('Re[3,1]')
AceModel1 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf1) #
AceModel2 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf2) #
AceModel3 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf3) #
AceModel4 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf4) #
AceModel5 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf5) #
AceModel6 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf6) #
AceModel7 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf7) #
# 3) RUN AceModel
AceFit1 <- mxTryHardOrdinal(AceModel1, intervals=T) #best fit -2lnL should be 40393.31
AceFit2 <- mxTryHardOrdinal(AceModel2, intervals=T) #best fit -2lnL should be 40393.31
AceFit3 <- mxTryHardOrdinal(AceModel3, intervals=T) #best fit -2lnL should be 40393.31
AceFit4 <- mxTryHardOrdinal(AceModel4, intervals=T) #best fit -2lnL should be 40393.31
AceFit5 <- mxTryHardOrdinal(AceModel5, intervals=T) #best fit -2lnL should be 40393.31
AceFit6 <- mxTryHardOrdinal(AceModel6, intervals=T) #best fit -2lnL should be 40393.31
AceFit7 <- mxTryHardOrdinal(AceModel7, intervals=T) #best fit -2lnL should be 40393.31
(AceSum1 <- summary(AceFit1,verbose=T))
(AceSum2 <- summary(AceFit2,verbose=T))
(AceSum3 <- summary(AceFit3,verbose=T))
(AceSum4 <- summary(AceFit4,verbose=T))
(AceSum5 <- summary(AceFit5,verbose=T))
(AceSum6 <- summary(AceFit6,verbose=T))
(AceSum7 <- summary(AceFit7,verbose=T))
#get the estimates and CIs
CI1 <- AceSum1$CI
CI2 <- AceSum2$CI
CI3 <- AceSum3$CI
CI4 <- AceSum4$CI
CI5 <- AceSum5$CI
CI6 <- AceSum6$CI
CI7 <- AceSum7$CI
tot_CI<-rbind(CI1,CI2,CI3,CI4,CI5,CI6,CI7)
#evaluate the contents
mxEval(MZ.ExpCovMZ, AceFit1)
mxEval(DZ.ExpCovDZ, AceFit1)
mxEval(ACE.h2, AceFit1)
mxEval(ACE.c2, AceFit1)
mxEval(ACE.e2, AceFit1)
mxEval(ACE.Ra, AceFit1)
mxEval(ACE.Rc, AceFit1)
mxEval(ACE.Re, AceFit1)
mxEval(ACE.Rph, AceFit1)
mxEval(ACE.RphACE_cTEPS_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1]*100
mxEval(ACE.RphACE_cTEPS_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1]*100
mxEval(ACE.V,AceFit1)
#get the proportion explained by A,C and E in the phenotypic correlation
proportion<-as.data.frame(rbind((mxEval(ACE.RphACE_cTEPS_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1])*100,
(mxEval(ACE.RphACE_cTEPS_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1])*100,
mxEval(ACE.RphACE_cTEPS_NSSH, AceFit1),
mxEval(ACE.RphACE_cTEPS_SSH, AceFit1)),
row.names=c("NSSH%","SSH%", "NSSH","SSH"))
colnames(proportion)<-c("A","C","E")
proportion
#constrain the model
Sub1Model <- mxModel(AceModel1, name="sub1",
mxConstraint(MZ.rA_NSSH_cTEPS==MZ.rA_SSH_cTEPS, name="rA_con"),
mxConstraint(MZ.rC_NSSH_cTEPS==MZ.rC_SSH_cTEPS, name="rC_con"),
mxConstraint(MZ.rE_NSSH_cTEPS==MZ.rE_SSH_cTEPS, name="rE_con"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = F)
(Sub1Sum <- summary(Sub1Fit))
mxEval(MZ.NSSH_a,Sub1Fit);mxEval(MZ.SSH_a,Sub1Fit)
mxEval(MZ.NSSH_c,Sub1Fit);mxEval(MZ.SSH_c,Sub1Fit)
mxEval(MZ.NSSH_e,Sub1Fit);mxEval(MZ.SSH_e,Sub1Fit)
mxEval(MZ.path_a,Sub1Fit);mxEval(MZ.path_c,Sub1Fit);mxEval(MZ.path_e,Sub1Fit)
mxEval(MZ.Ra,Sub1Fit);mxEval(MZ.Rc,Sub1Fit);mxEval(MZ.Re,Sub1Fit)
mxEval(MZ.h2,Sub1Fit)
### compare with ACE model
comparison <- mxCompare(AceFit1,Sub1Fit)
library(xlsx)
## 6) save the results
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_cTEPS_SLSQP_ACE_04_June_2020.RData")
# save the estimates and their confidence intervals
write.xlsx(tot_CI, file="trivariate_estimates_with_CI_04_June_2020.xlsx",
sheetName="cTEPS", append=TRUE)
# save the proportions
write.xlsx(proportion, file="trivariate_proportion_04_June_2020.xlsx",
sheetName="cTEPS", append=TRUE)
# save the results of the chi-square test
write.xlsx(comparison, file="trivariate_constrained_results_04_June_2020.xlsx",
sheetName="cTEPS", append=TRUE)
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse);require(polycor)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
hetcor(self_harm_data$pcbhdrug121, self_harm_data$u1cslfh021)$correlations #0.12
hetcor(self_harm_data$pcbhdrug131, self_harm_data$u1cslfh021)$correlations #0.19
hetcor(self_harm_data$pcbhdrug151, self_harm_data$u1cslfh021)$correlations #0.18
table(self_harm_data$pcbhdrug131);table(self_harm_data$pcbhdrug151)
str(self_harm_data);class(self_harm_data)
plot(self_harm_data$pcbhdrug151) #how many times using cannabis - more normally distributed and makes more sense
#using this variable, but need to recode from "no" in previous question
plot(self_harm_data$pcbhdrug131) #how often using cannabis
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,pcbhdrug061, pcbhdrug062, pcbhdrug091,pcbhdrug092,x3zygos,u1cage1,u1cage2,pcbhage1,pcbhage2, sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age_211 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age_212 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
hist(self_harm_data_c$u1cage1)
hist(self_harm_data_c$age_211)
self_harm_data_c <- mutate(self_harm_data_c, age_161 = ifelse(is.na(pcbhage1),pcbhage2 , pcbhage1))
self_harm_data_c <- mutate(self_harm_data_c, age_162 = ifelse(is.na(pcbhage2),pcbhage1 , pcbhage2))
hist(self_harm_data_c$pcbhage1)
hist(self_harm_data_c$age_161)
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$pcbhdrug121)
table(self_harm_data_c$pcbhdrug151)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
#bring zeros from never used cannabis into number of times using cannabis
self_harm_data_c <- mutate(self_harm_data_c, cSMOK1 = ifelse(is.na(pcbhdrug091)&pcbhdrug061==0,pcbhdrug061,pcbhdrug091))
self_harm_data_c <- mutate(self_harm_data_c, cSMOK2 = ifelse(is.na(pcbhdrug092)&pcbhdrug062==0,pcbhdrug062,pcbhdrug092))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$SSH1)
table(self_harm_data_c$SSH2)
table(self_harm_data_c$pcbhdrug061)
table(self_harm_data_c$pcbhdrug062)
table(self_harm_data_c$pcbhdrug091)
table(self_harm_data_c$pcbhdrug092)
table(self_harm_data_c$cSMOK1)
table(self_harm_data_c$cSMOK2)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
self_harm_data_c$cSMOK1<-mxFactor(self_harm_data_c$cSMOK1, levels=c(0:5) )
self_harm_data_c$cSMOK2<-mxFactor(self_harm_data_c$cSMOK2, levels=c(0:5) )
str(self_harm_data_c)
#check phenotypic correlation
hetcor(self_harm_data_c$cSMOK1, self_harm_data_c$NSSH1)$correlations #0.24
hetcor(self_harm_data_c$cSMOK1, self_harm_data_c$SSH1)$correlations # 0.26
hetcor(self_harm_data_c$SSH1, self_harm_data_c$NSSH1)$correlations # 0.87, same as in other less complex models.
vars <-c('cSMOK','NSSH', 'SSH')
selVars <-c('cSMOK1', 'NSSH1', 'SSH1', 'cSMOK2', 'NSSH2', 'SSH2')
useVars <-c('cSMOK1', 'NSSH1', 'SSH1', 'cSMOK2', 'NSSH2', 'SSH2', 'age_161', 'age_162','age_211', 'age_212', 'sex1','sex2')
# Select Data for Analysis
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(age_211&age_212) &!is.na(age_161&age_162) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(age_211&age_212) &!is.na(age_161&age_162) &!is.na(sex1&sex2), useVars)
describe(mzData)
describe(dzData)
nv <- 3 # number of variables per twin
nvo <-3 #number of ordinal variables per twin
nvc <-nv-nvo #number of continuous variables per twin
poso <- nvc+1 #position where ordinal variables start
ntv <- nv*2 # number of variables per pair
nth <- 5 # number of max thresholds
nlower <- ntv*(ntv+1)/2 # number of free elements in a lower matrix ntv*ntv
ncor <-(nv*(nv+1)/2)-nv # number of free elements in a correlation matrix nv*nv
ninc <- nth-1 #number of max increments
ncovariates <- 2 #number of covariates
# 2) Specify ACE Model
# To create Labels for Lower Triangular Matrices
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13','imz_14',
'Tmz_21','imz_21','imz_22','imz_23','imz_24',
'Tmz_31','imz_31','imz_32','imz_33','imz_34') # THs for var 1 and 2 for a twin individual (mz)
LabCovA21 <-c(rep('BageThNULL21',5),rep('BageThNSSH21',4),'BageThNULL21',rep('BageThSSH21',4),'BageThNULL21')
LabCovA16 <-c(rep('BageThDRUG16',5),rep('BageThNULL16',5),rep('BageThNULL16',5))
LabCovS <-c(rep('BsexThDRUG',5),rep('BsexThNSSH',4),'BsexThNULL',rep('BsexThSSH',4),'BsexThNULL')
StTH <-c(6.17,0.52,0.27,0.27,0.27,
-0.20,0.45,0.19,0.15,0,
0.88,0.55,0.25,0.16, 0)
ThPatSH <-c(rep(T,5),rep(T,4),F,rep(T,4),F)
aLabs <- paste("a", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
cLabs <- paste("c", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
eLabs <- paste("e", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
# Matrices to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(1.0,0.19,0.23,0.68,0.58,0.23), labels=aLabs, name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.74,0.18,0.19,0.002,0.002,0.005), labels=cLabs, name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(4.43,0.09,0.08,0.67,0.56,0.43), labels=eLabs, name="e" )
# # Define definition variables to hold the Covariates
obsAge211 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age_211"), name="Age211")
obsAge212 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age_212"), name="Age212")
obsAge161 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age_161"), name="Age161")
obsAge162 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age_162"), name="Age162")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#effect of age and sex on ordinal variable
value_sex<-c(rep(0.2,5),rep(0.2,4),0,rep(0.2,4),0)
free_sex <-c(rep(T,5),rep(T,4),F,rep(T,4),F)
value_age16<-c(rep(0.2,5),rep(0,5),rep(0,5))
free_age16 <-c(rep(T,5),rep(F,5),rep(F,5))
value_age21<-c(rep(0,5),rep(0.2,4),0,rep(0.2,4),0)
free_age21 <-c(rep(F,5),rep(T,4),F,rep(T,4),F)
betaA21 <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=free_age21, values=value_age21, labels=LabCovA21, name="BageTH21" )
betaA16 <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=free_age16, values=value_age16, labels=LabCovA16, name="BageTH16" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=free_sex, values=value_sex, labels=LabCovS, name="BsexTH" )
#mean and thresholds, no mean if all variables are ordinals
Mean <-mxMatrix( type="Zero", nrow=1, ncol=ntv, name="ExpMean" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=ThPatSH, values=StTH, lbound=-4, ubound=100,
labels=LabThMZ, name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH21%x%Age211+ BageTH16%x%Age161 + BsexTH%x%Sex1,
Low%*%Th + BageTH21%x%Age212+ BageTH16%x%Age162 + BsexTH%x%Sex2),
name="ExpThres")
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
# Algebra to compute standardized variance components
covP <- mxAlgebra( expression=A+C+E, name="V" )
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Constraint on total variance of Ordinal variable (A+C+E=1)
varL1 <- mxConstraint( expression=V[1,1]==1, name="L1" )
varL2 <- mxConstraint( expression=V[2,2]==1, name="L2" )
varL3 <- mxConstraint( expression=V[3,3]==1, name="L3" )
# Algebra to compute Rph-A, Rph-C & Rph-E between cSMOK-NSSH
rphace_cSMOK_NSSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE_cSMOK_NSSH" )
rphace_cSMOK_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[3,1]*sqrt(h2[3,3])),
(sqrt(c2[1,1])*Rc[3,1]*sqrt(c2[3,3])),
(sqrt(e2[1,1])*Re[3,1]*sqrt(e2[3,3])) ), name="RphACE_cSMOK_SSH" )
rphace_NSSH_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[2,2])*Ra[3,2]*sqrt(h2[3,3])),
(sqrt(c2[2,2])*Rc[3,2]*sqrt(c2[3,3])),
(sqrt(e2[2,2])*Re[3,2]*sqrt(e2[3,3])) ), name="RphACE_NSSH_SSH" )
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[2,2], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[3,3], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[2,2], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[3,3], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[2,2], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[3,3], name="SSH_e")
#rA
raNSSHcSMOK<-mxAlgebra(expression=Ra[2,1], name="rA_NSSH_cSMOK")
raSSHcSMOK<-mxAlgebra(expression=Ra[3,1], name="rA_SSH_cSMOK")
#rC
rcNSSHcSMOK<-mxAlgebra(expression=Rc[2,1], name="rC_NSSH_cSMOK")
rcSSHcSMOK<-mxAlgebra(expression=Rc[3,1], name="rC_SSH_cSMOK")
#rE
reNSSHcSMOK<-mxAlgebra(expression=Re[2,1], name="rE_NSSH_cSMOK")
reSSHcSMOK<-mxAlgebra(expression=Re[3,1], name="rE_SSH_cSMOK")
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="ExpCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('cSMOK1', 'NSSH1', 'SSH1', 'cSMOK2', 'NSSH2', 'SSH2') )
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('cSMOK1', 'NSSH1', 'SSH1', 'cSMOK2', 'NSSH2', 'SSH2') )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, StA, StC, StE, matI, rph, rA, rC, rE,
rphace_cSMOK_NSSH,rphace_cSMOK_SSH,rphace_NSSH_SSH,
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2,
raNSSHcSMOK,raSSHcSMOK,rcNSSHcSMOK,rcSSHcSMOK,reNSSHcSMOK,reSSHcSMOK)
modelMZ <- mxModel( pars, obsAge211, obsAge212,obsAge161,obsAge162, obsSex1, obsSex2 , Mean, Tr, inc, Thres,
betaA21,betaA16, betaS, covMZ, dataMZ, objMZ, fitFunction, varL1, varL2, varL3, name="MZ" )
modelDZ <- mxModel( pars, obsAge211, obsAge212,obsAge161,obsAge162, obsSex1, obsSex2 , Mean, Tr, inc, Thres,
betaA21,betaA16, betaS, covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
#confidence intervals
Conf1 <- mxCI (c('Rph[2,1]','Rph[3,1]'))
Conf2 <- mxCI ('Ra[2,1]')
Conf3 <- mxCI ('Ra[3,1]')
Conf4 <- mxCI ('Rc[2,1]')
Conf5 <- mxCI ('Rc[3,1]')
Conf6 <- mxCI ('Re[2,1]')
Conf7 <- mxCI ('Re[3,1]')
AceModel1 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf1)
AceModel2 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf2)
AceModel3 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf3)
AceModel4 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf4)
AceModel5 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf5)
AceModel6 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf6)
AceModel7 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf7)
# 3) RUN AceModel
AceFit1 <- mxTryHardOrdinal(AceModel1, intervals=T) #fit = 25519.628
AceFit2 <- mxTryHardOrdinal(AceModel2, intervals=T)
AceFit3 <- mxTryHardOrdinal(AceModel3, intervals=T)
AceFit4 <- mxTryHardOrdinal(AceModel4, intervals=T)
AceFit5 <- mxTryHardOrdinal(AceModel5, intervals=T)
AceFit6 <- mxTryHardOrdinal(AceModel6, intervals=T)
AceFit7 <- mxTryHardOrdinal(AceModel7, intervals=T)
(AceSum1 <- summary(AceFit1,verbose=T))
(AceSum2 <- summary(AceFit2,verbose=T))
(AceSum3 <- summary(AceFit3,verbose=T))
(AceSum4 <- summary(AceFit4,verbose=T))
(AceSum5 <- summary(AceFit5,verbose=T))
(AceSum6 <- summary(AceFit6,verbose=T))
(AceSum7 <- summary(AceFit7,verbose=T))
#get the estimates and CIs
CI1 <- AceSum1$CI
CI2 <- AceSum2$CI
CI3 <- AceSum3$CI
CI4 <- AceSum4$CI
CI5 <- AceSum5$CI
CI6 <- AceSum6$CI
CI7 <- AceSum7$CI
tot_CI<-rbind(CI1,CI2,CI3,CI4,CI5,CI6,CI7)
#evaluate the contents
mxEval(MZ.ExpCovMZ, AceFit1)
mxEval(DZ.ExpCovDZ, AceFit1)
mxEval(ACE.h2, AceFit1)
mxEval(ACE.c2, AceFit1)
mxEval(ACE.e2, AceFit1)
mxEval(ACE.Ra, AceFit1)
mxEval(ACE.Rc, AceFit1)
mxEval(ACE.Re, AceFit1)
mxEval(ACE.Rph, AceFit1)
mxEval(ACE.RphACE_cSMOK_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1]*100
mxEval(ACE.RphACE_cSMOK_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1]*100
mxEval(ACE.V,AceFit1)
#get the proportion explained by A,C and E in the phenotypic correlation
proportion<-as.data.frame(rbind((mxEval(ACE.RphACE_cSMOK_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1])*100,
(mxEval(ACE.RphACE_cSMOK_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1])*100,
mxEval(ACE.RphACE_cSMOK_NSSH, AceFit1),
mxEval(ACE.RphACE_cSMOK_SSH, AceFit1)),
row.names=c("NSSH%","SSH%", "NSSH","SSH"))
colnames(proportion)<-c("A","C","E")
proportion
#constrain the model
Sub1Model <- mxModel(AceModel1, name="sub1",
mxConstraint(MZ.rA_NSSH_cSMOK==MZ.rA_SSH_cSMOK, name="rA_con"),
mxConstraint(MZ.rC_NSSH_cSMOK==MZ.rC_SSH_cSMOK, name="rC_con"),
mxConstraint(MZ.rE_NSSH_cSMOK==MZ.rE_SSH_cSMOK, name="rE_con"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = F)
(Sub1Sum <- summary(Sub1Fit))
mxEval(MZ.NSSH_a,Sub1Fit);mxEval(MZ.SSH_a,Sub1Fit)
mxEval(MZ.NSSH_c,Sub1Fit);mxEval(MZ.SSH_c,Sub1Fit)
mxEval(MZ.NSSH_e,Sub1Fit);mxEval(MZ.SSH_e,Sub1Fit)
mxEval(MZ.path_a,Sub1Fit);mxEval(MZ.path_c,Sub1Fit);mxEval(MZ.path_e,Sub1Fit)
mxEval(MZ.Ra,Sub1Fit);mxEval(MZ.Rc,Sub1Fit);mxEval(MZ.Re,Sub1Fit)
mxEval(MZ.h2,Sub1Fit)
### compare with ACE model
comparison <- mxCompare(AceFit1,Sub1Fit)
library(xlsx)
## 6) save the results
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_cSMOK_SLSQP_ACE_04_June_2020.RData")
# save the estimates and their confidence intervals
write.xlsx(tot_CI, file="trivariate_estimates_with_CI_04_June_2020.xlsx",
sheetName="cSMOK", append=TRUE)
# save the proportions
write.xlsx(proportion, file="trivariate_proportion_04_June_2020.xlsx",
sheetName="cSMOK", append=TRUE)
# save the results of the chi-square test
write.xlsx(comparison, file="trivariate_constrained_results_04_June_2020.xlsx",
sheetName="cSMOK", append=TRUE)
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse);require(polycor)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
hetcor(self_harm_data$pcbhdrug121, self_harm_data$u1cslfh021)$correlations #0.12
hetcor(self_harm_data$pcbhdrug131, self_harm_data$u1cslfh021)$correlations #0.19
hetcor(self_harm_data$pcbhdrug151, self_harm_data$u1cslfh021)$correlations #0.18
table(self_harm_data$pcbhdrug131);table(self_harm_data$pcbhdrug151)
str(self_harm_data);class(self_harm_data)
plot(self_harm_data$pcbhdrug151) #how many times using cannabis - more normally distributed and makes more sense
#using this variable, but need to recode from "no" in previous question
plot(self_harm_data$pcbhdrug131) #how often using cannabis
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,pcbhdrug121, pcbhdrug122, pcbhdrug151,pcbhdrug152,x3zygos,u1cage1,u1cage2,pcbhage1,pcbhage2, sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age_211 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age_212 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
self_harm_data_c <- mutate(self_harm_data_c, age_161 = ifelse(is.na(pcbhage1),pcbhage2 , pcbhage1))
self_harm_data_c <- mutate(self_harm_data_c, age_162 = ifelse(is.na(pcbhage2),pcbhage1 , pcbhage2))
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$pcbhdrug121)
table(self_harm_data_c$pcbhdrug151)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
#bring zeros from never used cannabis into number of times using cannabis
self_harm_data_c <- mutate(self_harm_data_c, cCANN1 = ifelse(is.na(pcbhdrug151)&pcbhdrug121==0,pcbhdrug121,pcbhdrug151))
self_harm_data_c <- mutate(self_harm_data_c, cCANN2 = ifelse(is.na(pcbhdrug152)&pcbhdrug122==0,pcbhdrug122,pcbhdrug152))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$SSH1)
table(self_harm_data_c$SSH2)
table(self_harm_data_c$pcbhdrug121)
table(self_harm_data_c$pcbhdrug122)
table(self_harm_data_c$pcbhdrug151)
table(self_harm_data_c$pcbhdrug152)
table(self_harm_data_c$cCANN1)
table(self_harm_data_c$cCANN2)
plot(self_harm_data_c$cCANN1)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
self_harm_data_c$cCANN1<-mxFactor(self_harm_data_c$cCANN1, levels=c(0:5) )
self_harm_data_c$cCANN2<-mxFactor(self_harm_data_c$cCANN2, levels=c(0:5) )
str(self_harm_data_c)
library(polycor) #check phenotypic correlation
hetcor(self_harm_data_c$cCANN1, self_harm_data_c$NSSH1)$correlations #0.23
hetcor(self_harm_data_c$cCANN1, self_harm_data_c$SSH1)$correlations #without covariates, 0.22
hetcor(self_harm_data_c$SSH1, self_harm_data_c$NSSH1)$correlations # 0.87, same as in other less complex models.
nv <- 3 # number of variables per twin
nvo <-3 #number of ordinal variables per twin
nvc <-nv-nvo #number of continuous variables per twin
poso <- nvc+1 #position where ordinal variables start
ntv <- nv*2 # number of variables per pair
nth <- 5 # number of max thresholds
nlower <- ntv*(ntv+1)/2 # number of free elements in a lower matrix ntv*ntv
ncor <-(nv*(nv+1)/2)-nv # number of free elements in a correlation matrix nv*nv
ninc <-
vars <-c('cCANN','NSSH', 'SSH')
selVars <-c('cCANN1', 'NSSH1', 'SSH1', 'cCANN2', 'NSSH2', 'SSH2')
useVars <-c('cCANN1', 'NSSH1', 'SSH1', 'cCANN2', 'NSSH2', 'SSH2', 'age_211', 'age_212','age_161','age_162', 'sex1','sex2')
# Select Data for Analysis
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(age_211&age_212) &!is.na(age_161&age_162) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(age_211&age_212) &!is.na(age_161&age_162) &!is.na(sex1&sex2), useVars)
describe(mzData)
describe(dzData)
nth-1 #number of max increments
ncovariates <- 2 #number of covariates
# 2) Specify ACE Model, with ONE overall set of Means, ONE overall Threshold on IQ liability
# To create Labels for Lower Triangular Matrices
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13','imz_14',
'Tmz_21','imz_21','imz_22','imz_23','imz_24',
'Tmz_31','imz_31','imz_32','imz_33','imz_34') # THs for var 1 and 2 for a twin individual (mz)
#LabCorMZ <-c('r21','rMZ1','MZxtxt','MZxtxt','rMZ2','r21')
LabThDZ <-c('Tmz_11','imz_11','imz_12','imz_13','imz_14',
'Tmz_21','imz_21','imz_22','imz_23','imz_24',
'Tmz_31','imz_31','imz_32','imz_33','imz_34') # THs for var 1 and 2 for a twin individual (mz)
#LabCorDZ <-c('r21','rDZ1','DZxtxt','DZxtxt','rDZ2','r21')
LabCovA21 <-c(rep('BageThNULL21',5),rep('BageThNSSH21',4),'BageThNULL21',rep('BageThSSH21',4),'BageThNULL21')
LabCovA16 <-c(rep('BageThDRUG16',5),rep('BageThNULL16',5),rep('BageThNULL16',5))
LabCovS <-c(rep('BsexThDRUG',5),rep('BsexThNSSH',4),'BsexThNULL',rep('BsexThSSH',4),'BsexThNULL')
StTH <-c(6.17,0.52,0.27,0.27,0.27,
-0.20,0.45,0.19,0.15,0,
0.88,0.55,0.25,0.16, 0)
ThPatSH <-c(rep(T,5),rep(T,4),F,rep(T,4),F)
aLabs <- paste("a", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
cLabs <- paste("c", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
eLabs <- paste("e", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
# Matrices to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(1.0,0.19,0.23,0.68,0.58,0.23), labels=aLabs, name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.74,0.18,0.19,0.002,0.002,0.005), labels=cLabs, name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(4.43,0.09,0.08,0.67,0.56,0.43), labels=eLabs, name="e" )
# # Define definition variables to hold the Covariates
obsAge211 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age_211"), name="Age211")
obsAge212 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age_212"), name="Age212")
obsAge161 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age_161"), name="Age161")
obsAge162 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age_162"), name="Age162")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#effect of age and sex on ordinal variable
value_sex<-c(rep(0.2,5),rep(0.2,4),0,rep(0.2,4),0)
free_sex <-c(rep(T,5),rep(T,4),F,rep(T,4),F)
value_age16<-c(rep(0.2,5),rep(0,5),rep(0,5))
free_age16 <-c(rep(T,5),rep(F,5),rep(F,5))
value_age21<-c(rep(0,5),rep(0.2,4),0,rep(0.2,4),0)
free_age21 <-c(rep(F,5),rep(T,4),F,rep(T,4),F)
betaA21 <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=free_age21, values=value_age21, labels=LabCovA21, name="BageTH21" )
betaA16 <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=free_age16, values=value_age16, labels=LabCovA16, name="BageTH16" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=free_sex, values=value_sex, labels=LabCovS, name="BsexTH" )
#mean and thresholds, no mean if all variables are ordinals
Mean <-mxMatrix( type="Zero", nrow=1, ncol=ntv, name="ExpMean" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=ThPatSH, values=StTH, lbound=-4, ubound=100,
labels=LabThMZ, name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH21%x%Age211+ BageTH16%x%Age161 + BsexTH%x%Sex1,
Low%*%Th + BageTH21%x%Age212+ BageTH16%x%Age162 + BsexTH%x%Sex2),
name="ExpThres")
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
# Algebra to compute standardized variance components
covP <- mxAlgebra( expression=A+C+E, name="V" )
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Constraint on total variance of Ordinal variable (A+C+E=1)
varL1 <- mxConstraint( expression=V[1,1]==1, name="L1" )
varL2 <- mxConstraint( expression=V[2,2]==1, name="L2" )
varL3 <- mxConstraint( expression=V[3,3]==1, name="L3" )
# Algebra to compute Rph-A, Rph-C & Rph-E between cCANN-NSSH
rphace_cCANN_NSSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE_cCANN_NSSH" )
rphace_cCANN_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[3,1]*sqrt(h2[3,3])),
(sqrt(c2[1,1])*Rc[3,1]*sqrt(c2[3,3])),
(sqrt(e2[1,1])*Re[3,1]*sqrt(e2[3,3])) ), name="RphACE_cCANN_SSH" )
rphace_NSSH_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[2,2])*Ra[3,2]*sqrt(h2[3,3])),
(sqrt(c2[2,2])*Rc[3,2]*sqrt(c2[3,3])),
(sqrt(e2[2,2])*Re[3,2]*sqrt(e2[3,3])) ), name="RphACE_NSSH_SSH" )
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[2,2], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[3,3], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[2,2], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[3,3], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[2,2], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[3,3], name="SSH_e")
#rA
raNSSHcCANN<-mxAlgebra(expression=Ra[2,1], name="rA_NSSH_cCANN")
raSSHcCANN<-mxAlgebra(expression=Ra[3,1], name="rA_SSH_cCANN")
#rC
rcNSSHcCANN<-mxAlgebra(expression=Rc[2,1], name="rC_NSSH_cCANN")
rcSSHcCANN<-mxAlgebra(expression=Rc[3,1], name="rC_SSH_cCANN")
#rE
reNSSHcCANN<-mxAlgebra(expression=Re[2,1], name="rE_NSSH_cCANN")
reSSHcCANN<-mxAlgebra(expression=Re[3,1], name="rE_SSH_cCANN")
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="ExpCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('cCANN1', 'NSSH1', 'SSH1', 'cCANN2', 'NSSH2', 'SSH2') )
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('cCANN1', 'NSSH1', 'SSH1', 'cCANN2', 'NSSH2', 'SSH2') )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, StA, StC, StE, matI, rph, rA, rC, rE,
rphace_cCANN_NSSH,rphace_cCANN_SSH,rphace_NSSH_SSH,
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2,
raNSSHcCANN,raSSHcCANN,rcNSSHcCANN,rcSSHcCANN,reNSSHcCANN,reSSHcCANN)
modelMZ <- mxModel( pars, obsAge211, obsAge212,obsAge161,obsAge162, obsSex1, obsSex2 , Mean, Tr, inc, Thres,
betaA21,betaA16, betaS, covMZ, dataMZ, objMZ, fitFunction, varL1, varL2, varL3, name="MZ" )
modelDZ <- mxModel( pars, obsAge211, obsAge212,obsAge161,obsAge162, obsSex1, obsSex2 , Mean, Tr, inc, Thres,
betaA21,betaA16, betaS, covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
#confidence intervals
Conf1 <- mxCI (c('Rph[2,1]','Rph[3,1]'))
Conf2 <- mxCI ('Ra[2,1]')
Conf3 <- mxCI ('Ra[3,1]')
Conf4 <- mxCI ('Rc[2,1]')
Conf5 <- mxCI ('Rc[3,1]')
Conf6 <- mxCI ('Re[2,1]')
Conf7 <- mxCI ('Re[3,1]')
AceModel1 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf1)
AceModel2 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf2)
AceModel3 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf3)
AceModel4 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf4)
AceModel5 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf5)
AceModel6 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf6)
AceModel7 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf7)
# 3) RUN AceModel
AceFit1 <- mxTryHardOrdinal(AceModel1, intervals=T) #fit = 25519.628
AceFit2 <- mxTryHardOrdinal(AceModel2, intervals=T)
AceFit3 <- mxTryHardOrdinal(AceModel3, intervals=T)
AceFit4 <- mxTryHardOrdinal(AceModel4, intervals=T)
AceFit5 <- mxTryHardOrdinal(AceModel5, intervals=T)
AceFit6 <- mxTryHardOrdinal(AceModel6, intervals=T)
AceFit7 <- mxTryHardOrdinal(AceModel7, intervals=T)
(AceSum1 <- summary(AceFit1,verbose=T))
(AceSum2 <- summary(AceFit2,verbose=T))
(AceSum3 <- summary(AceFit3,verbose=T))
(AceSum4 <- summary(AceFit4,verbose=T))
(AceSum5 <- summary(AceFit5,verbose=T))
(AceSum6 <- summary(AceFit6,verbose=T))
(AceSum7 <- summary(AceFit7,verbose=T))
#get the estimates and CIs
CI1 <- AceSum1$CI
CI2 <- AceSum2$CI
CI3 <- AceSum3$CI
CI4 <- AceSum4$CI
CI5 <- AceSum5$CI
CI6 <- AceSum6$CI
CI7 <- AceSum7$CI
tot_CI<-rbind(CI1,CI2,CI3,CI4,CI5,CI6,CI7)
#evaluate the contents
mxEval(MZ.ExpCovMZ, AceFit1)
mxEval(DZ.ExpCovDZ, AceFit1)
mxEval(ACE.h2, AceFit1)
mxEval(ACE.c2, AceFit1)
mxEval(ACE.e2, AceFit1)
mxEval(ACE.Ra, AceFit1)
mxEval(ACE.Rc, AceFit1)
mxEval(ACE.Re, AceFit1)
mxEval(ACE.Rph, AceFit1)
mxEval(ACE.RphACE_cCANN_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1]*100
mxEval(ACE.RphACE_cCANN_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1]*100
mxEval(ACE.V,AceFit1)
#get the proportion explained by A,C and E in the phenotypic correlation
proportion<-as.data.frame(rbind((mxEval(ACE.RphACE_cCANN_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1])*100,
(mxEval(ACE.RphACE_cCANN_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1])*100,
mxEval(ACE.RphACE_cCANN_NSSH, AceFit1),
mxEval(ACE.RphACE_cCANN_SSH, AceFit1)),
row.names=c("NSSH%","SSH%", "NSSH","SSH"))
colnames(proportion)<-c("A","C","E")
proportion
#constrain the model
Sub1Model <- mxModel(AceModel1, name="sub1",
mxConstraint(MZ.rA_NSSH_cCANN==MZ.rA_SSH_cCANN, name="rA_con"),
mxConstraint(MZ.rC_NSSH_cCANN==MZ.rC_SSH_cCANN, name="rC_con"),
mxConstraint(MZ.rE_NSSH_cCANN==MZ.rE_SSH_cCANN, name="rE_con"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = F)
(Sub1Sum <- summary(Sub1Fit))
mxEval(MZ.NSSH_a,Sub1Fit);mxEval(MZ.SSH_a,Sub1Fit)
mxEval(MZ.NSSH_c,Sub1Fit);mxEval(MZ.SSH_c,Sub1Fit)
mxEval(MZ.NSSH_e,Sub1Fit);mxEval(MZ.SSH_e,Sub1Fit)
mxEval(MZ.path_a,Sub1Fit);mxEval(MZ.path_c,Sub1Fit);mxEval(MZ.path_e,Sub1Fit)
mxEval(MZ.Ra,Sub1Fit);mxEval(MZ.Rc,Sub1Fit);mxEval(MZ.Re,Sub1Fit)
mxEval(MZ.h2,Sub1Fit)
### compare with ACE model
comparison <- mxCompare(AceFit1,Sub1Fit)
library(xlsx)
## 6) save the results
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_cCANN_SLSQP_ACE_04_June_2020.RData")
# save the estimates and their confidence intervals
write.xlsx(tot_CI, file="trivariate_estimates_with_CI_04_June_2020.xlsx",
sheetName="cCANN", append=TRUE)
# save the proportions
write.xlsx(proportion, file="trivariate_proportion_04_June_2020.xlsx",
sheetName="cCANN", append=TRUE)
# save the results of the chi-square test
write.xlsx(comparison, file="trivariate_constrained_results_04_June_2020.xlsx",
sheetName="cCANN", append=TRUE)
rm(list=ls())
Sys.setenv(OMP_NUM_THREADS=parallel::detectCores()) #this has to be before loading the library OpenMx
require(OpenMx);require(psych);require(foreign);require(tidyverse);require(polycor)
mxOption(NULL, "Default optimizer", "SLSQP") # SLSQP is a better optimizer for ordinal data
self_harm_data=read.spss("427 Kai Lim self harm 250919.sav",verbose=T,to.data.frame = T)
hetcor(self_harm_data$pcbhdrug121, self_harm_data$u1cslfh021)$correlations #0.12
hetcor(self_harm_data$pcbhdrug131, self_harm_data$u1cslfh021)$correlations #0.19
hetcor(self_harm_data$pcbhdrug151, self_harm_data$u1cslfh021)$correlations #0.18
table(self_harm_data$pcbhdrug131);table(self_harm_data$pcbhdrug151)
str(self_harm_data);class(self_harm_data)
plot(self_harm_data$pcbhdrug151) #how many times using cannabis - more normally distributed and makes more sense
#using this variable, but need to recode from "no" in previous question
plot(self_harm_data$pcbhdrug131) #how often using cannabis
self_harm_data_c<-self_harm_data %>%
filter(exclude1==0 & exclude2 ==0)%>% #exclude those with medical conditions etc
select(randomfamid,randomtwinid,u1cslfh021,u1cslfh022,u1cslfh031,u1cslfh032,u1cslfh041,u1cslfh042,pcbhdrug011, pcbhdrug012, pcbhdrug051,pcbhdrug052,x3zygos,u1cage1,u1cage2,pcbhage1,pcbhage2, sex1,sex2, random)%>%
mutate_if(is.factor, as.numeric) #import as numeric values for all columns
#fill in co-twin's age as proxy
self_harm_data_c <- mutate(self_harm_data_c, age_211 = ifelse(is.na(u1cage1),u1cage2 , u1cage1))
self_harm_data_c <- mutate(self_harm_data_c, age_212 = ifelse(is.na(u1cage2),u1cage1 , u1cage2))
hist(self_harm_data_c$u1cage1)
hist(self_harm_data_c$age_211)
self_harm_data_c <- mutate(self_harm_data_c, age_161 = ifelse(is.na(pcbhage1),pcbhage2 , pcbhage1))
self_harm_data_c <- mutate(self_harm_data_c, age_162 = ifelse(is.na(pcbhage2),pcbhage1 , pcbhage2))
hist(self_harm_data_c$pcbhage1)
hist(self_harm_data_c$age_161)
#recode so that no="0"
self_harm_data_c$u1cslfh021=self_harm_data_c$u1cslfh021-1
self_harm_data_c$u1cslfh022=self_harm_data_c$u1cslfh022-1
self_harm_data_c$u1cslfh031=self_harm_data_c$u1cslfh031-1
self_harm_data_c$u1cslfh032=self_harm_data_c$u1cslfh032-1
self_harm_data_c$u1cslfh041=self_harm_data_c$u1cslfh041-1
self_harm_data_c$u1cslfh042=self_harm_data_c$u1cslfh042-1
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$pcbhdrug011)
table(self_harm_data_c$pcbhdrug051)
#bring zeros from SH question into NSSH and SSH.
self_harm_data_c <- mutate(self_harm_data_c, NSSH1 = ifelse(is.na(u1cslfh031)&u1cslfh021==0,u1cslfh021,u1cslfh031))
self_harm_data_c <- mutate(self_harm_data_c, NSSH2 = ifelse(is.na(u1cslfh032)&u1cslfh022==0,u1cslfh022,u1cslfh032))
self_harm_data_c <- mutate(self_harm_data_c, SSH1 = ifelse(is.na(u1cslfh041)&u1cslfh021==0,u1cslfh021,u1cslfh041))
self_harm_data_c <- mutate(self_harm_data_c, SSH2 = ifelse(is.na(u1cslfh042)&u1cslfh022==0,u1cslfh022,u1cslfh042))
#bring zeros from never used cannabis into number of times using cannabis
#recode so that no="0"
self_harm_data_c$pcbhdrug051<-self_harm_data_c$pcbhdrug051-1
self_harm_data_c$pcbhdrug052<-self_harm_data_c$pcbhdrug052-1
table(self_harm_data_c$pcbhdrug052);table(self_harm_data_c$pcbhdrug051)
self_harm_data_c <- mutate(self_harm_data_c, cALC1 = ifelse(is.na(pcbhdrug051)&pcbhdrug011==0,pcbhdrug011,pcbhdrug051))
self_harm_data_c <- mutate(self_harm_data_c, cALC2 = ifelse(is.na(pcbhdrug052)&pcbhdrug012==0,pcbhdrug012,pcbhdrug052))
table(self_harm_data_c$u1cslfh021)
table(self_harm_data_c$u1cslfh022)
table(self_harm_data_c$u1cslfh031)
table(self_harm_data_c$u1cslfh032)
table(self_harm_data_c$NSSH1)
table(self_harm_data_c$NSSH2)
table(self_harm_data_c$u1cslfh041)
table(self_harm_data_c$u1cslfh042)
table(self_harm_data_c$SSH1)
table(self_harm_data_c$SSH2)
table(self_harm_data_c$pcbhdrug011)
table(self_harm_data_c$pcbhdrug012)
table(self_harm_data_c$pcbhdrug051)
table(self_harm_data_c$pcbhdrug052)
table(self_harm_data_c$cALC1)
table(self_harm_data_c$cALC2)
head(self_harm_data_c)
dim(self_harm_data);dim(self_harm_data_c)
#Make the integer variables ordered factors
self_harm_data_c$NSSH1<-mxFactor(self_harm_data_c$NSSH1, levels=c(0:4) )
self_harm_data_c$NSSH2<-mxFactor(self_harm_data_c$NSSH2, levels=c(0:4) )
self_harm_data_c$SSH1<-mxFactor(self_harm_data_c$SSH1, levels=c(0:4) )
self_harm_data_c$SSH2<-mxFactor(self_harm_data_c$SSH2, levels=c(0:4) )
self_harm_data_c$cALC1<-mxFactor(self_harm_data_c$cALC1, levels=c(0:4) )
self_harm_data_c$cALC2<-mxFactor(self_harm_data_c$cALC2, levels=c(0:4) )
str(self_harm_data_c)
plot(self_harm_data_c$cALC1)
plot(self_harm_data_c$NSSH1)
library(polycor) #check phenotypic correlation
hetcor(self_harm_data_c$pcbhdrug011, self_harm_data_c$NSSH1)$correlations #0.05
hetcor(self_harm_data_c$pcbhdrug011, self_harm_data_c$SSH1)$correlations #0.02
hetcor(self_harm_data_c$cALC1, self_harm_data_c$NSSH1)$correlations #0.12
hetcor(self_harm_data_c$cALC1, self_harm_data_c$SSH1)$correlations #without covariates, 0.14
hetcor(self_harm_data_c$SSH1, self_harm_data_c$NSSH1)$correlations # 0.87, same as in other less complex models.
vars <-c('cALC','NSSH', 'SSH')
selVars <-c('cALC1', 'NSSH1', 'SSH1', 'cALC2', 'NSSH2', 'SSH2')
useVars <-c('cALC1', 'NSSH1', 'SSH1', 'cALC2', 'NSSH2', 'SSH2', 'age_161', 'age_162','age_211', 'age_212', 'sex1','sex2')
# Select Data for Analysis
mzData <- subset(self_harm_data_c, x3zygos==1 & random==1 & !is.na(age_211&age_212) &!is.na(age_161&age_162) &!is.na(sex1&sex2), useVars) #select only one twin from each pair because of double entry method
dzData <- subset(self_harm_data_c, x3zygos!=1 & random==1 & !is.na(age_211&age_212) &!is.na(age_161&age_162) &!is.na(sex1&sex2), useVars)
describe(mzData)
describe(dzData)
nv <- 3 # number of variables per twin
nvo <-3 #number of ordinal variables per twin
nvc <-nv-nvo #number of continuous variables per twin
poso <- nvc+1 #position where ordinal variables start
ntv <- nv*2 # number of variables per pair
nth <- 4 # number of max thresholds
nlower <- ntv*(ntv+1)/2 # number of free elements in a lower matrix ntv*ntv
ncor <-(nv*(nv+1)/2)-nv # number of free elements in a correlation matrix nv*nv
ninc <- nth-1 #number of max increments
ncovariates <- 2 #number of covariates
# 1) Fits a constrained Polychoric correlation model to answer reviewer's comments
# TH same across twins and across zyg groups
# Age effect is different acros variables, but same across thresholds within variables (if c>2)
# There is one overall rPH between var1-2 and the x-trait x-twin correlations are symmetric
#
# CREATE LABELS & START VALUES as objects(to ease specification)
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13',
'Tmz_21','imz_21','imz_22','imz_23',
'Tmz_31','imz_31','imz_32','imz_33') # THs for var 1 and 2 for a twin individual (mz)
#LabCorMZ <-c('r21','rMZ1','MZxtxt','MZxtxt','rMZ2','r21')
LabThDZ <-c('Tmz_11','imz_11','imz_12','imz_13','imz_14',
'Tmz_21','imz_21','imz_22','imz_23','imz_24',
'Tmz_31','imz_31','imz_32','imz_33','imz_34') # THs for var 1 and 2 for a twin individual (mz)
#LabCorDZ <-c('r21','rDZ1','DZxtxt','DZxtxt','rDZ2','r21')
LabCovA21 <-c(rep('BageThNULL21',4),rep('BageThNSSH21',4),rep('BageThSSH21',4))
LabCovA16 <-c(rep('BageThDRUG16',4),rep('BageThNULL16',4),rep('BageThNULL16',4))
LabCovS <-c(rep('BsexThDRUG',4),rep('BsexThNSSH',4),rep('BsexThSSH',4))
# Create Lables for a Correlation Matrix
rphLabs <- paste("r",1:ncor,sep="")
# Create Labels for Lower Triangular Matrices
MZbLabs <- paste("mz", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
DZbLabs <- paste("dz", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
(PatSD <- c( rep(T,nvc), rep(F, nvo)))
ThPatSH <-c(rep(T,4),rep(T,4),rep(T,4))
#StCorMZ <-c(.2, .4, .25, .25, .20, .2)
#StCorDZ <-c(.2, .1, .10, .10, .02, .2)
StTH <-c(6.17,0.52,0.27,0.27,
-0.20,0.45,0.19,0.15,
0.88,0.55,0.25,0.16)
#
# # Define definition variables to hold the Covariates
#
obsAge211 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age_211"), name="Age211")
obsAge212 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age_212"), name="Age212")
obsAge161 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age_161"), name="Age161")
obsAge162 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age_162"), name="Age162")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
# Matrix & Algebra for expected means (SND), Thresholds, effect of Age on Th and correlations
Mean <-mxMatrix( type="Zero", nrow=1, ncol=ntv, name="M" )
#effect of age and sex on ordinal variable
value_sex<-c(rep(0.2,4),rep(0.2,4),rep(0.2,4))
free_sex <-c(rep(T,4),rep(T,4),rep(T,4))
value_age16<-c(rep(0.2,4),rep(0,4),rep(0,4))
free_age16 <-c(rep(T,4),rep(F,4),rep(F,4))
value_age21<-c(rep(0,4),rep(0.2,4),rep(0.2,4))
free_age21 <-c(rep(F,4),rep(T,4),rep(T,4))
betaA21 <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=free_age21, values=value_age21, labels=LabCovA21, name="BageTH21" )
betaA16 <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=free_age16, values=value_age16, labels=LabCovA16, name="BageTH16" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=free_sex, values=value_sex, labels=LabCovS, name="BsexTH" )
#thresholds
Tmz <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=ThPatSH, values=StTH, lbound=-4, ubound=10,
labels=LabThMZ, name="ThMZ")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
ThresMZ <-mxAlgebra( expression= cbind(Low%*%ThMZ + BageTH21%x%Age211+ BageTH16%x%Age161 + BsexTH%x%Sex1,
Low%*%ThMZ + BageTH21%x%Age212+ BageTH16%x%Age162 + BsexTH%x%Sex2),
name="expThresMZ")
Tdz <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=ThPatSH, values=StTH, lbound=-4, ubound=10,
labels=LabThMZ, name="ThDZ")
ThresDZ <-mxAlgebra( expression= cbind(Low%*%ThDZ + BageTH21%x%Age211+ BageTH16%x%Age161 + BsexTH%x%Sex1,
Low%*%ThDZ + BageTH21%x%Age212+ BageTH16%x%Age162 + BsexTH%x%Sex2),
name="expThresDZ")
# # elements for the correlations
#SD
SD <-mxMatrix( type="Diag", nrow=ntv, ncol=ntv, free=c(PatSD,PatSD),
values=c(1,1,1,1,1,1), name="sd")
Rph <-mxMatrix("Stand", nv, nv, free = TRUE, values = StWithinperson, labels=rphLabs, name="within")
MZb <-mxMatrix("Symm", nv, nv, free = TRUE, values = StBetweenMZ, labels=MZbLabs, name="BetweenMZ")
DZb <-mxMatrix("Symm", nv, nv, free = TRUE, values = StBetweenDZ, labels=DZbLabs, name="BetweenDZ")
CorMZ <-mxAlgebra(rbind(cbind(within,BetweenMZ), cbind(BetweenMZ, within)), name="expCorMZ")
CorDZ <-mxAlgebra(rbind(cbind(within,BetweenDZ), cbind(BetweenDZ, within)), name="expCorDZ")
# Matrices for the Covariance model
CovMZ <-mxAlgebra( expression=sd %*% expCorMZ %*% t(sd), name="ExpCovMZ" )
CovDZ <-mxAlgebra( expression=sd %*% expCorDZ %*% t(sd), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="M", dimnames=selVars, thresholds="expThresMZ")
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="M", dimnames=selVars, thresholds="expThresDZ")
fitFunction <- mxFitFunctionML()
# Combine Groups
modelMZ <- mxModel( obsAge211, obsAge212, obsAge161,obsAge162,
obsSex1, obsSex2, Mean, betaA21,betaA16, betaS,
Tmz, inc, ThresMZ, SD, Rph, MZb, CovMZ, CorMZ, dataMZ, objMZ, fitFunction, name="MZ" )
modelDZ <- mxModel( obsAge211, obsAge212, obsAge161,obsAge162,
obsSex1, obsSex2, Mean, betaA21,betaA16, betaS,
Tdz, inc, ThresDZ, SD, Rph, DZb, CovDZ, CorDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
Conf1 <- mxCI (c ('MZ.expCorMZ','DZ.expCorDZ') )
Conf2 <- mxCI(c('MZ.BageTH21','MZ.BsexTH'))
SatModel <- mxModel( "Sat", modelMZ, modelDZ, minus2ll, obj, Conf1, Conf2 )
# 1) RUN concor Model
SatFit <- mxTryHardOrdinal(SatModel, intervals=T)
(SatSumm <- summary(SatFit,verbose=T))
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_cALC_SLSQP_Cor_26_Nov_2020.RData")
# 2) Specify ACE Model, with ONE overall set of Means, ONE overall Threshold on IQ liability
# To create Labels for Lower Triangular Matrices
LabThMZ <-c('Tmz_11','imz_11','imz_12','imz_13',
'Tmz_21','imz_21','imz_22','imz_23',
'Tmz_31','imz_31','imz_32','imz_33') # THs for var 1 and 2 for a twin individual (mz)
#LabCorMZ <-c('r21','rMZ1','MZxtxt','MZxtxt','rMZ2','r21')
LabThDZ <-c('Tmz_11','imz_11','imz_12','imz_13',
'Tmz_21','imz_21','imz_22','imz_23',
'Tmz_31','imz_31','imz_32','imz_33') # THs for var 1 and 2 for a twin individual (mz)
#LabCorDZ <-c('r21','rDZ1','DZxtxt','DZxtxt','rDZ2','r21')
LabCovA21 <-c(rep('BageThNULL21',4),rep('BageThNSSH21',4),rep('BageThSSH21',4))
LabCovA16 <-c(rep('BageThDRUG16',4),rep('BageThNULL16',4),rep('BageThNULL16',4))
LabCovS <-c(rep('BsexThDRUG',4),rep('BsexThNSSH',4),rep('BsexThSSH',4))
StTH <-c(6.17,0.52,0.27,0.27,
-0.20,0.45,0.19,0.15,
0.88,0.55,0.25,0.16)
ThPatSH <-c(rep(T,4),rep(T,4),rep(T,4))
aLabs <- paste("a", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
cLabs <- paste("c", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
eLabs <- paste("e", do.call(c, sapply(seq(1, nv), function(x){ paste(x:nv, x,sep="") })), sep="")
# Matrices to store a, c, and e Path Coefficients
pathA <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(1.0,0.19,0.23,0.68,0.58,0.23), labels=aLabs, name="a" )
pathC <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(0.74,0.18,0.19,0.002,0.002,0.005), labels=cLabs, name="c" )
pathE <- mxMatrix( type="Lower", nrow=nv, ncol=nv, free=TRUE, values=c(4.43,0.09,0.08,0.67,0.56,0.43), labels=eLabs, name="e" )
# # Define definition variables to hold the Covariates
obsAge211 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age_211"), name="Age211")
obsAge212 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age_212"), name="Age212")
obsAge161 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age_161"), name="Age161")
obsAge162 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.age_162"), name="Age162")
obsSex1 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex1"), name="Sex1")
obsSex2 <- mxMatrix( type="Full", nrow=1, ncol=1, free=F, labels=c("data.sex2"), name="Sex2")
#effect of age and sex on ordinal variable
value_sex<-c(rep(0.2,4),rep(0.2,4),rep(0.2,4))
free_sex <-c(rep(T,4),rep(T,4),rep(T,4))
value_age16<-c(rep(0.2,4),rep(0,4),rep(0,4))
free_age16 <-c(rep(T,4),rep(F,4),rep(F,4))
value_age21<-c(rep(0,4),rep(0.2,4),rep(0.2,4))
free_age21 <-c(rep(F,4),rep(T,4),rep(T,4))
betaA21 <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=free_age21, values=value_age21, labels=LabCovA21, name="BageTH21" )
betaA16 <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=free_age16, values=value_age16, labels=LabCovA16, name="BageTH16" )
betaS <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=free_sex, values=value_sex, labels=LabCovS, name="BsexTH" )
#mean and thresholds, no mean if all variables are ordinals
Mean <-mxMatrix( type="Zero", nrow=1, ncol=ntv, name="ExpMean" )
Tr <-mxMatrix( type="Full", nrow=nth, ncol=nvo, free=ThPatSH, values=StTH, lbound=-4, ubound=100,
labels=LabThMZ, name="Th")
inc <-mxMatrix( type="Lower",nrow=nth, ncol=nth, free=F, values=1, name="Low")
Thres <-mxAlgebra( expression= cbind(Low%*%Th + BageTH21%x%Age211+ BageTH16%x%Age161 + BsexTH%x%Sex1,
Low%*%Th + BageTH21%x%Age212+ BageTH16%x%Age162 + BsexTH%x%Sex2),
name="ExpThres")
# Matrices generated to hold A, C, and E computed Variance Components
covA <- mxAlgebra( expression=a %*% t(a), name="A" )
covC <- mxAlgebra( expression=c %*% t(c), name="C" )
covE <- mxAlgebra( expression=e %*% t(e), name="E" )
# Algebra to compute standardized variance components
covP <- mxAlgebra( expression=A+C+E, name="V" )
StA <- mxAlgebra( expression=A/V, name="h2")
StC <- mxAlgebra( expression=C/V, name="c2")
StE <- mxAlgebra( expression=E/V, name="e2")
# Algebra to compute Phenotypic, A, C & E correlations
matI <- mxMatrix( type="Iden", nrow=nv, ncol=nv, name="I")
rph <- mxAlgebra( expression= solve(sqrt(I*V)) %*% V %*% solve(sqrt(I*V)), name="Rph")
rA <- mxAlgebra( expression= solve(sqrt(I*A)) %*% A %*% solve(sqrt(I*A)), name="Ra" )
rC <- mxAlgebra( expression= solve(sqrt(I*C)) %*% C %*% solve(sqrt(I*C)), name="Rc" )
rE <- mxAlgebra( expression= solve(sqrt(I*E)) %*% E %*% solve(sqrt(I*E)), name="Re" )
# Constraint on total variance of Ordinal variable (A+C+E=1)
varL1 <- mxConstraint( expression=V[1,1]==1, name="L1" )
varL2 <- mxConstraint( expression=V[2,2]==1, name="L2" )
varL3 <- mxConstraint( expression=V[3,3]==1, name="L3" )
# Algebra to compute Rph-A, Rph-C & Rph-E between cALC-NSSH
rphace_cALC_NSSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[2,1]*sqrt(h2[2,2])),
(sqrt(c2[1,1])*Rc[2,1]*sqrt(c2[2,2])),
(sqrt(e2[1,1])*Re[2,1]*sqrt(e2[2,2])) ), name="RphACE_cALC_NSSH" )
rphace_cALC_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[1,1])*Ra[3,1]*sqrt(h2[3,3])),
(sqrt(c2[1,1])*Rc[3,1]*sqrt(c2[3,3])),
(sqrt(e2[1,1])*Re[3,1]*sqrt(e2[3,3])) ), name="RphACE_cALC_SSH" )
rphace_NSSH_SSH <- mxAlgebra( expression= cbind ( (sqrt(h2[2,2])*Ra[3,2]*sqrt(h2[3,3])),
(sqrt(c2[2,2])*Rc[3,2]*sqrt(c2[3,3])),
(sqrt(e2[2,2])*Re[3,2]*sqrt(e2[3,3])) ), name="RphACE_NSSH_SSH" )
# Algebra's needed for picking out elements from Cov models (used later for equality constraints)
sqrt_path_a<-mxAlgebra(expression=sqrt(h2), name="path_a")
NSSH_h2 <-mxAlgebra( expression= path_a[2,2], name="NSSH_a")
SSH_h2 <-mxAlgebra( expression= path_a[3,3], name="SSH_a")
sqrt_path_c<-mxAlgebra(expression=sqrt(c2), name="path_c")
NSSH_c2 <-mxAlgebra( expression= path_c[2,2], name="NSSH_c")
SSH_c2 <-mxAlgebra( expression= path_c[3,3], name="SSH_c")
sqrt_path_e<-mxAlgebra(expression=sqrt(e2), name="path_e")
NSSH_e2 <-mxAlgebra( expression= path_e[2,2], name="NSSH_e")
SSH_e2 <-mxAlgebra( expression= path_e[3,3], name="SSH_e")
#rA
raNSSHcALC<-mxAlgebra(expression=Ra[2,1], name="rA_NSSH_cALC")
raSSHcALC<-mxAlgebra(expression=Ra[3,1], name="rA_SSH_cALC")
#rC
rcNSSHcALC<-mxAlgebra(expression=Rc[2,1], name="rC_NSSH_cALC")
rcSSHcALC<-mxAlgebra(expression=Rc[3,1], name="rC_SSH_cALC")
#rE
reNSSHcALC<-mxAlgebra(expression=Re[2,1], name="rE_NSSH_cALC")
reSSHcALC<-mxAlgebra(expression=Re[3,1], name="rE_SSH_cALC")
# Algebra for expected Variance/Covariance Matrices in MZ & DZ twins
covMZ <- mxAlgebra( expression= rbind( cbind(A+C+E , A+C),
cbind(A+C , A+C+E)), name="ExpCovMZ" )
covDZ <- mxAlgebra( expression= rbind( cbind(A+C+E , 0.5%x%A+C),
cbind(0.5%x%A+C , A+C+E)), name="ExpCovDZ" )
# Data objects for Multiple Groups
dataMZ <- mxData( observed=mzData, type="raw" )
dataDZ <- mxData( observed=dzData, type="raw" )
# Objective objects for Multiple Groups
objMZ <- mxExpectationNormal( covariance="ExpCovMZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('cALC1', 'NSSH1', 'SSH1', 'cALC2', 'NSSH2', 'SSH2') )
objDZ <- mxExpectationNormal( covariance="ExpCovDZ", means="ExpMean", dimnames=selVars, thresholds="ExpThres", threshnames=c('cALC1', 'NSSH1', 'SSH1', 'cALC2', 'NSSH2', 'SSH2') )
fitFunction <- mxFitFunctionML()
# Combine Groups
pars <- list( pathA, pathC, pathE, covA, covC, covE, covP, StA, StC, StE, matI, rph, rA, rC, rE,
rphace_cALC_NSSH,rphace_cALC_SSH,rphace_NSSH_SSH,
sqrt_path_a, NSSH_h2, SSH_h2,
sqrt_path_c, NSSH_c2, SSH_c2,
sqrt_path_e, NSSH_e2, SSH_e2,
raNSSHcALC,raSSHcALC,rcNSSHcALC,rcSSHcALC,reNSSHcALC,reSSHcALC)
modelMZ <- mxModel( pars, obsAge211, obsAge212,obsAge161,obsAge162, obsSex1, obsSex2 , Mean, Tr, inc, Thres,
betaA21,betaA16, betaS, covMZ, dataMZ, objMZ, fitFunction, varL1, varL2, varL3, name="MZ" )
modelDZ <- mxModel( pars, obsAge211, obsAge212,obsAge161,obsAge162, obsSex1, obsSex2 , Mean, Tr, inc, Thres,
betaA21,betaA16, betaS, covDZ, dataDZ, objDZ, fitFunction, name="DZ" )
minus2ll <- mxAlgebra( expression=MZ.objective + DZ.objective, name="m2LL" )
obj <- mxFitFunctionAlgebra( "m2LL" )
#confidence intervals
Conf1 <- mxCI (c('Rph[2,1]','Rph[3,1]'))
Conf2 <- mxCI ('Ra[2,1]') #
Conf3 <- mxCI ('Ra[3,1]')
Conf4 <- mxCI ('Rc[2,1]')
Conf5 <- mxCI ('Rc[3,1]')
Conf6 <- mxCI ('Re[2,1]')
Conf7 <- mxCI ('Re[3,1]')
AceModel1 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf1)
AceModel2 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf2)
AceModel3 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf3)
AceModel4 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf4)
AceModel5 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf5)
AceModel6 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf6)
AceModel7 <- mxModel( "ACE", pars, modelMZ, modelDZ, minus2ll, obj, Conf7)
# 3) RUN AceModel
AceFit1 <- mxTryHardOrdinal(AceModel1, intervals=T)
AceFit2 <- mxTryHardOrdinal(AceModel2, intervals=T)
AceFit3 <- mxTryHardOrdinal(AceModel3, intervals=T)
AceFit4 <- mxTryHardOrdinal(AceModel4, intervals=T)
AceFit5 <- mxTryHardOrdinal(AceModel5, intervals=T)
AceFit6 <- mxTryHardOrdinal(AceModel6, intervals=T)
AceFit7 <- mxTryHardOrdinal(AceModel7, intervals=T)
(AceSum1 <- summary(AceFit1,verbose=T))
(AceSum2 <- summary(AceFit2,verbose=T))
(AceSum3 <- summary(AceFit3,verbose=T))
(AceSum4 <- summary(AceFit4,verbose=T))
(AceSum5 <- summary(AceFit5,verbose=T))
(AceSum6 <- summary(AceFit6,verbose=T))
(AceSum7 <- summary(AceFit7,verbose=T))
#get the estimates and CIs
CI1 <- AceSum1$CI
CI2 <- AceSum2$CI
CI3 <- AceSum3$CI
CI4 <- AceSum4$CI
CI5 <- AceSum5$CI
CI6 <- AceSum6$CI
CI7 <- AceSum7$CI
tot_CI<-rbind(CI1,CI2,CI3,CI4,CI5,CI6,CI7)
#evaluate the contents
mxEval(MZ.ExpCovMZ, AceFit1)
mxEval(DZ.ExpCovDZ, AceFit3)
mxEval(ACE.RphACE_cALC_SSH, AceFit7)
mxEval(ACE.h2, AceFit1)
mxEval(ACE.c2, AceFit1)
mxEval(ACE.e2, AceFit1)
mxEval(ACE.Ra, AceFit5)
mxEval(ACE.Rc, AceFit1)
mxEval(ACE.Re, AceFit1)
mxEval(ACE.Rph, AceFit1)
mxEval(ACE.RphACE_cALC_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1]*100
mxEval(ACE.RphACE_cALC_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1]*100
mxEval(ACE.V,AceFit1)
mxEval(ACE.RphACE_cALC_SSH, AceFit6)
#get the proportion explained by A,C and E in the phenotypic correlation
proportion<-as.data.frame(rbind((mxEval(ACE.RphACE_cALC_NSSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[2,1])*100,
(mxEval(ACE.RphACE_cALC_SSH, AceFit1)/mxEval(ACE.Rph, AceFit1)[3,1])*100,
mxEval(ACE.RphACE_cALC_NSSH, AceFit1),
mxEval(ACE.RphACE_cALC_SSH, AceFit1)),
row.names=c("NSSH%","SSH%", "NSSH","SSH"))
colnames(proportion)<-c("A","C","E")
proportion
#constrain the model
Sub1Model <- mxModel(AceModel1, name="sub1",
mxConstraint(MZ.rA_NSSH_cALC==MZ.rA_SSH_cALC, name="rA_con"),
mxConstraint(MZ.rC_NSSH_cALC==MZ.rC_SSH_cALC, name="rC_con"),
mxConstraint(MZ.rE_NSSH_cALC==MZ.rE_SSH_cALC, name="rE_con"))
Sub1Fit <- mxTryHardOrdinal(Sub1Model, intervals = F)
(Sub1Sum <- summary(Sub1Fit))
mxEval(MZ.NSSH_a,Sub1Fit);mxEval(MZ.SSH_a,Sub1Fit)
mxEval(MZ.NSSH_c,Sub1Fit);mxEval(MZ.SSH_c,Sub1Fit)
mxEval(MZ.NSSH_e,Sub1Fit);mxEval(MZ.SSH_e,Sub1Fit)
mxEval(MZ.path_a,Sub1Fit);mxEval(MZ.path_c,Sub1Fit);mxEval(MZ.path_e,Sub1Fit)
mxEval(MZ.Ra,Sub1Fit);mxEval(MZ.Rc,Sub1Fit);mxEval(MZ.Re,Sub1Fit)
mxEval(MZ.h2,Sub1Fit)
### compare with ACE model
comparison <- mxCompare(AceFit1,Sub1Fit)
library(xlsx)
## 6) save the results
setwd("../results")
save.image(file="Tri_LT_NSSH_SSH_cALC_SLSQP_ACE_04_June_2020.RData")
# save the estimates and their confidence intervals
write.xlsx(tot_CI, file="trivariate_estimates_with_CI_04_June_2020.xlsx",
sheetName="cALC", append=TRUE)
# save the proportions
write.xlsx(proportion, file="trivariate_proportion_04_June_2020.xlsx",
sheetName="cALC", append=TRUE)
# save the results of the chi-square test
write.xlsx(comparison, file="trivariate_constrained_results_04_June_2020.xlsx",
sheetName="cALC", append=TRUE)
Code to compile phenotypic correlations between each measure with NSSH and SSH in the trivariate ACE models, and the contributions of A, C and E to the correlations
#make table for supp materials
#phenotypic correlations
#load packages
library(tidyverse)
library(fs)
library(readxl)
library(ggforce)
library(patchwork)
library(viridis)
library(colortools)
library(plyr)
library(drlib)
specify_decimal <- function(x, k) trimws(format(round(x, k), nsmall=k))
path<-"/Users/kai/OneDrive - King's College London/PhD/TEDS_project/results/14_reanalyses_trivariate/trivariate_proportion_16_June_2020.xlsx"
prop <- path %>%
excel_sheets() %>%
set_names() %>%
map_df(read_excel,
path = path,
.id = "trait") #id = column name for the sheet name as column values
prop2<-as.data.frame(prop)
prop2$phenocor=prop2$A+prop2$C+prop2$E
colnames(prop2)<-c( "trait","selfharm","A","C","E","phenotypic_cor")
pheno<- filter(prop2, selfharm=="NSSH"|selfharm=="SSH")
percent<- filter(prop2, selfharm=="NSSH%"|selfharm=="SSH%")
colnames(percent)<-c("trait_prop","selfharm_prop","A_prop","C_prop","E_prop","phenotypic_cor_prop")
bigdata<-data.frame(pheno,percent)
bigdata$`correlation due to A`=paste(specify_decimal(bigdata$A,3), " (", specify_decimal(bigdata$A_prop,1),"%", ")", sep="")
bigdata$`correlation due to C`=paste(specify_decimal(bigdata$C,3), " (", specify_decimal(bigdata$C_prop,1),"%", ")",sep="")
bigdata$`correlation due to E`=paste(specify_decimal(bigdata$E,3), " (", specify_decimal(bigdata$E_prop,1),"%", ")",sep="")
bigdata<-bigdata%>%
add_column(trait_category=ifelse(bigdata$trait=="pSDQ"|
bigdata$trait=="cSDQ"|
bigdata$trait=="pAUT"|
bigdata$trait=="cAUT", "Others",
ifelse(bigdata$trait=="pCONN"|
bigdata$trait=="pEMOLv2"|
bigdata$trait=="pINAT"|
bigdata$trait=="pHYPER"|
bigdata$trait=="cSWAN","Externalising problems",
ifelse(bigdata$trait=="pMFQ"|
bigdata$trait=="cMFQv2"|
bigdata$trait=="pANX"|
bigdata$trait=="cANX"|
bigdata$trait=="cEAT"|
bigdata$trait=="cINSOM","Internalising problems",
ifelse(bigdata$trait=="cCAPS"|
bigdata$trait=="cGRAND"|
bigdata$trait=="cTEPS"|
bigdata$trait=="cANHE"|
bigdata$trait=="cPRND"|
bigdata$trait=="pSANS","Psychotic-like experiences",
ifelse(bigdata$trait=="cSMOK"|
bigdata$trait=="cALC"|
bigdata$trait=="cCANN","Substance abuse",NA))))))%>%
select(trait_category,trait,selfharm,phenotypic_cor,`correlation due to A`,`correlation due to C`,`correlation due to E`)%>%
arrange(trait)%>%
arrange(trait_category)
bigdata$trait[bigdata$trait=="pEMOLv2"]<-"pEMOL"
bigdata$trait[bigdata$trait=="cMFQv2"]<-"cMFQ"
knitr::kable(bigdata,digits=3)%>%
kableExtra::kable_styling(font_size = 12)%>%
kableExtra::collapse_rows()
| trait_category | trait | selfharm | phenotypic_cor | correlation due to A | correlation due to C | correlation due to E |
|---|---|---|---|---|---|---|
| Externalising problems | cSWAN | NSSH | -0.127 | -0.081 (64.1%) | 0.001 (-0.7%) | -0.046 (36.6%) |
| SSH | -0.213 | -0.130 (61.0%) | 0.001 (-0.4%) | -0.084 (39.4%) | ||
| pCONN | NSSH | 0.113 | 0.062 (55.1%) | 0.033 (29.2%) | 0.018 (15.7%) | |
| SSH | 0.163 | 0.089 (55.0%) | 0.049 (29.9%) | 0.024 (15.1%) | ||
| pEMOL | NSSH | 0.150 | 0.047 (31.1%) | 0.067 (44.6%) | 0.036 (24.3%) | |
| SSH | 0.195 | 0.110 (56.6%) | 0.054 (27.7%) | 0.031 (15.8%) | ||
| pHYPER | NSSH | 0.053 | 0.018 (33.1%) | 0.026 (48.9%) | 0.010 (18.1%) | |
| SSH | 0.097 | 0.063 (64.6%) | 0.037 (38.5%) | -0.003 (-3.2%) | ||
| pINAT | NSSH | 0.129 | 0.110 (85.5%) | 0.001 (0.8%) | 0.018 (13.7%) | |
| SSH | 0.176 | 0.144 (81.9%) | 0.001 (0.5%) | 0.031 (17.6%) | ||
| Internalising problems | cANX | NSSH | 0.233 | 0.089 (38.0%) | 0.054 (23.2%) | 0.091 (38.8%) |
| SSH | 0.253 | 0.106 (41.8%) | 0.059 (23.1%) | 0.089 (35.1%) | ||
| cEAT | NSSH | 0.256 | 0.195 (76.3%) | 0.000 (0.0%) | 0.061 (23.7%) | |
| SSH | 0.311 | 0.228 (73.3%) | 0.083 (26.7%) | |||
| cINSOM | NSSH | 0.322 | 0.242 (75.1%) | 0.003 (0.8%) | 0.078 (24.1%) | |
| SSH | 0.361 | 0.270 (74.8%) | 0.002 (0.6%) | 0.089 (24.6%) | ||
| cMFQ | NSSH | 0.377 | 0.177 (47.1%) | 0.081 (21.5%) | 0.119 (31.4%) | |
| SSH | 0.396 | 0.225 (56.7%) | 0.056 (14.1%) | 0.116 (29.2%) | ||
| pANX | NSSH | 0.113 | 0.124 (109.9%) | 0.001 (1.2%) | -0.013 (-11.1%) | |
| SSH | 0.165 | 0.169 (102.5%) | 0.001 (0.6%) | -0.005 (-3.1%) | ||
| pMFQ | NSSH | 0.191 | 0.170 (89.3%) | 0.002 (0.8%) | 0.019 (9.9%) | |
| SSH | 0.227 | 0.197 (86.7%) | 0.001 (0.5%) | 0.029 (12.9%) | ||
| Others | cAUT | NSSH | 0.211 | 0.143 (67.6%) | 0.017 (8.2%) | 0.051 (24.2%) |
| SSH | 0.194 | 0.136 (70.4%) | 0.014 (7.1%) | 0.044 (22.5%) | ||
| cSDQ | NSSH | 0.364 | 0.213 (58.4%) | 0.050 (13.8%) | 0.101 (27.7%) | |
| SSH | 0.386 | 0.227 (58.7%) | 0.044 (11.5%) | 0.115 (29.7%) | ||
| pAUT | NSSH | 0.080 | -0.052 (-65.3%) | 0.115 (143.7%) | 0.017 (21.6%) | |
| SSH | 0.094 | -0.032 (-33.8%) | 0.108 (114.7%) | 0.018 (19.1%) | ||
| pSDQ | NSSH | 0.149 | 0.141 (95.1%) | -0.004 (-2.5%) | 0.011 (7.5%) | |
| SSH | 0.193 | 0.158 (82.0%) | 0.006 (3.0%) | 0.029 (15.0%) | ||
| Psychotic-like experiences | cANHE | NSSH | 0.182 | 0.167 (91.9%) | 0.006 (3.2%) | 0.009 (4.9%) |
| SSH | 0.229 | 0.193 (84.5%) | 0.005 (2.0%) | 0.031 (13.5%) | ||
| cCAPS | NSSH | 0.226 | 0.124 (55.0%) | 0.042 (18.4%) | 0.060 (26.6%) | |
| SSH | 0.252 | 0.105 (41.6%) | 0.051 (20.1%) | 0.096 (38.3%) | ||
| cGRAND | NSSH | -0.052 | -0.044 (85.1%) | 0.004 (-6.8%) | -0.011 (21.8%) | |
| SSH | -0.034 | -0.032 (94.2%) | 0.016 (-48.2%) | -0.018 (53.9%) | ||
| cPRND | NSSH | 0.312 | 0.243 (78.0%) | 0.009 (2.8%) | 0.060 (19.2%) | |
| SSH | 0.331 | 0.216 (65.4%) | 0.010 (3.1%) | 0.104 (31.5%) | ||
| cTEPS | NSSH | -0.208 | -0.180 (86.6%) | 0.000 (0.0%) | -0.028 (13.4%) | |
| SSH | -0.194 | -0.133 (68.6%) | -0.061 (31.4%) | |||
| pSANS | NSSH | 0.141 | 0.010 (7.3%) | 0.082 (58.4%) | 0.048 (34.3%) | |
| SSH | 0.198 | 0.056 (28.1%) | 0.083 (41.8%) | 0.060 (30.1%) | ||
| Substance abuse | cALC | NSSH | 0.138 | 0.009 (6.7%) | 0.077 (56.1%) | 0.051 (37.2%) |
| SSH | 0.162 | -0.057 (-35.3%) | 0.143 (88.1%) | 0.077 (47.2%) | ||
| cCANN | NSSH | 0.267 | 0.155 (58.2%) | 0.068 (25.7%) | 0.043 (16.1%) | |
| SSH | 0.162 (60.5%) | 0.081 (30.1%) | 0.025 (9.4%) | |||
| cSMOK | NSSH | 0.251 | 0.136 (54.0%) | 0.039 (15.5%) | 0.077 (30.5%) | |
| SSH | 0.293 | 0.087 (29.6%) | 0.095 (32.5%) | 0.111 (37.9%) |
#save as excel file for further editting
library(xlsx)
write.xlsx(bigdata, "phenotypic_correlation_tidied_up_25_July_2020.xlsx")
Code to compile genetic and environmental correlations between each measure with both NSSH and SSH in the trivariate models
Note: The column for phenotypic correlation in the table below was later moved to Table S7 using Excel functions after these two tables were generated and exported out from R, as we deemed that was a better way to present the results.
##read RPh,Ra,Rc,Re results
path_CI<-"/Users/kai/OneDrive - King's College London/PhD/TEDS_project/results/14_reanalyses_trivariate/trivariate_estimates_with_CI_16_June_2020.xlsx"
corr <- path_CI %>%
excel_sheets() %>%
set_names() %>%
map_df(read_excel,
path = path_CI,
.id = "trait") #id = column name for the sheet name as column values
corr2<-as.data.frame(corr)
colnames(corr2)[2]<-"correlation"
corr_plot <- corr2 %>%
add_column(typecor=ifelse(grepl("ACE.Rph",corr2$correlation),
"Rph",
ifelse(grepl("ACE.Ra",corr2$correlation),
"Ra",
ifelse(grepl("ACE.Rc",corr2$correlation),
"Rc", "Re")))) %>%
add_column(selfharm=rep(c("NSSH","SSH"),96))%>%
add_column(unique_ID=paste(corr2$trait,corr2$selfharm,sep="_"))%>%
add_column(rater=ifelse(grepl("c",corr2$trait),"child","parent"))
corr_plot$estimate_CI=paste(specify_decimal(corr_plot$estimate,3), " (",specify_decimal(corr_plot$lbound,3), ",", specify_decimal(corr_plot$ubound,3),")", sep="")
corr_plot2<-spread(corr_plot,typecor,estimate_CI)
corr_plot3<-corr_plot2%>%
select(trait,selfharm,Ra,Rc,Re,Rph)
Rph=corr_plot3[!is.na(corr_plot3$Rph),c("trait","selfharm","Rph")]
Ra=corr_plot3[!is.na(corr_plot3$Ra),c("trait","selfharm","Ra")]
Rc=corr_plot3[!is.na(corr_plot3$Rc),c("trait","selfharm","Rc")]
Re=corr_plot3[!is.na(corr_plot3$Re),c("trait","selfharm","Re")]
corr_plot4<-data.frame(Rph,Ra,Rc,Re)
corr_plot5<-corr_plot4%>%
select(trait,selfharm,Rph,Ra,Rc,Re)%>%
add_column(trait_category=ifelse(corr_plot4$trait=="pSDQ"|
corr_plot4$trait=="cSDQ"|
corr_plot4$trait=="pAUT"|
corr_plot4$trait=="cAUT", "Others",
ifelse(corr_plot4$trait=="pCONN"|
corr_plot4$trait=="pEMOLv2"|
corr_plot4$trait=="pINAT"|
corr_plot4$trait=="pHYPER"|
corr_plot4$trait=="cSWAN","Externalising problems",
ifelse(corr_plot4$trait=="pMFQ"|
corr_plot4$trait=="cMFQv2"|
corr_plot4$trait=="pANX"|
corr_plot4$trait=="cANX"|
corr_plot4$trait=="cEAT"|
corr_plot4$trait=="cINSOM","Internalising problems",
ifelse(corr_plot4$trait=="cCAPS"|
corr_plot4$trait=="cGRAND"|
corr_plot4$trait=="cTEPS"|
corr_plot4$trait=="cANHE"|
corr_plot4$trait=="cPRND"|
corr_plot4$trait=="pSANS","Psychotic-like experiences",
ifelse(corr_plot4$trait=="cSMOK"|
corr_plot4$trait=="cALC"|
corr_plot4$trait=="cCANN","Substance abuse",NA))))))%>%
select(trait_category,trait,selfharm,Rph,Ra,Rc,Re)%>%
arrange(trait)%>%
arrange(trait_category)
corr_plot5$trait[corr_plot5$trait=="pEMOLv2"]<-"pEMOL"
corr_plot5$trait[corr_plot5$trait=="cMFQv2"]<-"cMFQ"
knitr::kable(corr_plot5,digits=3)%>%
kableExtra::kable_styling(font_size = 12)%>%
kableExtra::collapse_rows()
| trait_category | trait | selfharm | Rph | Ra | Rc | Re |
|---|---|---|---|---|---|---|
| Externalising problems | cSWAN | NSSH | -0.127 (-0.202,-0.049) | -0.159 (-0.402,0.112) | 1.000 (-1.000,1.000) | -0.096 (-0.266,0.086) |
| SSH | -0.213 (-0.305,-0.113) | -0.268 (-0.698,-0.268) | -0.163 (-0.359,0.048) | |||
| pCONN | NSSH | 0.113 (0.077,0.149) | 0.099 (0.083,0.233) | 1.000 (-0.012,1.000) | 0.069 (-0.019,0.155) | |
| SSH | 0.163 (0.119,0.205) | 0.153 (0.010,0.314) | 1.000 (0.562,1.000) | 0.089 (-0.014,0.177) | ||
| pEMOL | NSSH | 0.150 (0.116,0.182) | 0.098 (0.068,0.224) | 0.868 (-1.000,1.000) | 0.100 (0.022,0.134) | |
| SSH | 0.195 (0.155,0.234) | 0.221 (0.027,0.319) | 0.964 (-1.000,1.000) | 0.089 (-0.023,0.172) | ||
| pHYPER | NSSH | 0.053 (-0.029,0.082) | 0.003 (-0.028,0.033) | 0.470 (-1.000,1.000) | 0.034 (-0.069,0.139) | |
| SSH | 0.097 (0.054,0.138) | 0.121 (-0.023,0.267) | 1.000 (-1.000,1.000) | -0.011 (-0.113,0.087) | ||
| pINAT | NSSH | 0.129 (0.093,0.166) | 0.169 (0.086,0.250) | 0.979 (-1.000,1.000) | 0.058 (-0.027,0.142) | |
| SSH | 0.176 (0.133,0.221) | 0.231 (-0.952,0.964) | 0.542 (-1.000,1.000) | 0.096 (-0.004,0.196) | ||
| Internalising problems | cANX | NSSH | 0.233 (0.202,0.264) | 0.217 (0.105,0.375) | 1.000 (-1.000,1.000) | 0.172 (0.096,0.246) |
| SSH | 0.253 (0.215,0.289) | 0.279 (0.073,0.487) | 0.159 (0.071,0.246) | |||
| cEAT | NSSH | 0.256 (0.023,0.322) | 0.352 (0.122,1.000) | 0.668 (-1.000,1.000) | 0.135 (-0.028,0.294) | |
| SSH | 0.311 (0.220,0.391) | 0.434 (0.189,0.817) | 0.831 (-1.000,1.000) | 0.173 (-0.024,0.363) | ||
| cINSOM | NSSH | 0.322 (0.289,0.357) | 0.530 (0.530,0.714) | 1.000 (-1.000,1.000) | 0.148 (0.068,0.227) | |
| SSH | 0.361 (0.322,0.398) | 0.621 (0.621,0.897) | 0.159 (0.065,0.252) | |||
| cMFQ | NSSH | 0.377 (0.348,0.406) | 0.515 (0.515,0.833) | 0.921 (0.190,1.000) | 0.225 (0.145,0.300) | |
| SSH | 0.396 (0.360,0.431) | 0.671 (0.671,0.982) | 0.873 (0.768,1.000) | 0.207 (0.112,0.301) | ||
| pANX | NSSH | 0.113 (0.063,0.162) | 0.217 (0.016,0.983) | 1.000 (-1.000,1.000) | -0.029 (-0.160,0.104) | |
| SSH | 0.165 (0.108,0.220) | 0.310 (0.114,0.577) | -0.011 (-0.153,0.130) | |||
| pMFQ | NSSH | 0.191 (0.176,0.244) | 0.343 (-1.000,0.531) | 0.966 (-0.983,1.000) | 0.087 (-0.061,0.185) | |
| SSH | 0.227 (0.174,0.282) | 0.381 (0.264,0.417) | -0.986 (-1.000,1.000) | 0.077 (-0.013,0.220) | ||
| Others | cAUT | NSSH | 0.211 (0.178,0.243) | 0.287 (0.258,0.402) | 1.000 (-1.000,1.000) | 0.107 (0.030,0.141) |
| SSH | 0.194 (0.154,0.232) | 0.285 (0.211,0.432) | 0.086 (-0.004,0.176) | |||
| cSDQ | NSSH | 0.364 (0.334,0.393) | 0.452 (0.419,0.578) | 0.211 (0.137,0.284) | ||
| SSH | 0.386 (0.351,0.419) | 0.502 (0.484,0.694) | 1.000 (0.995,1.000) | 0.228 (0.138,0.315) | ||
| pAUT | NSSH | 0.080 (0.044,0.115) | -0.091 (-0.226,0.029) | 1.000 (1.000,1.000) | 0.079 (-0.004,0.162) | |
| SSH | 0.094 (0.052,0.137) | -0.059 (-0.235,0.088) | 1.000 (0.912,1.000) | 0.078 (-0.018,0.173) | ||
| pSDQ | NSSH | 0.149 (0.114,0.183) | 0.218 (0.096,0.245) | -0.036 (-1.000,1.000) | 0.039 (-0.048,0.123) | |
| SSH | 0.193 (0.151,0.233) | 0.257 (-0.488,0.346) | 0.451 (-1.000,1.000) | 0.094 (-0.007,0.189) | ||
| Psychotic-like experiences | cANHE | NSSH | 0.182 (0.149,0.214) | 0.365 (-0.975,0.499) | 1.000 (-1.000,1.000) | 0.016 (-0.060,0.095) |
| SSH | 0.229 (0.190,0.267) | 0.441 (0.441,0.628) | 0.056 (-0.035,0.147) | |||
| cCAPS | NSSH | 0.226 (0.194,0.257) | 0.297 (0.297,0.574) | 0.965 (0.718,1.000) | 0.118 (0.036,0.196) | |
| SSH | 0.252 (0.214,0.288) | 0.268 (0.268,0.588) | 0.996 (-1.000,1.000) | 0.178 (0.083,0.269) | ||
| cGRAND | NSSH | -0.052 (-0.087,-0.017) | -0.087 (-0.283,0.104) | 1.000 (-1.000,1.000) | -0.024 (-0.109,0.061) | |
| SSH | -0.034 (-0.075,0.008) | -0.067 (-0.337,0.146) | -0.036 (-0.137,0.066) | |||
| cPRND | NSSH | 0.312 (0.281,0.342) | 0.476 (0.476,0.704) | 0.572 (-1.000,1.000) | 0.127 (0.044,0.206) | |
| SSH | 0.331 (0.293,0.366) | 0.445 (0.445,0.693) | 0.703 (-1.000,1.000) | 0.209 (0.113,0.300) | ||
| cTEPS | NSSH | -0.208 (-0.240,-0.176) | -0.355 (-0.512,-0.239) | -0.913 (-1.000,1.000) | -0.057 (-0.131,0.018) | |
| SSH | -0.194 (-0.232,-0.157) | -0.277 (-0.470,-0.135) | -0.662 (-1.000,1.000) | -0.118 (-0.205,0.144) | ||
| pSANS | NSSH | 0.141 (0.105,0.176) | 0.018 (-0.106,0.153) | 1.000 (0.930,1.000) | 0.173 (0.085,0.259) | |
| SSH | 0.198 (0.156,0.239) | 0.102 (-0.081,0.268) | 1.000 (0.898,1.000) | 0.201 (0.095,0.302) | ||
| Substance abuse | cALC | NSSH | 0.138 (0.087,0.189) | 0.023 (-0.316,0.339) | 0.999 (-1.000,1.000) | 0.189 (-0.053,0.336) |
| SSH | 0.162 (0.107,0.219) | -0.082 (-0.531,0.325) | 0.991 (0.965,1.000) | 0.180 (-0.018,0.363) | ||
| cCANN | NSSH | 0.267 (0.203,0.330) | 0.353 (0.353,0.680) | 0.852 (-1.000,1.000) | 0.164 (-0.090,0.590) | |
| SSH | 0.267 (0.196,0.338) | 0.466 (0.466,0.888) | 0.985 (-1.000,1.000) | 0.096 (-0.215,0.391) | ||
| cSMOK | NSSH | 0.251 (0.202,0.301) | 0.253 (-0.010,0.538) | 0.981 (-1.000,1.000) | 0.276 (0.092,0.438) | |
| SSH | 0.293 (0.237,0.348) | 0.190 (-0.990,0.507) | 0.998 (-1.000,1.000) | 0.315 (0.117,0.572) |
#save the table into an excel file for further edit
write.xlsx(corr_plot5,"Ra_Rc_Re_compiled_25_July_2020.xlsx")
# plot graph for Rph and proportion
#load packages
library(tidyverse)
library(fs)
library(readxl)
library(ggforce)
library(patchwork)
library(viridis)
library(colortools)
library(plyr)
library(drlib)
library(psych)
path<-"/Users/kai/OneDrive - King's College London/PhD/TEDS_project/results/14_reanalyses_trivariate/trivariate_proportion_16_June_2020.xlsx"
prop <- path %>%
excel_sheets() %>%
set_names() %>%
map_df(read_excel,
path = path,
.id = "trait") #id = column name for the sheet name as column values
prop2<-as.data.frame(prop)
long_prop<-gather(prop2,ACE,proportion,A:E)
colnames(long_prop)<-c( "trait","selfharm","ACE","phenotypic_cor")
plot_data<- filter(long_prop, selfharm=="NSSH"|selfharm=="SSH")
plot_data$rater=NA
plot_data$rater<-as.character(grepl("c",plot_data$trait))
plot_data$rater2<-ifelse(plot_data$rater=="TRUE","child","parent")
plot_data$unique_ID<- with(plot_data, paste(trait,selfharm, sep="_"))
plot_data<-plot_data%>%
add_column(trait_category=ifelse(plot_data$trait=="pSDQ"|
plot_data$trait=="cSDQ"|
plot_data$trait=="pAUT"|
plot_data$trait=="cAUT", "Others",
ifelse(plot_data$trait=="pCONN"|
plot_data$trait=="pEMOLv2"|
plot_data$trait=="pINAT"|
plot_data$trait=="pHYPER"|
plot_data$trait=="cSWAN","Externalising problems",
ifelse(plot_data$trait=="pMFQ"|
plot_data$trait=="cMFQv2"|
plot_data$trait=="pANX"|
plot_data$trait=="cANX"|
plot_data$trait=="cEAT"|
plot_data$trait=="cINSOM","Internalising problems",
ifelse(plot_data$trait=="cCAPS"|
plot_data$trait=="cGRAND"|
plot_data$trait=="cTEPS"|
plot_data$trait=="cANHE"|
plot_data$trait=="cPRND"|
plot_data$trait=="pSANS","Psychotic-like experiences",
ifelse(plot_data$trait=="cSMOK"|
plot_data$trait=="cALC"|
plot_data$trait=="cCANN","Substance abuse",NA))))))
#plot_data$trait_ordered=factor(plot_data$unique_ID, levels = plot_data$unique_ID[order(plot_data$phenotypic_cor)])
#used this to choose colour: http://www.sthda.com/english/wiki/the-elements-of-choosing-colors-for-great-data-visualization-in-r
#wheel("darkcyan", num = 3)
#internalising problems
plot_data$trait_p = factor(plot_data$trait, levels=c("cMFQv2","cINSOM",'cEAT','cANX','cANHE','pMFQ','pANX'),
labels=c("cMFQ","cINSOM",'cEAT','cANX','cANHE','pMFQ','pANX'))
p<-ggplot(plot_data[plot_data$trait_category=="Internalising problems",],
aes(fill=ACE, y=phenotypic_cor, x=selfharm)) +
geom_bar(position="stack", stat="identity")+
theme(axis.text.x = element_text(angle = 90, hjust = 1))+
facet_grid(~trait_p)+ scale_fill_manual(values = wheel("darkcyan", num = 3))+ theme(legend.position = "none")+
theme(axis.title.x=element_blank(), axis.text.x=element_blank(), axis.ticks.x=element_blank(),
title=element_text(size=9,face="bold"),
axis.title.y = element_text(size=10),strip.text = element_text(size=9))+
labs(title="Internalising problems",y="Phenotypic correlation")+ylim(-0.22,0.4)
#externalising problems
plot_data$trait_q = factor(plot_data$trait, levels=c("cSDQ","cAUT",'pSDQ','pCONN','pEMOLv2','pINAT','pHYPER',"cSWAN","pAUT"),
labels=c("cSDQ","cAUT",'pSDQ','pCONN','pEMOL','pINAT','pHYPER',"cSWAN","pAUT"))
q<-ggplot(plot_data[plot_data$trait_category=="Externalising problems",],
aes(fill=ACE, y=phenotypic_cor, x=selfharm)) +
geom_bar(position="stack", stat="identity")+
theme(axis.text.x = element_blank(),axis.title.x=element_blank(),axis.ticks.x=element_blank(),
legend.title = element_blank(),axis.title.y = element_text(size=10),
title=element_text(size=9,face="bold"),strip.text = element_text(size=9))+
facet_grid(~trait_q)+scale_fill_manual(values = wheel("darkcyan", num = 3))+
labs(title="Externalising problems",y="Phenotypic correlation")+ylim(-0.22,0.4)+
guides(fill = guide_legend(nrow = 1, byrow = TRUE))
#psychotic symptoms
plot_data$trait_r = factor(plot_data$trait, levels=c("cPRND","cCAPS",'cANHE','pSANS','cGRAND','cTEPS'))
r<-ggplot(plot_data[plot_data$trait_category=="Psychotic-like experiences",],
aes(fill=ACE, y=phenotypic_cor, x=selfharm)) +
geom_bar(position="stack", stat="identity")+
theme(axis.text.x = element_text(angle = 45),
title=element_text(size=9,face="bold"),strip.text = element_text(size=9),
axis.title.x=element_text(face="bold",size=11),
axis.title.y = element_text(size=10))+
facet_grid(~trait_r)+scale_fill_manual(values = wheel("darkcyan", num = 3))+ theme(legend.position = "none")+
labs(title="Psychotic-like experiences", x = "Type of self-harm",y="Phenotypic correlation")+ylim(-0.22,0.4)
#substance abuse
plot_data$trait_s = factor(plot_data$trait, levels=c("cSMOK","cCANN",'cALC'))
s<-ggplot(plot_data[plot_data$trait_category=="Substance abuse",],
aes(fill=ACE, y=phenotypic_cor, x=selfharm)) +
geom_bar(position="stack", stat="identity")+
facet_grid(~trait_s)+scale_fill_manual(values = wheel("darkcyan", num = 3))+
theme(axis.title.x=element_blank(), axis.text.x=element_blank(), axis.ticks.x=element_blank(),
title=element_text(size=9,face="bold"),strip.text = element_text(size=9),
axis.title.y = element_text(size=10))+
theme(legend.position = "none")+labs(title="Substance abuse",y="Phenotypic correlation")+ylim(-0.22,0.4)
#others
plot_data$trait_t = factor(plot_data$trait, levels=c("cSDQ",'cAUT',"pSDQ", 'pAUT'))
t<-ggplot(plot_data[plot_data$trait_category=="Others",],
aes(fill=ACE, y=phenotypic_cor, x=selfharm)) +
geom_bar(position="stack", stat="identity")+
theme(axis.text.x = element_text(angle = 90, hjust = 1))+
facet_grid(~trait_t)+scale_fill_manual(values = wheel("darkcyan", num = 3))+
theme(axis.title.x=element_blank(),axis.text.x=element_blank(),axis.text.y=element_blank(), axis.ticks=element_blank(),
title=element_text(size=9,face="bold"),axis.title.y = element_text(size=10),strip.text = element_text(size=9))+
labs(title="Others")+ theme(legend.position = "none")+ylim(-0.22,0.4)+ylab(label="")
#use patchwork to have 4 plots together:
qq<-(q+plot_spacer()+plot_layout(ncol=2,widths = c(100,1)))
st<-(s+t+plot_layout(ncol=2,widths = c(3,4)))
pheno_plot<-(qq/st/p/r)
#pheno_plot<-(p/((r|s)+ plot_layout(ncol=2,widths=c(2,1))))/q
pheno_plot
######## now plot the second graph for rG, rC and rE #######
path_rg<-"/Users/kai/OneDrive - King's College London/PhD/TEDS_project/results/14_reanalyses_trivariate/trivariate_estimates_with_CI_16_June_2020.xlsx"
corr <- path_rg %>%
excel_sheets() %>%
set_names() %>%
map_df(read_excel,
path = path_rg,
.id = "trait") #id = column name for the sheet name as column values
corr2<-as.data.frame(corr)
colnames(corr2)[2]<-"correlation"
corr_plot <- corr2 %>%
add_column(typecor=ifelse(grepl("ACE.Rph",corr2$correlation),
"Rph",
ifelse(grepl("ACE.Ra",corr2$correlation),
"Ra",
ifelse(grepl("ACE.Rc",corr2$correlation),
"Rc", "Re")))) %>%
add_column(selfharm=rep(c("NSSH","SSH"),96))%>%
add_column(unique_ID=paste(corr2$trait,corr2$selfharm,sep="_"))%>%
add_column(rater=ifelse(grepl("c",corr2$trait),"child","parent"))
corr_plot<-corr_plot%>%
add_column(trait_category=ifelse(corr_plot$trait=="pSDQ"|
corr_plot$trait=="cSDQ"|
corr_plot$trait=="pAUT"|
corr_plot$trait=="cAUT","Others",
ifelse(corr_plot$trait=="pCONN"|
corr_plot$trait=="pEMOLv2"|
corr_plot$trait=="pINAT"|
corr_plot$trait=="pHYPER"|
corr_plot$trait=="cSWAN","Externalising problems",
ifelse(corr_plot$trait=="pMFQ"|
corr_plot$trait=="cMFQv2"|
corr_plot$trait=="pANX"|
corr_plot$trait=="cANX"|
corr_plot$trait=="cEAT"|
corr_plot$trait=="cINSOM","Internalising problems",
ifelse(corr_plot$trait=="cCAPS"|
corr_plot$trait=="cGRAND"|
corr_plot$trait=="cTEPS"|
corr_plot$trait=="cANHE"|
corr_plot$trait=="cPRND"|
corr_plot$trait=="pSANS","Psychotic-like experiences",
ifelse(corr_plot$trait=="cSMOK"|
corr_plot$trait=="cALC"|
corr_plot$trait=="cCANN","Substance abuse","No"))))))
corr_plot$trait_ra = factor(corr_plot$trait, levels=c("pHYPER",'pCONN',"pEMOLv2",'pINAT','pSDQ',"cAUT","cSDQ","pAUT","cSWAN",
"cANX","pANX","pMFQ","cEAT","cINSOM","cMFQv2",
"pSANS","cCAPS","cANHE","cPRND","cGRAND","cTEPS",
"cSMOK","cCANN","cALC"),
labels=c("pHYPER",'pCONN',"pEMOL",'pINAT','pSDQ',"cAUT","cSDQ","pAUT","cSWAN",
"cANX","pANX","pMFQ","cEAT","cINSOM","cMFQ",
"pSANS","cCAPS","cANHE","cPRND","cGRAND","cTEPS",
"cSMOK","cCANN","cALC"))
#### try to plot a heatmap suggested by reviewer ######
#https://jcoliver.github.io/learn-r/006-heatmaps.html
#https://stackoverflow.com/questions/13016022/ggplot2-heatmaps-using-different-gradients-for-categories
re_heat<-ggplot(corr_plot[corr_plot$typecor=="Re",],
mapping=aes(fill=estimate, x=trait_ra,y=selfharm))+
geom_tile()+
facet_grid(vars(typecor),vars(trait_category),scales = "free_x", space = "free_x",
labeller=labeller(trait_category=label_wrap_gen(width=10),
typecor=c(Re="Re")))+
theme(axis.text.x = element_text(angle =50, hjust = 1, size=10, face="plain"),
strip.text.x=element_blank(),
axis.title=element_blank(),
strip.text= element_text(size = 10, face="plain"),
axis.text.y=element_text(size=10, face="plain"))+
scale_fill_gradient2(low = "blue", high = "red", mid = "white",
midpoint = 0, limit = c(-0.7,0.7), space = "Lab",
name="")
ra_heat<-ggplot(corr_plot[corr_plot$typecor=="Ra",],
mapping=aes(fill=estimate, x=trait_ra,y=selfharm))+
geom_tile()+
facet_grid(vars(typecor),vars(trait_category),scales = "free_x", space = "free_x",
labeller=labeller(trait_category=label_wrap_gen(width=10),
typecor=c(Ra="Rg")))+
theme(axis.title=element_blank(),
axis.text.x=element_blank(),
axis.ticks.x=element_blank(),
legend.title = element_blank(),
strip.text= element_text(size = 10, face="plain"),
axis.text.y=element_text(size=10, face="plain"),
legend.position = "none")+
scale_fill_gradient2(low = "blue", high = "red", mid = "white",
midpoint = 0, limit = c(-0.7,0.7), space = "Lab",
name="")
rare_heat<-(ra_heat/re_heat)+plot_layout(guides="collect")
rare_heat
Code to compile goodness of fit tests results into a table
#now read the chisquare results
path_chi<-"/Users/kai/OneDrive - King's College London/PhD/TEDS_project/results/14_reanalyses_trivariate/trivariate_constrained_results_16_June_2020.xlsx"
chi <- path_chi %>%
excel_sheets() %>%
set_names() %>%
map_df(read_excel,
path = path_chi,
.id = "trait") #id = column name for the sheet name as column values
chi2<-chi%>%
add_column(trait_category=ifelse(chi$trait=="pSDQ"|
chi$trait=="cSDQ"|
chi$trait=="pAUT"|
chi$trait=="cAUT", "Others",
ifelse(chi$trait=="pCONN"|
chi$trait=="pEMOLv2"|
chi$trait=="pINAT"|
chi$trait=="pHYPER"|
chi$trait=="cSWAN","Externalising problems",
ifelse(chi$trait=="pMFQ"|
chi$trait=="cMFQv2"|
chi$trait=="pANX"|
chi$trait=="cANX"|
chi$trait=="cEAT"|
chi$trait=="cINSOM","Internalising problems",
ifelse(chi$trait=="cCAPS"|
chi$trait=="cGRAND"|
chi$trait=="cTEPS"|
chi$trait=="cANHE"|
chi$trait=="cPRND"|
chi$trait=="pSANS","Psychotic-like experiences",
ifelse(chi$trait=="cSMOK"|
chi$trait=="cALC"|
chi$trait=="cCANN","Substance abuse",NA))))))%>%
select(trait_category,`...1`,trait,minus2LL,df,AIC,diffLL,diffdf,p)%>%
arrange(trait_category)
chi_p<-chi2[!is.na(chi2$p),]
chi_p$q<-p.adjust(chi_p$p,method="fdr")
chi_merged<-merge(x = chi2, y = chi_p[ , c("p", "q")], by = "p", all.x=T, all.y=T)%>%
select(trait_category,trait,`...1`,minus2LL,df,AIC,diffLL,diffdf,p,q)%>%
arrange(`...1`)%>%
arrange(trait)%>%
arrange(trait_category)
chi_merged$minus2LL<-specify_decimal(chi_merged$minus2LL,2)
chi_merged$AIC<-specify_decimal(chi_merged$AIC,2)
chi_merged$diffLL<-specify_decimal(chi_merged$diffLL,2)
chi_merged$trait[chi_merged$trait=="pEMOLv2"]<-"pEMOL"
chi_merged$trait[chi_merged$trait=="cMFQv2"]<-"cMFQ"
chi_merged$p[which(is.na(chi_merged$p))]<-chi_merged$p[which(is.na(chi_merged$p))+1]
chi_merged$q[which(is.na(chi_merged$q))]<-chi_merged$q[which(is.na(chi_merged$q))+1]
chi_merged$diffdf[which(is.na(chi_merged$diffdf))]<-chi_merged$diffdf[which(is.na(chi_merged$diffdf))+1]
chi_merged$diffLL[which(chi_merged$diffLL=="NA")] <- chi_merged$diffLL[which(chi_merged$diffLL=="NA")+1]
colnames(chi_merged)<-c("Category","Measure","Model", "-2 Log Likelihood","df","AIC","∆ -2 Log Likelihood",
"∆ df", "p-value", "q-value")
chi_merged$Model[chi_merged$Model==1]<-"ACE model"
chi_merged$Model[chi_merged$Model==2]<-"Constrained model"
knitr::kable(chi_merged,digits=3)%>%
kableExtra::kable_styling(font_size = 12)%>%
kableExtra::collapse_rows()
| Category | Measure | Model | -2 Log Likelihood | df | AIC | ∆ -2 Log Likelihood | ∆ df | p-value | q-value |
|---|---|---|---|---|---|---|---|---|---|
| Externalising problems | cSWAN | ACE model | 23036.39 | 19852 | -16667.61 | 4.32 | 3 | 0.229 | 0.610 |
| Constrained model | 23040.71 | 19855 | -16669.29 | ||||||
| pCONN | ACE model | 41725.73 | 25890 | -10054.27 | 2.07 | 0.559 | 0.789 | ||
| Constrained model | 41727.79 | 25893 | -10058.21 | ||||||
| pEMOL | ACE model | 40229.31 | 25890 | -11550.69 | 5.35 | 0.148 | 0.595 | ||
| Constrained model | 40234.66 | 25893 | -11551.34 | ||||||
| pHYPER | ACE model | 42996.61 | 25887 | -8777.39 | 2.22 | 0.528 | 0.789 | ||
| Constrained model | 42998.83 | 25890 | -8781.17 | ||||||
| pINAT | ACE model | 42909.11 | 25889 | -8868.89 | 8.08 | 0.044 | 0.356 | ||
| Constrained model | 42917.19 | 25892 | -8866.81 | ||||||
| Internalising problems | cANX | ACE model | 45759.79 | 25896 | -6032.21 | 0.61 | 0.893 | 0.991 | |
| Constrained model | 45760.40 | 25899 | -6037.60 | ||||||
| cEAT | ACE model | 25519.81 | 19839 | -14158.19 | 3.28 | 0.350 | 0.617 | ||
| Constrained model | 25523.09 | 19842 | -14160.91 | ||||||
| cINSOM | ACE model | 36036.72 | 24115 | -12193.28 | 5.20 | 0.157 | 0.595 | ||
| Constrained model | 36041.93 | 24118 | -12194.07 | ||||||
| cMFQ | ACE model | 45289.22 | 25896 | -6502.78 | 2.16 | 0.541 | 0.789 | ||
| Constrained model | 45291.38 | 25899 | -6506.62 | ||||||
| pANX | ACE model | 28136.81 | 20905 | -13673.19 | 4.66 | 0.198 | 0.595 | ||
| Constrained model | 28141.48 | 20908 | -13674.52 | ||||||
| pMFQ | ACE model | 56337.82 | 25894 | 4549.82 | 9.85 | 0.020 | 0.356 | ||
| Constrained model | 56347.67 | 25897 | 4553.67 | ||||||
| Others | cAUT | ACE model | 46048.29 | 25889 | -5729.71 | 0.66 | 0.882 | 0.991 | |
| Constrained model | 46048.95 | 25892 | -5735.05 | ||||||
| cSDQ | ACE model | 45951.91 | 25887 | -5822.09 | 3.35 | 0.341 | 0.617 | ||
| Constrained model | 45955.26 | 25890 | -5824.74 | ||||||
| pAUT | ACE model | 42388.26 | 25894 | -9399.74 | 0.32 | 0.957 | 0.991 | ||
| Constrained model | 42388.58 | 25897 | -9405.42 | ||||||
| pSDQ | ACE model | 45621.87 | 25899 | -6176.13 | 4.73 | 0.192 | 0.595 | ||
| Constrained model | 45626.61 | 25902 | -6177.39 | ||||||
| Psychotic-like experiences | cANHE | ACE model | 22611.77 | 25886 | -29160.23 | 8.94 | 0.030 | 0.356 | |
| Constrained model | 22620.71 | 25889 | -29157.29 | ||||||
| cCAPS | ACE model | 42088.83 | 25898 | -9707.17 | 3.26 | 0.353 | 0.617 | ||
| Constrained model | 42092.09 | 25901 | -9709.91 | ||||||
| cGRAND | ACE model | 49025.66 | 25889 | -2752.34 | 0.11 | 0.991 | 0.991 | ||
| Constrained model | 49025.77 | 25892 | -2758.23 | ||||||
| cPRND | ACE model | 44502.34 | -7281.66 | 5.44 | 0.142 | 0.595 | |||
| Constrained model | 44507.78 | 25895 | -7282.22 | ||||||
| cTEPS | ACE model | 71995.56 | 25897 | 20201.56 | 3.21 | 0.360 | 0.617 | ||
| Constrained model | 71998.78 | 25900 | 20198.78 | ||||||
| pSANS | ACE model | 48818.38 | 25888 | -2957.62 | 3.88 | 0.274 | |||
| Constrained model | 48822.26 | 25891 | -2959.74 | ||||||
| Substance abuse | cALC | ACE model | 21776.33 | 18573 | -15369.67 | 0.80 | 0.849 | 0.991 | |
| Constrained model | 21777.14 | 18576 | -15374.86 | ||||||
| cCANN | ACE model | 17200.98 | 19226 | -21251.02 | 0.51 | 0.918 | |||
| Constrained model | 17201.49 | 19229 | -21256.51 | ||||||
| cSMOK | ACE model | 21512.15 | 19210 | -16907.85 | 1.78 | 0.620 | 0.827 | ||
| Constrained model | 21513.93 | 19213 | -16912.07 |
#save the table to an excel file
write.xlsx(chi_merged,"chi_test_2LL_2dp_25_July_2020.xlsx")