I. Meta-data

# list of loaded packages and versions
si <- devtools::session_info()[[2]]
rownames(si) <- NULL
si %>% 
  select(package, loadedversion, date, source) %>% 
  
  #red bold the called packages
  mutate(package = cell_spec(package, 
                             color = ifelse(package %in% libraries, "red", "black"),
                             bold = ifelse(package %in% libraries, TRUE, FALSE))) %>% 
  knitr::kable(escape = F, caption = "All loaded packages. Bolded in red are those loaded explicitly with <code>library()</code>") %>% 
  kable_styling() %>% 
  scroll_box(height = "300px")
All loaded packages. Bolded in red are those loaded explicitly with library()
package loadedversion date source
abind 1.4-5 2016-07-21 CRAN (R 4.2.0)
arm 1.12-2 2021-10-15 CRAN (R 4.2.0)
assertthat 0.2.1 2019-03-21 CRAN (R 4.2.0)
backports 1.4.1 2021-12-13 CRAN (R 4.2.0)
base64enc 0.1-3 2015-07-28 CRAN (R 4.2.0)
bayestestR 0.12.1 2022-05-02 CRAN (R 4.2.0)
boot 1.3-28 2021-05-03 CRAN (R 4.2.1)
brio 1.1.3 2021-11-30 CRAN (R 4.2.0)
broom 0.8.0 2022-04-13 CRAN (R 4.2.0)
bslib 0.3.1 2021-10-06 CRAN (R 4.2.0)
cachem 1.0.6 2021-08-19 CRAN (R 4.2.0)
callr 3.7.0 2021-04-20 CRAN (R 4.2.0)
carData 3.0-5 2022-01-06 CRAN (R 4.2.0)
cellranger 1.1.0 2016-07-27 CRAN (R 4.2.0)
checkmate 2.1.0 2022-04-21 CRAN (R 4.2.0)
cli 3.3.0 2022-04-25 CRAN (R 4.2.0)
cluster 2.1.3 2022-03-28 CRAN (R 4.2.1)
coda 0.19-4 2020-09-30 CRAN (R 4.2.0)
codetools 0.2-18 2020-11-04 CRAN (R 4.2.1)
colorspace 2.0-3 2022-02-21 CRAN (R 4.2.0)
corpcor 1.6.10 2021-09-16 CRAN (R 4.2.0)
cowplot 1.1.1 2020-12-30 CRAN (R 4.2.0)
crayon 1.5.1 2022-03-26 CRAN (R 4.2.0)
curl 4.3.2 2021-06-23 CRAN (R 4.2.0)
data.table 1.14.2 2021-09-27 CRAN (R 4.2.0)
datawizard 0.4.1 2022-05-16 CRAN (R 4.2.0)
DBI 1.1.2 2021-12-20 CRAN (R 4.2.0)
dbplyr 2.2.0 2022-06-05 CRAN (R 4.2.0)
desc 1.4.1 2022-03-06 CRAN (R 4.2.0)
devtools 2.4.3 2021-11-30 CRAN (R 4.2.0)
digest 0.6.29 2021-12-01 CRAN (R 4.2.0)
dplyr 1.0.9 2022-04-28 CRAN (R 4.2.0)
effectsize 0.7.0 2022-05-26 CRAN (R 4.2.0)
ellipsis 0.3.2 2021-04-29 CRAN (R 4.2.0)
emmeans 1.7.4-1 2022-05-15 CRAN (R 4.2.0)
estimability 1.3 2018-02-11 CRAN (R 4.2.0)
evaluate 0.15 2022-02-18 CRAN (R 4.2.0)
fansi 1.0.3 2022-03-24 CRAN (R 4.2.0)
fastmap 1.1.0 2021-01-25 CRAN (R 4.2.0)
fdrtool 1.2.17 2021-11-13 CRAN (R 4.2.0)
forcats 0.5.1 2021-01-27 CRAN (R 4.2.0)
foreign 0.8-82 2022-01-16 CRAN (R 4.2.1)
Formula 1.2-4 2020-10-16 CRAN (R 4.2.0)
fs 1.5.2 2021-12-08 CRAN (R 4.2.0)
generics 0.1.2 2022-01-31 CRAN (R 4.2.0)
ggeffects 1.1.2 2022-04-10 CRAN (R 4.2.0)
ggplot2 3.3.6 2022-05-03 CRAN (R 4.2.0)
glasso 1.11 2019-10-01 CRAN (R 4.2.0)
glue 1.6.2 2022-02-24 CRAN (R 4.2.0)
gridExtra 2.3 2017-09-09 CRAN (R 4.2.0)
gtable 0.3.0 2019-03-25 CRAN (R 4.2.0)
gtools 3.9.2.1 2022-05-23 CRAN (R 4.2.0)
haven 2.5.0 2022-04-15 CRAN (R 4.2.0)
Hmisc 4.7-0 2022-04-19 CRAN (R 4.2.0)
hms 1.1.1 2021-09-26 CRAN (R 4.2.0)
htmlTable 2.4.0 2022-01-04 CRAN (R 4.2.0)
htmltools 0.5.2 2021-08-25 CRAN (R 4.2.0)
htmlwidgets 1.5.4 2021-09-08 CRAN (R 4.2.0)
httr 1.4.3 2022-05-04 CRAN (R 4.2.0)
igraph 1.3.1 2022-04-20 CRAN (R 4.2.0)
insight 0.17.1 2022-05-13 CRAN (R 4.2.0)
jpeg 0.1-9 2021-07-24 CRAN (R 4.2.0)
jquerylib 0.1.4 2021-04-26 CRAN (R 4.2.0)
jsonlite 1.8.0 2022-02-22 CRAN (R 4.2.0)
kableExtra 1.3.4 2021-02-20 CRAN (R 4.2.0)
knitr 1.39 2022-04-26 CRAN (R 4.2.0)
kutils 1.70 2020-04-29 CRAN (R 4.2.0)
labelled 2.9.1 2022-05-05 CRAN (R 4.2.0)
lattice 0.20-45 2021-09-22 CRAN (R 4.2.1)
latticeExtra 0.6-29 2019-12-19 CRAN (R 4.2.0)
lavaan 0.6-11 2022-03-31 CRAN (R 4.2.0)
lifecycle 1.0.1 2021-09-24 CRAN (R 4.2.0)
likert 1.3.5 2016-12-31 CRAN (R 4.2.0)
lisrelToR 0.1.5 2022-05-09 CRAN (R 4.2.0)
lme4 1.1-29 2022-04-07 CRAN (R 4.2.0)
lubridate 1.8.0 2021-10-07 CRAN (R 4.2.0)
magick 2.7.3 2021-08-18 CRAN (R 4.2.0)
magrittr 2.0.3 2022-03-30 CRAN (R 4.2.0)
MASS 7.3-57 2022-04-22 CRAN (R 4.2.1)
Matrix 1.4-1 2022-03-23 CRAN (R 4.2.1)
matrixStats 0.62.0 2022-04-19 CRAN (R 4.2.0)
memoise 2.0.1 2021-11-26 CRAN (R 4.2.0)
mi 1.1 2022-06-06 CRAN (R 4.2.0)
minqa 1.2.4 2014-10-09 CRAN (R 4.2.0)
mnormt 2.1.0 2022-06-07 CRAN (R 4.2.0)
modelr 0.1.8 2020-05-19 CRAN (R 4.2.0)
munsell 0.5.0 2018-06-12 CRAN (R 4.2.0)
mvtnorm 1.1-3 2021-10-08 CRAN (R 4.2.0)
nlme 3.1-157 2022-03-25 CRAN (R 4.2.1)
nloptr 2.0.3 2022-05-26 CRAN (R 4.2.0)
nnet 7.3-17 2022-01-16 CRAN (R 4.2.1)
OpenMx 2.20.6 2022-03-09 CRAN (R 4.2.0)
openxlsx 4.2.5 2021-12-14 CRAN (R 4.2.0)
pander 0.6.5 2022-03-18 CRAN (R 4.2.0)
parameters 0.18.1 2022-05-29 CRAN (R 4.2.0)
pbapply 1.5-0 2021-09-16 CRAN (R 4.2.0)
pbivnorm 0.6.0 2015-01-23 CRAN (R 4.2.0)
performance 0.9.0 2022-03-30 CRAN (R 4.2.0)
pillar 1.7.0 2022-02-01 CRAN (R 4.2.0)
pkgbuild 1.3.1 2021-12-20 CRAN (R 4.2.0)
pkgconfig 2.0.3 2019-09-22 CRAN (R 4.2.0)
pkgload 1.2.4 2021-11-30 CRAN (R 4.2.0)
plyr 1.8.7 2022-03-24 CRAN (R 4.2.0)
png 0.1-7 2013-12-03 CRAN (R 4.2.0)
prettyunits 1.1.1 2020-01-24 CRAN (R 4.2.0)
processx 3.6.0 2022-06-10 CRAN (R 4.2.0)
pryr 0.1.5 2021-07-26 CRAN (R 4.2.0)
ps 1.7.0 2022-04-23 CRAN (R 4.2.0)
psych 2.2.5 2022-05-10 CRAN (R 4.2.0)
purrr 0.3.4 2020-04-17 CRAN (R 4.2.0)
qgraph 1.9.2 2022-03-04 CRAN (R 4.2.0)
R6 2.5.1 2021-08-19 CRAN (R 4.2.0)
rapportools 1.1 2022-03-22 CRAN (R 4.2.0)
RColorBrewer 1.1-3 2022-04-03 CRAN (R 4.2.0)
Rcpp 1.0.8.3 2022-03-17 CRAN (R 4.2.0)
RcppParallel 5.1.5 2022-01-05 CRAN (R 4.2.0)
readr 2.1.2 2022-01-30 CRAN (R 4.2.0)
readxl 1.4.0 2022-03-28 CRAN (R 4.2.0)
remotes 2.4.2 2021-11-30 CRAN (R 4.2.0)
reprex 2.0.1 2021-08-05 CRAN (R 4.2.0)
reshape2 1.4.4 2020-04-09 CRAN (R 4.2.0)
rio 0.5.29 2021-11-22 CRAN (R 4.2.0)
rlang 1.0.3 2022-06-27 CRAN (R 4.2.0)
rmarkdown 2.14 2022-04-25 CRAN (R 4.2.0)
rockchalk 1.8.152 2022-05-20 CRAN (R 4.2.0)
rpart 4.1.16 2022-01-24 CRAN (R 4.2.1)
rprojroot 2.0.3 2022-04-02 CRAN (R 4.2.0)
rstudioapi 0.13 2020-11-12 CRAN (R 4.2.0)
rvest 1.0.2 2021-10-16 CRAN (R 4.2.0)
sass 0.4.1 2022-03-23 CRAN (R 4.2.0)
scales 1.2.0 2022-04-13 CRAN (R 4.2.0)
sem 3.1-15 2022-04-10 CRAN (R 4.2.0)
semPlot 1.1.5 2022-03-08 CRAN (R 4.2.0)
sessioninfo 1.2.2 2021-12-06 CRAN (R 4.2.0)
sjlabelled 1.2.0 2022-04-10 CRAN (R 4.2.0)
sjmisc 2.8.9 2021-12-03 CRAN (R 4.2.0)
sjPlot 2.8.10 2021-11-26 CRAN (R 4.2.0)
sjstats 0.18.1 2021-01-09 CRAN (R 4.2.0)
stringi 1.7.6 2021-11-29 CRAN (R 4.2.0)
stringr 1.4.0 2019-02-10 CRAN (R 4.2.0)
summarytools 1.0.1 2022-05-20 CRAN (R 4.2.0)
survival 3.3-1 2022-03-03 CRAN (R 4.2.1)
svglite 2.1.0 2022-02-03 CRAN (R 4.2.0)
systemfonts 1.0.4 2022-02-11 CRAN (R 4.2.0)
testthat 3.1.4 2022-04-26 CRAN (R 4.2.0)
tibble 3.1.7 2022-05-03 CRAN (R 4.2.0)
tidyr 1.2.0 2022-02-01 CRAN (R 4.2.0)
tidyselect 1.1.2 2022-02-21 CRAN (R 4.2.0)
tidyverse 1.3.1 2021-04-15 CRAN (R 4.2.0)
tzdb 0.3.0 2022-03-28 CRAN (R 4.2.0)
usethis 2.1.6 2022-05-25 CRAN (R 4.2.0)
utf8 1.2.2 2021-07-24 CRAN (R 4.2.0)
vctrs 0.4.1 2022-04-13 CRAN (R 4.2.0)
viridisLite 0.4.0 2021-04-13 CRAN (R 4.2.0)
webshot 0.5.3 2022-04-14 CRAN (R 4.2.0)
withr 2.5.0 2022-03-03 CRAN (R 4.2.0)
xfun 0.31 2022-05-10 CRAN (R 4.2.0)
XML 3.99-0.10 2022-06-09 CRAN (R 4.2.0)
xml2 1.3.3 2021-11-30 CRAN (R 4.2.0)
xtable 1.8-4 2019-04-21 CRAN (R 4.2.0)
yaml 2.3.5 2022-02-21 CRAN (R 4.2.0)
zip 2.2.0 2021-05-31 CRAN (R 4.2.0)

II. MPQ cleaning and descriptives

#load data
mpq <- rio::import(file = "./Data/SIBS_LONGITUDINAL_PERSONALITY_20210413.csv") %>% 
  select(-1)
rel_IN <- rio::import(file = "./Data/rel_IN.sav")
rel_FU1 <- rio::import(file = "./Data/rel_FU1.sav")
lei <- rio::import(file = './Data/lei.sav')
lei[is.na(lei)] <- 0

#aggression items
mpq$AG_IN <- mpq %>% 
  select(starts_with("AG") & ends_with("IN")) %>% 
  rowMeans(na.rm = T)
mpq$AG_FU1 <- mpq %>% 
  select(starts_with("AG") & ends_with("FU1")) %>% 
  rowMeans(na.rm = T)
mpq$AG_FU2 <- mpq %>% 
  select(starts_with("AG") & ends_with("FU2")) %>% 
  rowMeans(na.rm = T)
mpq$AG_FU3 <- mpq %>% 
  select(starts_with("AG") & ends_with("FU3")) %>% 
  rowMeans(na.rm = T)

#control items
mpq$CON_IN <- mpq %>% 
  select(starts_with("CON") & ends_with("IN")) %>% 
  rowMeans(na.rm = T)
mpq$CON_FU1 <- mpq %>% 
  select(starts_with("CON") & ends_with("FU1")) %>% 
  rowMeans(na.rm = T)
mpq$CON_FU2 <- mpq %>% 
  select(starts_with("CON") & ends_with("FU2")) %>% 
  rowMeans(na.rm = T)
mpq$CON_FU3 <- mpq %>% 
  select(starts_with("CON") & ends_with("FU3")) %>% 
  rowMeans(na.rm = T)

#harm avoidance items
mpq$HA_IN <- mpq %>% 
  select(starts_with("HA") & ends_with("IN")) %>% 
  rowMeans(na.rm = T)
mpq$HA_FU1 <- mpq %>% 
  select(starts_with("HA") & ends_with("FU1")) %>% 
  rowMeans(na.rm = T)
mpq$HA_FU2 <- mpq %>% 
  select(starts_with("HA") & ends_with("FU2")) %>% 
  rowMeans(na.rm = T)
mpq$HA_FU3 <- mpq %>% 
  select(starts_with("HA") & ends_with("FU3")) %>% 
  rowMeans(na.rm = T)

#clean up NaN
mpq$AG_IN[is.nan(mpq$AG_IN)]<-NA
mpq$AG_FU1[is.nan(mpq$AG_FU1)]<-NA
mpq$AG_FU2[is.nan(mpq$AG_FU2)]<-NA
mpq$AG_FU3[is.nan(mpq$AG_FU3)]<-NA
mpq$CON_IN[is.nan(mpq$CON_IN)]<-NA
mpq$CON_FU1[is.nan(mpq$CON_FU1)]<-NA
mpq$CON_FU2[is.nan(mpq$CON_FU2)]<-NA
mpq$CON_FU3[is.nan(mpq$CON_FU3)]<-NA
mpq$HA_IN[is.nan(mpq$HA_IN)]<-NA
mpq$HA_FU1[is.nan(mpq$HA_FU1)]<-NA
mpq$HA_FU2[is.nan(mpq$HA_FU2)]<-NA
mpq$HA_FU3[is.nan(mpq$HA_FU3)]<-NA

# participants with relationship data at FU1 but not IN
FU1_ID <- rel_FU1[which(!rel_FU1$ID %in% rel_IN$ID), "ID"]
rel_FU1 <- rel_FU1 %>%
  filter(ID %in% FU1_ID)

# merge relationship data (IN for all, FU1 for those without IN data)
mpq_IN <- mpq %>% filter(!ID %in% FU1_ID)
mpq_FU1 <- mpq %>% filter(ID %in% FU1_ID)
mpq_IN <- merge(mpq_IN, rel_IN, all.x = TRUE)
mpq_FU1 <- merge(mpq_FU1, rel_FU1, all.x = TRUE)
mpq <- rbind(mpq_IN, mpq_FU1)

# merge life events data
mpq <- merge(mpq, lei, all.x = TRUE)

# reverse code some relationship items (into new items _R)
#mpq <- mpq %>%
#  mutate(S_ENURY_R = 6 - S_ENURY,
#         S_YADME_R = 6 - S_YADME,
#         S_EADMY_R = 6 - S_EADMY,
#         S_EDOMY_R = 6 - S_EDOMY,
#         S_AFFECT_R = 6 - S_AFFECT)

#create wide dyad dataframe
mpq <- mpq[order(mpq$ID),]
mpq$P <- rep(c(1:2), length.out = nrow(mpq)) #person dummy var
yo <- mpq %>% select(IDYRFAM, BDAY, P) %>% 
  mutate(BDAY = as.character(BDAY),
         P = as.character(P))

#wide data with 2 siblings per row
yo <- reshape2::dcast(yo, IDYRFAM ~ P, value.var = "BDAY") 
yo <- yo %>% mutate(`1` = as.Date(`1`),
                    `2` = as.Date(`2`))
yo <- yo %>% mutate(older = ifelse(`1`<`2`, "P1", "P2")) %>% 
  select(IDYRFAM, older)
mpq <- merge(mpq, yo)

#y = younger, o = older
mpq <- mpq %>% 
  mutate(yo = ifelse(P == 1 & older == "P2" | 
                     P == 2 & older == "P1", "y", "o")) %>%  
  select(-P, -older)

#data with only younger sib
young <- mpq %>%      
  filter(yo == "y")
names(young) <- paste0(names(young), "_y", sep = "")
young <- young %>% rename(IDYRFAM = IDYRFAM_y)

#data with only older sib
old <- mpq %>%        
  filter(yo == "o")
names(old) <- paste0(names(old), "_o", sep = "")
old <- old %>% rename(IDYRFAM = IDYRFAM_o)

yo <- merge(young, old)
rm(young, old)

Demographics

#descriptives
mpq %>% 
  select(IDSEX:FU3_AGE) %>% 
  descr(stats = "common", order = "p")

Descriptive Statistics
mpq
N: 1231

IDSEX IDAB IDFAMAB IDSC IN_AGE FU1_AGE FU2_AGE FU3_AGE
Mean 1.55 1.44 1.74 3.12 14.92 18.05 20.10 31.92
Std.Dev 0.50 0.50 0.77 2.26 1.93 1.98 1.08 2.71
Min 1.00 1.00 1.00 0.00 10.73 13.67 18.95 25.66
Median 2.00 1.00 2.00 3.00 14.98 18.05 19.97 31.76
Max 2.00 2.00 3.00 7.00 20.98 25.34 23.09 40.53
N.Valid 1231.00 1231.00 1231.00 1231.00 1221.00 1065.00 132.00 769.00
Pct.Valid 100.00 100.00 100.00 100.00 99.19 86.52 10.72 62.47
# graphs: continuous
ggplot(data = yo, aes(IN_AGE_y)) +
  geom_histogram(binwidth = 0.2, fill = "#710c0c") + 
  geom_vline(xintercept = mean(yo$IN_AGE_y, na.rm = T),
             color = "#f1c232", size = 1) +
  annotate("text", 
           label = paste0("Mean = ", round(mean(yo$IN_AGE_y, na.rm = T), 2),
                          ", SD = ",round(sd(yo$IN_AGE_y, na.rm = T), 2)),
           x = 17, y = 25) + 
  labs(
    title = "Distribution of younger sibling's age at intake",
    x = "Age (in years)",
    y = NULL
  ) +
  theme_classic()

ggplot(data = yo, aes(IN_AGE_o)) +
  geom_histogram(binwidth = 0.2, fill = "#710c0c") + 
  geom_vline(xintercept = mean(yo$IN_AGE_o, na.rm = T),
             color = "#f1c232", size = 1) +
  annotate("text", 
           label = paste0("Mean = ", round(mean(yo$IN_AGE_o, na.rm = T), 2),
                          ", SD = ",round(sd(yo$IN_AGE_o, na.rm = T), 2)),
           x = 18, y = 35) + 
  labs(
    title = "Distribution of older sibling's age at intake",
    x = "Age (in years)",
    y = NULL
  ) +
  theme_classic()

# graphs: discrete
ggplot(mpq, 
       aes(factor(mpq$IDAB,
                  levels = c(1, 2),
                  labels = c("Adoptive", "Non-Adoptive")))) + 
  geom_bar(fill = c("#710c0c", "#f1c232")) + 
  geom_text(stat='count', aes(label=..count..), vjust = -1) + 
  labs(
    title = "Count of adoption status",
    x = NULL
  ) +
  ylim(0, 700) +
  theme_classic()

ggplot(mpq, 
       aes(factor(mpq$IDSEX,
                  levels = c(1, 2),
                  labels = c("Male", "Female")))) + 
  geom_bar(fill = c("#f1c232", "#710c0c")) + 
  geom_text(stat='count', aes(label=..count..), vjust = -1) + 
  labs(
    title = "Count of sex",
    x = NULL
  ) +
  ylim(0, 700) +
  theme_classic()

The average time between assessments is:

  • Between intake and follow-up 1: 3.306 years.
  • Between follow-up 1 and follow-up 2: 4.283 years.
  • Between follow-up 3 and follow-up 2: 9.393 years.

Scale scores

#descriptives
mpq %>% select(AG_IN:HA_FU3) %>% descr(stats = "common", order = "p")

Descriptive Statistics
mpq
N: 1231

Table continues below
AG_IN AG_FU1 AG_FU2 AG_FU3 CON_IN CON_FU1 CON_FU2 CON_FU3
Mean 2.16 2.06 1.89 1.71 2.58 2.63 2.79 2.98
Std.Dev 0.58 0.56 0.49 0.44 0.47 0.48 0.47 0.45
Min 1.00 1.00 1.00 1.00 1.17 1.07 1.67 1.25
Median 2.11 2.00 1.89 1.67 2.61 2.67 2.83 3.00
Max 4.00 4.00 3.22 3.75 4.00 3.94 3.83 4.00
N.Valid 1221.00 1061.00 132.00 748.00 1221.00 1061.00 132.00 748.00
Pct.Valid 99.19 86.19 10.72 60.76 99.19 86.19 10.72 60.76
HA_IN HA_FU1 HA_FU2 HA_FU3
Mean 2.66 2.60 2.63 3.03
Std.Dev 0.60 0.60 0.66 0.57
Min 1.00 1.00 1.11 1.33
Median 2.69 2.61 2.75 3.08
Max 4.00 4.00 3.94 4.00
N.Valid 1221.00 1061.00 132.00 748.00
Pct.Valid 99.19 86.19 10.72 60.76
#random sample for plots
sample = sample(mpq$ID, size = 100)
sample <- mpq %>% filter(ID %in% c(sample))
sample <- reshape(sample, direction = "long",
                varying = list(c("IN_AGE", "FU1_AGE", "FU2_AGE", "FU3_AGE"),
                               c("AG_IN", "AG_FU1", "AG_FU2", "AG_FU3"),
                               c("CON_IN", "CON_FU1", "CON_FU2", "CON_FU3"),
                               c("HA_IN", "HA_FU1", "HA_FU2", "HA_FU3")),
                timevar = "time",
                times = c(0,1,2,3),
                v.names = c("age","AG","CON","HA"),
                idvar = c("ID"))
row.names(sample) <- 1:nrow(sample)

#plot by timepoints
pAG <- ggplot(data = sample,
               aes(x = time, y = AG, group = ID)) + 
    geom_line (linetype = "dashed")+ 
    geom_point(size = 0.5) +
    theme_bw () +
    stat_summary(aes(data=sample$AG,group=1),fun=mean,geom="line",lwd = 1.5, color= "red")
pCON <- ggplot(data = sample,
                aes(x = time, y = CON, group = ID)) + 
    geom_line (linetype = "dashed")+ 
    geom_point(size = 0.5) +
    theme_bw () +
    stat_summary(aes(data=sample$CON,group=1),fun=mean,geom="line",lwd = 1.5, color= "red")
pHA <- ggplot(data = sample,
               aes(x = time, y = HA, group = ID)) + 
    geom_line (linetype = "dashed")+ 
    geom_point(size = 0.5) +
    theme_bw () +
    stat_summary(aes(data=sample$HA,group=1),fun=mean,geom="line",lwd = 1.5, color= "red")

#plot by age
paAG <- ggplot(data = sample,
               aes(x = age, y = AG, group = ID)) + 
    geom_line (linetype = "dashed")+ 
    geom_point(size = 0.25) + 
    theme_bw () +
    stat_smooth(aes(data=sample$AG,group=1),method="lm",formula=y ~ poly(x, 2),lwd = 1.5, color= "red")
paCON <- ggplot(data = sample,
                aes(x = age, y = CON, group = ID)) + 
    geom_line (linetype = "dashed")+ 
    geom_point(size = 0.25) +
    theme_bw () +
    stat_smooth(aes(data=sample$CON,group=1),method="lm",formula=y ~ poly(x, 2),lwd = 1.5, color= "red")
paHA <- ggplot(data = sample,
               aes(x = age, y = HA, group = ID)) + 
    geom_line (linetype = "dashed")+ 
    geom_point(size = 0.25) +
    theme_bw () +
    stat_smooth(aes(data=sample$HA,group=1),method="lm",formula=y ~ poly(x, 2),lwd = 1.5, color= "red")
  
cowplot::plot_grid(pAG, paAG,
                   pCON, paCON, 
                   pHA, paHA,
                   nrow = 3, ncol = 2)

rm(sample, pAG, paAG, pCON, paCON, pHA, paHA)

There are 1221 participants with complete responses at intake, 1061 at follow-up 1, 132 at follow-up 2, and 748 at follow-up 3.

There are 615 families with at least 1 sibling at intake, 569 at follow-up 1, 123 at follow-up 2, and 495 at follow-up 3.

There are 606 families with both siblings at intake, 492 at follow-up 1, 9 at follow-up 2, and 253 at follow-up 3.

III. Analyses with 3 waves

These analyses do NOT use data points at wave 3 (FU2) due to very high and non-random missingness of the study design. The supplementary analyses (section IV.) includes these data points for robustness checks. Missingness was too severe such that when grouping variables (e.g., adoption status) were added, some variables only have one observations across older siblings and as a result the models could not run.

Random parcel sampling

par <- c(1:18)
par1 <- sample(par, size = 6) #parcel 1
par2 <- sample(par[which(!par %in% par1)], size = 6) #parcel 2
par3 <- par[which(!par %in% par1 & !par %in% par2)] #parcel 3

# aggression AG 
yo <- yo %>% 
  mutate(# older sibling
         AG_IN_o_p1 = rowMeans(select(yo, AG12_IN_o, AG18_IN_o, AG4_IN_o, AG15_IN_o, AG6_IN_o, AG2_IN_o), na.rm = T),
         AG_IN_o_p2 = rowMeans(select(yo, AG10_IN_o, AG17_IN_o, AG7_IN_o, AG13_IN_o, AG1_IN_o, AG3_IN_o), na.rm = T),
         AG_IN_o_p3 = rowMeans(select(yo, AG5_IN_o, AG8_IN_o, AG9_IN_o, AG11_IN_o, AG14_IN_o, AG16_IN_o), na.rm = T),
         
         AG_FU1_o_p1 = rowMeans(select(yo, AG12_FU1_o, AG18_FU1_o, AG4_FU1_o, AG15_FU1_o, AG6_FU1_o, AG2_FU1_o), na.rm = T),
         AG_FU1_o_p2 = rowMeans(select(yo, AG10_FU1_o, AG17_FU1_o, AG7_FU1_o, AG13_FU1_o, AG1_FU1_o, AG3_FU1_o), na.rm = T),
         AG_FU1_o_p3 = rowMeans(select(yo, AG5_FU1_o, AG8_FU1_o, AG9_FU1_o, AG11_FU1_o, AG14_FU1_o, AG16_FU1_o), na.rm = T),
         
         AG_FU2_o_p1 = rowMeans(select(yo, AG12_FU2_o, AG18_FU2_o, AG4_FU2_o, AG15_FU2_o, AG6_FU2_o, AG2_FU2_o), na.rm = T),
         AG_FU2_o_p2 = rowMeans(select(yo, AG10_FU2_o, AG17_FU2_o, AG7_FU2_o, AG13_FU2_o, AG1_FU2_o, AG3_FU2_o), na.rm = T),
         AG_FU2_o_p3 = rowMeans(select(yo, AG5_FU2_o, AG8_FU2_o, AG9_FU2_o, AG11_FU2_o, AG14_FU2_o, AG16_FU2_o), na.rm = T),
         
         AG_FU3_o_p1 = rowMeans(select(yo, AG12_FU3_o, AG18_FU3_o, AG4_FU3_o, AG6_FU3_o, AG2_FU3_o), na.rm = T),
         AG_FU3_o_p2 = rowMeans(select(yo, AG10_FU3_o, AG7_FU3_o), na.rm = T),
         AG_FU3_o_p3 = rowMeans(select(yo, AG5_FU3_o, AG8_FU3_o, AG11_FU3_o, AG14_FU3_o, AG16_FU3_o), na.rm = T),
         
         # younger sibling
         AG_IN_y_p1 = rowMeans(select(yo, AG12_IN_y, AG18_IN_y, AG4_IN_y, AG15_IN_y, AG6_IN_y, AG2_IN_y), na.rm = T),
         AG_IN_y_p2 = rowMeans(select(yo, AG10_IN_y, AG17_IN_y, AG7_IN_y, AG13_IN_y, AG1_IN_y, AG3_IN_y), na.rm = T),
         AG_IN_y_p3 = rowMeans(select(yo, AG5_IN_y, AG8_IN_y, AG9_IN_y, AG11_IN_y, AG14_IN_y, AG16_IN_y), na.rm = T),
         
         AG_FU1_y_p1 = rowMeans(select(yo, AG12_FU1_y, AG18_FU1_y, AG4_FU1_y, AG15_FU1_y, AG6_FU1_y, AG2_FU1_y), na.rm = T),
         AG_FU1_y_p2 = rowMeans(select(yo, AG10_FU1_y, AG17_FU1_y, AG7_FU1_y, AG13_FU1_y, AG1_FU1_y, AG3_FU1_y), na.rm = T),
         AG_FU1_y_p3 = rowMeans(select(yo, AG5_FU1_y, AG8_FU1_y, AG9_FU1_y, AG11_FU1_y, AG14_FU1_y, AG16_FU1_y), na.rm = T),
         
         AG_FU2_y_p1 = rowMeans(select(yo, AG12_FU2_y, AG18_FU2_y, AG4_FU2_y, AG15_FU2_y, AG6_FU2_y, AG2_FU2_y), na.rm = T),
         AG_FU2_y_p2 = rowMeans(select(yo, AG10_FU2_y, AG17_FU2_y, AG7_FU2_y, AG13_FU2_y, AG1_FU2_y, AG3_FU2_y), na.rm = T),
         AG_FU2_y_p3 = rowMeans(select(yo, AG5_FU2_y, AG8_FU2_y, AG9_FU2_y, AG11_FU2_y, AG14_FU2_y, AG16_FU2_y), na.rm = T),
         
         AG_FU3_y_p1 = rowMeans(select(yo, AG12_FU3_y, AG18_FU3_y, AG4_FU3_y, AG6_FU3_y, AG2_FU3_y), na.rm = T),
         AG_FU3_y_p2 = rowMeans(select(yo, AG10_FU3_y, AG7_FU3_y), na.rm = T),
         AG_FU3_y_p3 = rowMeans(select(yo, AG5_FU3_y, AG8_FU3_y, AG11_FU3_y, AG14_FU3_y, AG16_FU3_y), na.rm = T))

# control CON 
yo <- yo %>% 
  mutate(# older sibling
         CON_IN_o_p1 = rowMeans(select(yo, CON12_IN_o, CON18_IN_o, CON4_IN_o, CON15_IN_o, CON6_IN_o, CON2_IN_o), na.rm = T),
         CON_IN_o_p2 = rowMeans(select(yo, CON10_IN_o, CON17_IN_o, CON7_IN_o, CON13_IN_o, CON1_IN_o, CON3_IN_o), na.rm = T),
         CON_IN_o_p3 = rowMeans(select(yo, CON5_IN_o, CON8_IN_o, CON9_IN_o, CON11_IN_o, CON14_IN_o, CON16_IN_o), na.rm = T),
         
         CON_FU1_o_p1 = rowMeans(select(yo, CON12_FU1_o, CON18_FU1_o, CON4_FU1_o, CON15_FU1_o, CON6_FU1_o, CON2_FU1_o), na.rm = T),
         CON_FU1_o_p2 = rowMeans(select(yo, CON10_FU1_o, CON17_FU1_o, CON7_FU1_o, CON13_FU1_o, CON1_FU1_o, CON3_FU1_o), na.rm = T),
         CON_FU1_o_p3 = rowMeans(select(yo, CON5_FU1_o, CON8_FU1_o, CON9_FU1_o, CON11_FU1_o, CON14_FU1_o, CON16_FU1_o), na.rm = T),
         
         CON_FU2_o_p1 = rowMeans(select(yo, CON12_FU2_o, CON18_FU2_o, CON4_FU2_o, CON15_FU2_o, CON6_FU2_o, CON2_FU2_o), na.rm = T),
         CON_FU2_o_p2 = rowMeans(select(yo, CON10_FU2_o, CON17_FU2_o, CON7_FU2_o, CON13_FU2_o, CON1_FU2_o, CON3_FU2_o), na.rm = T),
         CON_FU2_o_p3 = rowMeans(select(yo, CON5_FU2_o, CON8_FU2_o, CON9_FU2_o, CON11_FU2_o, CON14_FU2_o, CON16_FU2_o), na.rm = T),
         
         CON_FU3_o_p1 = rowMeans(select(yo, CON4_FU3_o, CON15_FU3_o, CON6_FU3_o, CON2_FU3_o), na.rm = T),
         CON_FU3_o_p2 = rowMeans(select(yo, CON10_FU3_o, CON17_FU3_o, CON7_FU3_o), na.rm = T),
         CON_FU3_o_p3 = rowMeans(select(yo, CON5_FU3_o, CON8_FU3_o, CON9_FU3_o, CON16_FU3_o), na.rm = T),
         
         # younger sibling
         CON_IN_y_p1 = rowMeans(select(yo, CON12_IN_y, CON18_IN_y, CON4_IN_y, CON15_IN_y, CON6_IN_y, CON2_IN_y), na.rm = T),
         CON_IN_y_p2 = rowMeans(select(yo, CON10_IN_y, CON17_IN_y, CON7_IN_y, CON13_IN_y, CON1_IN_y, CON3_IN_y), na.rm = T),
         CON_IN_y_p3 = rowMeans(select(yo, CON5_IN_y, CON8_IN_y, CON9_IN_y, CON11_IN_y, CON14_IN_y, CON16_IN_y), na.rm = T),
         
         CON_FU1_y_p1 = rowMeans(select(yo, CON12_FU1_y, CON18_FU1_y, CON4_FU1_y, CON15_FU1_y, CON6_FU1_y, CON2_FU1_y), na.rm = T),
         CON_FU1_y_p2 = rowMeans(select(yo, CON10_FU1_y, CON17_FU1_y, CON7_FU1_y, CON13_FU1_y, CON1_FU1_y, CON3_FU1_y), na.rm = T),
         CON_FU1_y_p3 = rowMeans(select(yo, CON5_FU1_y, CON8_FU1_y, CON9_FU1_y, CON11_FU1_y, CON14_FU1_y, CON16_FU1_y), na.rm = T),
         
         CON_FU2_y_p1 = rowMeans(select(yo, CON12_FU2_y, CON18_FU2_y, CON4_FU2_y, CON15_FU2_y, CON6_FU2_y, CON2_FU2_y), na.rm = T),
         CON_FU2_y_p2 = rowMeans(select(yo, CON10_FU2_y, CON17_FU2_y, CON7_FU2_y, CON13_FU2_y, CON1_FU2_y, CON3_FU2_y), na.rm = T),
         CON_FU2_y_p3 = rowMeans(select(yo, CON5_FU2_y, CON8_FU2_y, CON9_FU2_y, CON11_FU2_y, CON14_FU2_y, CON16_FU2_y), na.rm = T),
         
         CON_FU3_y_p1 = rowMeans(select(yo, CON4_FU3_y, CON15_FU3_y, CON6_FU3_y, CON2_FU3_y), na.rm = T),
         CON_FU3_y_p2 = rowMeans(select(yo, CON10_FU3_y, CON17_FU3_y, CON7_FU3_y), na.rm = T),
         CON_FU3_y_p3 = rowMeans(select(yo, CON5_FU3_y, CON8_FU3_y, CON9_FU3_y, CON16_FU3_y), na.rm = T))

# harm avoidance HA
yo <- yo %>% 
    mutate(# older sibling
         HA_IN_o_p1 = rowMeans(select(yo, HA12_IN_o, HA18_IN_o, HA4_IN_o, HA15_IN_o, HA6_IN_o, HA2_IN_o), na.rm = T),
         HA_IN_o_p2 = rowMeans(select(yo, HA10_IN_o, HA17_IN_o, HA7_IN_o, HA13_IN_o, HA1_IN_o, HA3_IN_o), na.rm = T),
         HA_IN_o_p3 = rowMeans(select(yo, HA5_IN_o, HA8_IN_o, HA9_IN_o, HA11_IN_o, HA14_IN_o, HA16_IN_o), na.rm = T),
         
         HA_FU1_o_p1 = rowMeans(select(yo, HA12_FU1_o, HA18_FU1_o, HA4_FU1_o, HA15_FU1_o, HA6_FU1_o, HA2_FU1_o), na.rm = T),
         HA_FU1_o_p2 = rowMeans(select(yo, HA10_FU1_o, HA17_FU1_o, HA7_FU1_o, HA13_FU1_o, HA1_FU1_o, HA3_FU1_o), na.rm = T),
         HA_FU1_o_p3 = rowMeans(select(yo, HA5_FU1_o, HA8_FU1_o, HA9_FU1_o, HA11_FU1_o, HA14_FU1_o, HA16_FU1_o), na.rm = T),
         
         HA_FU2_o_p1 = rowMeans(select(yo, HA12_FU2_o, HA18_FU2_o, HA4_FU2_o, HA15_FU2_o, HA6_FU2_o, HA2_FU2_o), na.rm = T),
         HA_FU2_o_p2 = rowMeans(select(yo, HA10_FU2_o, HA17_FU2_o, HA7_FU2_o, HA13_FU2_o, HA1_FU2_o, HA3_FU2_o), na.rm = T),
         HA_FU2_o_p3 = rowMeans(select(yo, HA5_FU2_o, HA8_FU2_o, HA9_FU2_o, HA11_FU2_o, HA14_FU2_o, HA16_FU2_o), na.rm = T),
         
         HA_FU3_o_p1 = rowMeans(select(yo, HA18_FU3_o, HA4_FU3_o, HA6_FU3_o, HA2_FU3_o), na.rm = T),
         HA_FU3_o_p2 = rowMeans(select(yo, HA10_FU3_o, HA7_FU3_o, HA13_FU3_o, HA1_FU3_o, HA3_FU3_o), na.rm = T),
         HA_FU3_o_p3 = rowMeans(select(yo, HA8_FU3_o, HA9_FU3_o, HA16_FU3_o), na.rm = T),
         
         # younger sibling
         HA_IN_y_p1 = rowMeans(select(yo, HA12_IN_y, HA18_IN_y, HA4_IN_y, HA15_IN_y, HA6_IN_y, HA2_IN_y), na.rm = T),
         HA_IN_y_p2 = rowMeans(select(yo, HA10_IN_y, HA17_IN_y, HA7_IN_y, HA13_IN_y, HA1_IN_y, HA3_IN_y), na.rm = T),
         HA_IN_y_p3 = rowMeans(select(yo, HA5_IN_y, HA8_IN_y, HA9_IN_y, HA11_IN_y, HA14_IN_y, HA16_IN_y), na.rm = T),
         
         HA_FU1_y_p1 = rowMeans(select(yo, HA12_FU1_y, HA18_FU1_y, HA4_FU1_y, HA15_FU1_y, HA6_FU1_y, HA2_FU1_y), na.rm = T),
         HA_FU1_y_p2 = rowMeans(select(yo, HA10_FU1_y, HA17_FU1_y, HA7_FU1_y, HA13_FU1_y, HA1_FU1_y, HA3_FU1_y), na.rm = T),
         HA_FU1_y_p3 = rowMeans(select(yo, HA5_FU1_y, HA8_FU1_y, HA9_FU1_y, HA11_FU1_y, HA14_FU1_y, HA16_FU1_y), na.rm = T),
         
         HA_FU2_y_p1 = rowMeans(select(yo, HA12_FU2_y, HA18_FU2_y, HA4_FU2_y, HA15_FU2_y, HA6_FU2_y, HA2_FU2_y), na.rm = T),
         HA_FU2_y_p2 = rowMeans(select(yo, HA10_FU2_y, HA17_FU2_y, HA7_FU2_y, HA13_FU2_y, HA1_FU2_y, HA3_FU2_y), na.rm = T),
         HA_FU2_y_p3 = rowMeans(select(yo, HA5_FU2_y, HA8_FU2_y, HA9_FU2_y, HA11_FU2_y, HA14_FU2_y, HA16_FU2_y), na.rm = T),
         
         HA_FU3_y_p1 = rowMeans(select(yo, HA18_FU3_y, HA4_FU3_y, HA6_FU3_y, HA2_FU3_y), na.rm = T),
         HA_FU3_y_p2 = rowMeans(select(yo, HA10_FU3_y, HA7_FU3_y, HA13_FU3_y, HA1_FU3_y, HA3_FU3_y), na.rm = T),
         HA_FU3_y_p3 = rowMeans(select(yo, HA8_FU3_y, HA9_FU3_y, HA16_FU3_y), na.rm = T))

  
# clean up NaN
for (row in seq(nrow(yo))) {
  for (col in seq(ncol(yo))) {
    if (is.nan(yo[row, col])) {
      yo[row, col] <- NA
    }}} # END for row/col LOOP

For SEM analyses of each personality variable, the three parcels were randomized to contain items numbered:

  • Parcel 1: 2, 4, 6, 7, 14, 15
  • Parcel 2: 3, 8, 9, 12, 13, 17
  • Parcel 3: 1, 5, 10, 11, 16, 18

General change trajectories and correlated change

Aggression AG

lgmAG <- '
#younger sibling
AG0y =~   AG_IN_y_p1  + p2 * AG_IN_y_p2   + p3 * AG_IN_y_p3
AG3y =~   AG_FU1_y_p1 + p2 * AG_FU1_y_p2  + p3 * AG_FU1_y_p3
AG17y =~  AG_FU3_y_p1 + p2 * AG_FU3_y_p2  + p3 * AG_FU3_y_p3
                   
#older sibling
AG0o =~   AG_IN_o_p1  + p2 * AG_IN_o_p2   + p3 * AG_IN_o_p3
AG3o =~   AG_FU1_o_p1 + p2 * AG_FU1_o_p2  + p3 * AG_FU1_o_p3
AG17o =~  AG_FU3_o_p1 + p2 * AG_FU3_o_p2  + p3 * AG_FU3_o_p3

#latent intercept and slopes
iy =~ 1*AG0y + 1*AG3y + 1*AG17y
io =~ 1*AG0o + 1*AG3o + 1*AG17o
sy =~ 0*AG0y + 3.3*AG3y + 17*AG17y
so =~ 0*AG0o + 3.3*AG3o + 17*AG17o
iy ~ 1
io ~ 1
sy ~ 1
so ~ 1

#fix zero latent intercepts
AG0y ~ 0*1
AG3y ~ 0*1
AG17y ~ 0*1
AG0o ~ 0*1
AG3o ~ 0*1
AG17o ~ 0*1

#fix zero/equal item intercepts
AG_IN_y_p1  ~ 0*1
AG_FU1_y_p1 ~ 0*1
AG_FU3_y_p1 ~ 0*1
AG_IN_o_p1  ~ 0*1
AG_FU1_o_p1 ~ 0*1
AG_FU3_o_p1 ~ 0*1

AG_IN_y_p2  ~ par2*1
AG_FU1_y_p2 ~ par2*1
AG_FU3_y_p2 ~ par2*1
AG_IN_o_p2  ~ par2*1
AG_FU1_o_p2 ~ par2*1
AG_FU3_o_p2 ~ par2*1

AG_IN_y_p3  ~ par3*1
AG_FU1_y_p3 ~ par3*1
AG_FU3_y_p3 ~ par3*1
AG_IN_o_p3  ~ par3*1
AG_FU1_o_p3 ~ par3*1
AG_FU3_o_p3 ~ par3*1

#residual covariances
AG_IN_y_p1 ~~ c(cov11)*AG_FU1_y_p1 + c(cov13)*AG_FU3_y_p1 
AG_FU1_y_p1 ~~ c(cov12)*AG_FU3_y_p1 

AG_IN_y_p2 ~~ c(cov21)*AG_FU1_y_p2 + c(cov23)*AG_FU3_y_p2 
AG_FU1_y_p2 ~~ c(cov22)*AG_FU3_y_p2 

AG_IN_y_p3 ~~ c(cov31)*AG_FU1_y_p3 + c(cov33)*AG_FU3_y_p3 
AG_FU1_y_p3 ~~ c(cov32)*AG_FU3_y_p3 

AG_IN_o_p1 ~~ c(cov11)*AG_FU1_o_p1 + c(cov13)*AG_FU3_o_p1 
AG_FU1_o_p1 ~~ c(cov12)*AG_FU3_o_p1 

AG_IN_o_p2 ~~ c(cov21)*AG_FU1_o_p2 + c(cov23)*AG_FU3_o_p2 
AG_FU1_o_p2 ~~ c(cov22)*AG_FU3_o_p2 

AG_IN_o_p3 ~~ c(cov31)*AG_FU1_o_p3 + c(cov33)*AG_FU3_o_p3 
AG_FU1_o_p3 ~~ c(cov32)*AG_FU3_o_p3 
'
#ad_sibAG <- sem(sibAG, data = yo[which(yo$adopt == 1),], missing = "FIML")
#summary(ad_sibAG, fit.measures = T, standardized = T)

#bio_sibAG <- sem(sibAG, data = yo[which(yo$adopt == 0),], missing = "FIML")
#summary(bio_sibAG, fit.measures = T, standardized = T)

#g_sibAG <- sem(sibAG, data = yo, missing = "FIML", group = "adopt", em.iter.max = 20000)
#summary(g_sibAG, fit.measures = T, standardized = T, ci = T)

sibAG <- sem(lgmAG, data = yo, missing = "FIML")

fitMeasures(sibAG, c("chisq", "df", "pvalue", "cfi", "rmsea", "srmr"), 
            output = "text")
## 
## Model Test User Model:
## 
##   Test statistic                               272.327
##   Degrees of freedom                               138
##   P-value                                        0.000
## 
## User Model versus Baseline Model:
## 
##   Comparative Fit Index (CFI)                    0.979
## 
## Root Mean Square Error of Approximation:
## 
##   RMSEA                                          0.040
## 
## Standardized Root Mean Square Residual:
## 
##   SRMR                                           0.052
as.data.frame(unclass(standardizedSolution(sibAG))) %>% 
  filter(op == "~1" & lhs %in% c("iy", "io", "sy", "so")) %>% 
  select("Parameters" = lhs, Beta = est.std, SE = se, Z = z, "p-value" = pvalue, "CI lower" = ci.lower, "CI upper" = ci.upper) %>% 
  knitr::kable(caption = "Intercept and Slope", digits = 6) %>% 
  kable_styling() %>% 
  footnote(general = "i = intercept, s = slope, o = older sibling, y = younger sibling")
Intercept and Slope
Parameters Beta SE Z p-value CI lower CI upper
iy 4.063 0.180 22.56 0e+00 3.71 4.416
io 3.876 0.165 23.54 0e+00 3.55 4.199
sy -1.080 0.238 -4.53 6e-06 -1.55 -0.613
so -0.831 0.141 -5.90 0e+00 -1.11 -0.555
Note:
i = intercept, s = slope, o = older sibling, y = younger sibling
as.data.frame(unclass(standardizedSolution(sibAG))) %>% 
  filter(op == "~~" & lhs %in% c("sy", "iy") & rhs %in% c("so", "io")) %>% 
  select("Younger sibling" = lhs, "Older sibling" = rhs, Beta = est.std, SE = se, Z = z, "p-value" = pvalue, "CI lower" = ci.lower, "CI upper" = ci.upper) %>% 
  knitr::kable(caption = "Correlated intercepts and slopes", digits = 6) %>% 
  kable_styling() %>% 
  footnote(general = "i = intercept, s = slope, o = older sibling, y = younger sibling")
Correlated intercepts and slopes
Younger sibling Older sibling Beta SE Z p-value CI lower CI upper
iy io 0.311 0.0518 6.02 0.000000 0.2099 0.413
iy so -0.251 0.0733 -3.42 0.000616 -0.3949 -0.107
sy so 0.229 0.1010 2.27 0.023180 0.0314 0.427
Note:
i = intercept, s = slope, o = older sibling, y = younger sibling
semPaths(sibAG, what = "col", whatLabels = "est", intercepts = T)

Control CON

lgmCON <- '
#younger sibling
CON0y =~   CON_IN_y_p1  + p2 * CON_IN_y_p2   + p3 * CON_IN_y_p3
CON3y =~   CON_FU1_y_p1 + p2 * CON_FU1_y_p2  + p3 * CON_FU1_y_p3
CON17y =~  CON_FU3_y_p1 + p2 * CON_FU3_y_p2  + p3 * CON_FU3_y_p3
                   
#older sibling
CON0o =~   CON_IN_o_p1  + p2 * CON_IN_o_p2   + p3 * CON_IN_o_p3
CON3o =~   CON_FU1_o_p1 + p2 * CON_FU1_o_p2  + p3 * CON_FU1_o_p3
CON17o =~  CON_FU3_o_p1 + p2 * CON_FU3_o_p2  + p3 * CON_FU3_o_p3

#latent intercept and slopes
iy =~ 1*CON0y + 1*CON3y + 1*CON17y
io =~ 1*CON0o + 1*CON3o + 1*CON17o
sy =~ 0*CON0y + 3.3*CON3y + 17*CON17y
so =~ 0*CON0o + 3.3*CON3o + 17*CON17o
iy ~ 1
io ~ 1
sy ~ 1
so ~ 1

#fix zero latent intercepts
CON0y ~ 0*1
CON3y ~ 0*1
CON17y ~ 0*1
CON0o ~ 0*1
CON3o ~ 0*1
CON17o ~ 0*1

#fix zero/equal item intercepts
CON_IN_y_p1  ~ 0*1
CON_FU1_y_p1 ~ 0*1
CON_FU3_y_p1 ~ 0*1
CON_IN_o_p1  ~ 0*1
CON_FU1_o_p1 ~ 0*1
CON_FU3_o_p1 ~ 0*1

CON_IN_y_p2  ~ par2*1
CON_FU1_y_p2 ~ par2*1
CON_FU3_y_p2 ~ par2*1
CON_IN_o_p2  ~ par2*1
CON_FU1_o_p2 ~ par2*1
CON_FU3_o_p2 ~ par2*1

CON_IN_y_p3  ~ par3*1
CON_FU1_y_p3 ~ par3*1
CON_FU3_y_p3 ~ par3*1
CON_IN_o_p3  ~ par3*1
CON_FU1_o_p3 ~ par3*1
CON_FU3_o_p3 ~ par3*1

#residual covariances
CON_IN_y_p1 ~~ c(cov11)*CON_FU1_y_p1 + c(cov13)*CON_FU3_y_p1 
CON_FU1_y_p1 ~~ c(cov12)*CON_FU3_y_p1 

CON_IN_y_p2 ~~ c(cov21)*CON_FU1_y_p2 + c(cov23)*CON_FU3_y_p2 
CON_FU1_y_p2 ~~ c(cov22)*CON_FU3_y_p2 

CON_IN_y_p3 ~~ c(cov31)*CON_FU1_y_p3 + c(cov33)*CON_FU3_y_p3 
CON_FU1_y_p3 ~~ c(cov32)*CON_FU3_y_p3 

CON_IN_o_p1 ~~ c(cov11)*CON_FU1_o_p1 + c(cov13)*CON_FU3_o_p1 
CON_FU1_o_p1 ~~ c(cov12)*CON_FU3_o_p1 

CON_IN_o_p2 ~~ c(cov21)*CON_FU1_o_p2 + c(cov23)*CON_FU3_o_p2 
CON_FU1_o_p2 ~~ c(cov22)*CON_FU3_o_p2 

CON_IN_o_p3 ~~ c(cov31)*CON_FU1_o_p3 + c(cov33)*CON_FU3_o_p3 
CON_FU1_o_p3 ~~ c(cov32)*CON_FU3_o_p3 
'

sibCON <- sem(lgmCON, data = yo, missing = "FIML")

fitMeasures(sibCON, c("chisq", "df", "pvalue", "cfi", "rmsea", "srmr"), 
            output = "text")
## 
## Model Test User Model:
## 
##   Test statistic                               265.283
##   Degrees of freedom                               138
##   P-value                                        0.000
## 
## User Model versus Baseline Model:
## 
##   Comparative Fit Index (CFI)                    0.975
## 
## Root Mean Square Error of Approximation:
## 
##   RMSEA                                          0.039
## 
## Standardized Root Mean Square Residual:
## 
##   SRMR                                           0.049
as.data.frame(unclass(standardizedSolution(sibCON))) %>% 
  filter(op == "~1" & lhs %in% c("iy", "io", "sy", "so")) %>% 
  select("Parameters" = lhs, Beta = est.std, SE = se, Z = z, "p-value" = pvalue, "CI lower" = ci.lower, "CI upper" = ci.upper) %>% 
  knitr::kable(caption = "Intercept and Slope", digits = 6) %>% 
  kable_styling() %>% 
  footnote(general = "i = intercept, s = slope, o = older sibling, y = younger sibling")
Intercept and Slope
Parameters Beta SE Z p-value CI lower CI upper
iy 7.97 0.445 17.922 0.000 7.095 8.84
io 6.67 0.312 21.362 0.000 6.057 7.28
sy 3.54 7.185 0.493 0.622 -10.541 17.62
so 1.49 0.579 2.575 0.010 0.356 2.62
Note:
i = intercept, s = slope, o = older sibling, y = younger sibling
as.data.frame(unclass(standardizedSolution(sibCON))) %>% 
  filter(op == "~~" & lhs %in% c("sy", "iy") & rhs %in% c("so", "io") & z < 1.324) %>% 
  select("Younger sibling" = lhs, "Older sibling" = rhs, Beta = est.std, SE = se, Z = z, "p-value" = pvalue, "CI lower" = ci.lower, "CI upper" = ci.upper) %>% 
  knitr::kable(caption = "Correlated intercepts and slopes", digits = 6) %>% 
  kable_styling() %>% 
  footnote(general = "i = intercept, s = slope, o = older sibling, y = younger sibling")
Correlated intercepts and slopes
Younger sibling Older sibling Beta SE Z p-value CI lower CI upper
iy io -0.00339 0.0637 -0.0533 0.958 -0.128 0.122
iy so 0.14394 0.1209 1.1907 0.234 -0.093 0.381
sy so -0.67387 1.4293 -0.4715 0.637 -3.475 2.127
Note:
i = intercept, s = slope, o = older sibling, y = younger sibling
semPaths(sibCON, what = "col", whatLabels = "est", intercepts = T)

Harm Avoidance HA

lgmHA <- '
#younger sibling
HA0y =~   HA_IN_y_p1  + p2 * HA_IN_y_p2   + p3 * HA_IN_y_p3
HA3y =~   HA_FU1_y_p1 + p2 * HA_FU1_y_p2  + p3 * HA_FU1_y_p3
HA17y =~  HA_FU3_y_p1 + p2 * HA_FU3_y_p2  + p3 * HA_FU3_y_p3
                   
#older sibling
HA0o =~   HA_IN_o_p1  + p2 * HA_IN_o_p2   + p3 * HA_IN_o_p3
HA3o =~   HA_FU1_o_p1 + p2 * HA_FU1_o_p2  + p3 * HA_FU1_o_p3
HA17o =~  HA_FU3_o_p1 + p2 * HA_FU3_o_p2  + p3 * HA_FU3_o_p3

#latent intercept and slopes
iy =~ 1*HA0y + 1*HA3y + 1*HA17y
io =~ 1*HA0o + 1*HA3o + 1*HA17o
sy =~ 0*HA0y + 3.3*HA3y + 17*HA17y
so =~ 0*HA0o + 3.3*HA3o + 17*HA17o
iy ~ 1
io ~ 1
sy ~ 1
so ~ 1

#fix zero latent intercepts
HA0y ~ 0*1
HA3y ~ 0*1
HA17y ~ 0*1
HA0o ~ 0*1
HA3o ~ 0*1
HA17o ~ 0*1

#fix zero/equal item intercepts
HA_IN_y_p1  ~ 0*1
HA_FU1_y_p1 ~ 0*1
HA_FU3_y_p1 ~ 0*1
HA_IN_o_p1  ~ 0*1
HA_FU1_o_p1 ~ 0*1
HA_FU3_o_p1 ~ 0*1

HA_IN_y_p2  ~ par2*1
HA_FU1_y_p2 ~ par2*1
HA_FU3_y_p2 ~ par2*1
HA_IN_o_p2  ~ par2*1
HA_FU1_o_p2 ~ par2*1
HA_FU3_o_p2 ~ par2*1

HA_IN_y_p3  ~ par3*1
HA_FU1_y_p3 ~ par3*1
HA_FU3_y_p3 ~ par3*1
HA_IN_o_p3  ~ par3*1
HA_FU1_o_p3 ~ par3*1
HA_FU3_o_p3 ~ par3*1

#residual covariances
HA_IN_y_p1 ~~ c(cov11)*HA_FU1_y_p1 + c(cov13)*HA_FU3_y_p1 
HA_FU1_y_p1 ~~ c(cov12)*HA_FU3_y_p1 

HA_IN_y_p2 ~~ c(cov21)*HA_FU1_y_p2 + c(cov23)*HA_FU3_y_p2 
HA_FU1_y_p2 ~~ + c(cov22)*HA_FU3_y_p2 

HA_IN_y_p3 ~~ c(cov31)*HA_FU1_y_p3 + c(cov33)*HA_FU3_y_p3 
HA_FU1_y_p3 ~~ c(cov32)*HA_FU3_y_p3 

HA_IN_o_p1 ~~ c(cov11)*HA_FU1_o_p1 + c(cov13)*HA_FU3_o_p1 
HA_FU1_o_p1 ~~ c(cov12)*HA_FU3_o_p1 

HA_IN_o_p2 ~~ c(cov21)*HA_FU1_o_p2 + c(cov23)*HA_FU3_o_p2 
HA_FU1_o_p2 ~~ c(cov22)*HA_FU3_o_p2 

HA_IN_o_p3 ~~ c(cov31)*HA_FU1_o_p3 + c(cov33)*HA_FU3_o_p3 
HA_FU1_o_p3 ~~ c(cov32)*HA_FU3_o_p3 
'

sibHA <- sem(lgmHA, data = yo, missing = "FIML")

fitMeasures(sibHA, c("chisq", "df", "pvalue", "cfi", "rmsea", "srmr"), 
            output = "text")
## 
## Model Test User Model:
## 
##   Test statistic                               502.965
##   Degrees of freedom                               138
##   P-value                                        0.000
## 
## User Model versus Baseline Model:
## 
##   Comparative Fit Index (CFI)                    0.918
## 
## Root Mean Square Error of Approximation:
## 
##   RMSEA                                          0.066
## 
## Standardized Root Mean Square Residual:
## 
##   SRMR                                           0.064
as.data.frame(unclass(standardizedSolution(sibHA))) %>% 
  filter(op == "~1" & lhs %in% c("iy", "io", "sy", "so")) %>% 
  select("Parameters" = lhs, Beta = est.std, SE = se, Z = z, "p-value" = pvalue, "CI lower" = ci.lower, "CI upper" = ci.upper) %>% 
  knitr::kable(caption = "Intercept and Slope", digits = 6) %>% 
  kable_styling() %>% 
  footnote(general = "i = intercept, s = slope, o = older sibling, y = younger sibling")
Intercept and Slope
Parameters Beta SE Z p-value CI lower CI upper
iy 6.17 0.372 16.56 0.000000 5.436 6.89
io 4.91 0.221 22.22 0.000000 4.480 5.35
sy 1.21 0.718 1.69 0.091608 -0.196 2.62
so 1.08 0.296 3.64 0.000278 0.495 1.65
Note:
i = intercept, s = slope, o = older sibling, y = younger sibling
as.data.frame(unclass(standardizedSolution(sibHA))) %>% 
  filter(op == "~~" & lhs %in% c("sy", "iy") & rhs %in% c("so", "io")) %>% 
  select("Younger sibling" = lhs, "Older sibling" = rhs, Beta = est.std, SE = se, Z = z, "p-value" = pvalue, "CI lower" = ci.lower, "CI upper" = ci.upper) %>% 
  knitr::kable(caption = "Correlated intercepts and slopes", digits = 6) %>% 
  kable_styling() %>% 
  footnote(general = "i = intercept, s = slope, o = older sibling, y = younger sibling")
Correlated intercepts and slopes
Younger sibling Older sibling Beta SE Z p-value CI lower CI upper
iy io 0.326 0.0617 5.291 0.000 0.205 0.4471
iy so -0.135 0.1017 -1.329 0.184 -0.335 0.0642
sy so 0.127 0.1773 0.717 0.473 -0.220 0.4746
Note:
i = intercept, s = slope, o = older sibling, y = younger sibling
semPaths(sibHA, what = "col", whatLabels = "est", intercepts = T)

Adopted vs. Non-adopted

Here we compare between-sibling correlations in adopted vs. non-adopted sibling pairs.

Correlations are considered significantly different from one another if the confidence interval of one correlation does not include the point estimate for the other correlation.

# create adopted/bio variable
yo <- yo %>% 
  mutate(adopt = ifelse(IDAB_y == 1 | IDAB_o == 1, 1, 0))

# histogram
ggplot(yo, 
       aes(factor(yo$adopt,
                  levels = c(0, 1),
                  labels = c("Non-Adoptive", "Adoptive")))) + 
  geom_bar(fill = c("#710c0c", "#f1c232")) + 
  geom_text(stat='count', aes(label=..count..), vjust = -1) + 
  labs(
    title = "Count of adoption status in sibling pairs",
    x = NULL
  ) +
  ylim(0, 450) +
  theme_classic()

There are 406 adopted pairs and 208 non-adopted sibling pairs.

Adoption status - Aggression AG

adoptAG <- sem(lgmAG, data = yo, missing = "FIML",
               group = "adopt")

fitMeasures(adoptAG, c("chisq", "df", "pvalue", "cfi", "rmsea", "srmr"), 
            output = "text")
## 
## Model Test User Model:
## 
##   Test statistic                               484.633
##   Degrees of freedom                               289
##   P-value                                        0.000
## 
## User Model versus Baseline Model:
## 
##   Comparative Fit Index (CFI)                    0.969
## 
## Root Mean Square Error of Approximation:
## 
##   RMSEA                                          0.047
## 
## Standardized Root Mean Square Residual:
## 
##   SRMR                                           0.061
# intercept and slope 
as.data.frame(unclass(standardizedSolution(adoptAG))) %>% 
  filter(op == "~1" & lhs %in% c("iy", "io", "sy", "so")) %>% 
  select("Adopted" = group, "Parameters" = lhs, Beta = est.std, SE = se, Z = z, "p-value" = pvalue, "CI lower" = ci.lower, "CI upper" = ci.upper) %>% 
  mutate(Adopted = ifelse(Adopted == 1, "adopt", "bio")) %>% 
  arrange(Parameters) %>% 
  knitr::kable(caption = "Intercept and Slope", digits = 6) %>% 
  kable_styling() %>% 
  footnote(general = "i = intercept, s = slope, o = older sibling, y = younger sibling")
Intercept and Slope
Adopted Parameters Beta SE Z p-value CI lower CI upper
adopt io 3.780 0.189 20.007 0.000000 3.41 4.150
bio io 4.073 0.323 12.607 0.000000 3.44 4.706
adopt iy 4.152 0.234 17.763 0.000000 3.69 4.610
bio iy 3.921 0.281 13.949 0.000000 3.37 4.472
adopt so -0.757 0.167 -4.527 0.000006 -1.08 -0.429
bio so -0.969 0.255 -3.806 0.000141 -1.47 -0.470
adopt sy -0.777 0.150 -5.185 0.000000 -1.07 -0.483
bio sy -3.263 6.766 -0.482 0.629576 -16.52 9.998
Note:
i = intercept, s = slope, o = older sibling, y = younger sibling
# correlated intercepts and slopes
as.data.frame(unclass(standardizedSolution(adoptAG))) %>% 
  filter(op == "~~" & lhs %in% c("sy", "iy") & rhs %in% c("so", "io")) %>% 
  arrange(lhs) %>% 
  select("Adopted" = group, "Younger sibling" = lhs, "Older sibling" = rhs, Beta = est.std, SE = se, Z = z, "p-value" = pvalue, "CI lower" = ci.lower, "CI upper" = ci.upper) %>% 
  mutate(Adopted = ifelse(Adopted == 1, "adopt", "bio")) %>% 
  knitr::kable(caption = "Correlated intercepts and slopes", digits = 6) %>% 
  kable_styling() %>% 
  footnote(general = "i = intercept, s = slope, o = older sibling, y = younger sibling")
Correlated intercepts and slopes
Adopted Younger sibling Older sibling Beta SE Z p-value CI lower CI upper
adopt iy io 0.235 0.0650 3.612 0.000303 0.1073 0.3620
adopt iy so -0.259 0.0963 -2.690 0.007155 -0.4479 -0.0703
bio iy io 0.470 0.0833 5.636 0.000000 0.3063 0.6330
bio iy so -0.231 0.1089 -2.117 0.034255 -0.4439 -0.0171
adopt sy so 0.158 0.0965 1.637 0.101665 -0.0312 0.3472
bio sy so 0.668 1.4185 0.471 0.637643 -2.1121 3.4484
Note:
i = intercept, s = slope, o = older sibling, y = younger sibling

Adoption status - Control CON

adoptCON <- sem(lgmCON, data = yo, missing = "FIML",
                group = "adopt")

fitMeasures(adoptCON, c("chisq", "df", "pvalue", "cfi", "rmsea", "srmr"), 
            output = "text")
## 
## Model Test User Model:
## 
##   Test statistic                               426.770
##   Degrees of freedom                               289
##   P-value                                        0.000
## 
## User Model versus Baseline Model:
## 
##   Comparative Fit Index (CFI)                    0.973
## 
## Root Mean Square Error of Approximation:
## 
##   RMSEA                                          0.039
## 
## Standardized Root Mean Square Residual:
## 
##   SRMR                                           0.059
# intercept and slope 
as.data.frame(unclass(standardizedSolution(adoptCON))) %>% 
  filter(op == "~1" & lhs %in% c("iy", "io", "sy", "so")) %>% 
  select("Adopted" = group, "Parameters" = lhs, Beta = est.std, SE = se, Z = z, "p-value" = pvalue, "CI lower" = ci.lower, "CI upper" = ci.upper) %>% 
  mutate(Adopted = ifelse(Adopted == 1, "adopt", "bio")) %>% 
  arrange(Parameters) %>% 
  knitr::kable(caption = "Intercept and Slope", digits = 6) %>% 
  kable_styling() %>% 
  footnote(general = "i = intercept, s = slope, o = older sibling, y = younger sibling")
Intercept and Slope
Adopted Parameters Beta SE Z p-value CI lower CI upper
adopt io 6.04 0.314 19.22 0.000000 5.426 6.66
bio io 8.48 0.888 9.54 0.000000 6.735 10.22
adopt iy 7.81 0.504 15.50 0.000000 6.824 8.80
bio iy 8.24 0.872 9.46 0.000000 6.535 9.95
adopt so 1.05 0.267 3.91 0.000091 0.523 1.57
bio so NA NA NA NA NA NA
adopt sy 1.65 0.993 1.66 0.096409 -0.295 3.60
bio sy NA NA NA NA NA NA
Note:
i = intercept, s = slope, o = older sibling, y = younger sibling
# correlated intercepts and slopes
as.data.frame(unclass(standardizedSolution(adoptCON))) %>% 
  filter(op == "~~" & lhs %in% c("sy", "iy") & rhs %in% c("so", "io")) %>% 
  arrange(lhs) %>% 
  select("Adopted" = group, "Younger sibling" = lhs, "Older sibling" = rhs, Beta = est.std, SE = se, Z = z, "p-value" = pvalue, "CI lower" = ci.lower, "CI upper" = ci.upper) %>% 
  mutate(Adopted = ifelse(Adopted == 1, "adopt", "bio")) %>% 
  slice(-c(2,4)) %>% 
  knitr::kable(caption = "Correlated intercepts and slopes", digits = 6) %>% 
  kable_styling() %>% 
  footnote(general = "i = intercept, s = slope, o = older sibling, y = younger sibling")
Correlated intercepts and slopes
Adopted Younger sibling Older sibling Beta SE Z p-value CI lower CI upper
adopt iy io -0.0239 0.072 -0.331 0.741 -0.165 0.117
bio iy io 0.0401 0.135 0.297 0.766 -0.224 0.305
adopt sy so -0.2106 0.221 -0.952 0.341 -0.644 0.223
bio sy so -1.4592 10.540 -0.138 0.890 -22.117 19.199
Note:
i = intercept, s = slope, o = older sibling, y = younger sibling

Adoption status - Harm Avoidance HA

adoptHA <- sem(lgmHA, data = yo, missing = "FIML",
                group = "adopt")

fitMeasures(adoptHA, c("chisq", "df", "pvalue", "cfi", "rmsea", "srmr"), 
            output = "text")
## 
## Model Test User Model:
## 
##   Test statistic                               666.446
##   Degrees of freedom                               289
##   P-value                                        0.000
## 
## User Model versus Baseline Model:
## 
##   Comparative Fit Index (CFI)                    0.915
## 
## Root Mean Square Error of Approximation:
## 
##   RMSEA                                          0.065
## 
## Standardized Root Mean Square Residual:
## 
##   SRMR                                           0.072
# intercept and slope 
as.data.frame(unclass(standardizedSolution(adoptHA))) %>% 
  filter(op == "~1" & lhs %in% c("iy", "io", "sy", "so")) %>% 
  select("Adopted" = group, "Parameters" = lhs, Beta = est.std, SE = se, Z = z, "p-value" = pvalue, "CI lower" = ci.lower, "CI upper" = ci.upper) %>% 
  mutate(Adopted = ifelse(Adopted == 1, "adopt", "bio")) %>% 
  arrange(Parameters) %>% 
  knitr::kable(caption = "Intercept and Slope", digits = 6) %>% 
  kable_styling() %>% 
  footnote(general = "i = intercept, s = slope, o = older sibling, y = younger sibling")
Intercept and Slope
Adopted Parameters Beta SE Z p-value CI lower CI upper
adopt io 4.968 0.275 18.081 0.00000 4.429 5.51
bio io 4.817 0.360 13.376 0.00000 4.111 5.52
adopt iy 6.889 0.574 11.997 0.00000 5.763 8.01
bio iy 5.409 0.491 11.015 0.00000 4.447 6.37
adopt so 1.078 0.407 2.651 0.00802 0.281 1.88
bio so 1.071 0.414 2.585 0.00975 0.259 1.88
adopt sy 1.857 3.267 0.568 0.56971 -4.546 8.26
bio sy 0.988 0.595 1.661 0.09680 -0.178 2.15
Note:
i = intercept, s = slope, o = older sibling, y = younger sibling
# correlated intercepts and slopes
as.data.frame(unclass(standardizedSolution(adoptHA))) %>% 
  filter(op == "~~" & lhs %in% c("sy", "iy") & rhs %in% c("so", "io")) %>% 
  arrange(lhs) %>% 
  select("Adopted" = group, "Younger sibling" = lhs, "Older sibling" = rhs, Beta = est.std, SE = se, Z = z, "p-value" = pvalue, "CI lower" = ci.lower, "CI upper" = ci.upper) %>% 
  mutate(Adopted = ifelse(Adopted == 1, "adopt", "bio")) %>% 
  slice(-c(2,4)) %>% 
  knitr::kable(caption = "Correlated intercepts and slopes", digits = 6) %>% 
  kable_styling() %>% 
  footnote(general = "i = intercept, s = slope, o = older sibling, y = younger sibling")
Correlated intercepts and slopes
Adopted Younger sibling Older sibling Beta SE Z p-value CI lower CI upper
adopt iy io 0.2123 0.0826 2.570 0.0102 0.0504 0.374
bio iy io 0.5213 0.0911 5.725 0.0000 0.3429 0.700
adopt sy so 0.2617 0.5674 0.461 0.6446 -0.8504 1.374
bio sy so 0.0523 0.2016 0.259 0.7955 -0.3430 0.447
Note:
i = intercept, s = slope, o = older sibling, y = younger sibling

Same-sex vs. Opposite-sex

Here we compare between-sibling correlations in same-sex and opposite-sex pairs.

Correlations are considered significantly different from one another if the confidence interval of one correlation does not include the point estimate for the other correlation.

# create same/opposite sex variable
yo <- yo %>% 
  mutate(samesex = as.numeric(IDSEX_y == IDSEX_o))

# histogram
ggplot(yo, 
       aes(factor(yo$samesex,
                  levels = c(0, 1),
                  labels = c("Different-Sex", "Same-Sex")))) + 
  geom_bar(fill = c("#f1c232", "#710c0c")) + 
  geom_text(stat='count', aes(label=..count..), vjust = -1) + 
  labs(
    title = "Count of sex similarity in sibling pairs",
    x = NULL
  ) +
  ylim(0, 450) +
  theme_classic()

There are 374 same-sex and 240 opposite-sex sibling pairs.

Sex similarity - Aggression AG

sexAG <- sem(lgmAG, data = yo, missing = "FIML",
               group = "samesex")

fitMeasures(sexAG, c("chisq", "df", "pvalue", "cfi", "rmsea", "srmr"), 
            output = "text")
## 
## Model Test User Model:
## 
##   Test statistic                               423.557
##   Degrees of freedom                               289
##   P-value                                        0.000
## 
## User Model versus Baseline Model:
## 
##   Comparative Fit Index (CFI)                    0.979
## 
## Root Mean Square Error of Approximation:
## 
##   RMSEA                                          0.039
## 
## Standardized Root Mean Square Residual:
## 
##   SRMR                                           0.062
# intercept and slope 
as.data.frame(unclass(standardizedSolution(sexAG))) %>% 
  filter(op == "~1" & lhs %in% c("iy", "io", "sy", "so")) %>% 
  select("SameSex" = group, "Parameters" = lhs, Beta = est.std, SE = se, Z = z, "p-value" = pvalue, "CI lower" = ci.lower, "CI upper" = ci.upper) %>% 
  mutate(SameSex = ifelse(SameSex == 1, "same-sex", "opposite-sex")) %>% 
  arrange(Parameters) %>% 
  knitr::kable(caption = "Intercept and Slope", digits = 6) %>% 
  kable_styling() %>% 
  footnote(general = "i = intercept, s = slope, o = older sibling, y = younger sibling")
Intercept and Slope
SameSex Parameters Beta SE Z p-value CI lower CI upper
same-sex io 3.787 0.203 18.65 0.000000 3.389 4.185
opposite-sex io 4.036 0.279 14.49 0.000000 3.490 4.582
same-sex iy 3.954 0.216 18.34 0.000000 3.531 4.376
opposite-sex iy 4.228 0.314 13.47 0.000000 3.613 4.843
same-sex so -0.909 0.216 -4.21 0.000026 -1.333 -0.485
opposite-sex so -0.671 0.141 -4.75 0.000002 -0.948 -0.394
same-sex sy -1.172 0.319 -3.68 0.000235 -1.797 -0.548
opposite-sex sy -1.016 0.370 -2.75 0.006028 -1.741 -0.291
Note:
i = intercept, s = slope, o = older sibling, y = younger sibling
# correlated intercepts and slopes
as.data.frame(unclass(standardizedSolution(sexAG))) %>% 
  filter(op == "~~" & lhs %in% c("sy", "iy") & rhs %in% c("so", "io")) %>% 
  arrange(lhs) %>% 
  select("SameSex" = group, "Younger sibling" = lhs, "Older sibling" = rhs, Beta = est.std, SE = se, Z = z, "p-value" = pvalue, "CI lower" = ci.lower, "CI upper" = ci.upper) %>% 
  mutate(SameSex = ifelse(SameSex == 1, "same-sex", "opposite-sex")) %>% 
  knitr::kable(caption = "Correlated intercepts and slopes", digits = 6) %>% 
  kable_styling() %>% 
  footnote(general = "i = intercept, s = slope, o = older sibling, y = younger sibling")
Correlated intercepts and slopes
SameSex Younger sibling Older sibling Beta SE Z p-value CI lower CI upper
same-sex iy io 0.4462 0.0609 7.328 0.00000 0.3268 0.5655
same-sex iy so -0.3383 0.1123 -3.013 0.00258 -0.5584 -0.1183
opposite-sex iy io 0.0776 0.0904 0.858 0.39064 -0.0995 0.2547
opposite-sex iy so -0.1510 0.0886 -1.704 0.08844 -0.3248 0.0227
same-sex sy so 0.1918 0.1359 1.411 0.15818 -0.0746 0.4581
opposite-sex sy so 0.2805 0.1506 1.862 0.06263 -0.0148 0.5757
Note:
i = intercept, s = slope, o = older sibling, y = younger sibling

Sex similarity - Control CON

sexCON <- sem(lgmCON, data = yo, missing = "FIML",
                group = "samesex")

fitMeasures(sexCON, c("chisq", "df", "pvalue", "cfi", "rmsea", "srmr"), 
            output = "text")
## 
## Model Test User Model:
## 
##   Test statistic                               441.077
##   Degrees of freedom                               289
##   P-value                                        0.000
## 
## User Model versus Baseline Model:
## 
##   Comparative Fit Index (CFI)                    0.970
## 
## Root Mean Square Error of Approximation:
## 
##   RMSEA                                          0.041
## 
## Standardized Root Mean Square Residual:
## 
##   SRMR                                           0.063
# intercept and slope 
as.data.frame(unclass(standardizedSolution(sexCON))) %>% 
  filter(op == "~1" & lhs %in% c("iy", "io", "sy", "so")) %>% 
  select("SameSex" = group, "Parameters" = lhs, Beta = est.std, SE = se, Z = z, "p-value" = pvalue, "CI lower" = ci.lower, "CI upper" = ci.upper) %>% 
  mutate(SameSex = ifelse(SameSex == 1, "same-sex", "opposite-sex")) %>% 
  arrange(Parameters) %>% 
  knitr::kable(caption = "Intercept and Slope", digits = 6) %>% 
  kable_styling() %>% 
  footnote(general = "i = intercept, s = slope, o = older sibling, y = younger sibling")
Intercept and Slope
SameSex Parameters Beta SE Z p-value CI lower CI upper
same-sex io 6.97 0.437 15.947 0.00000 6.11 7.83
opposite-sex io 6.29 0.436 14.439 0.00000 5.44 7.14
same-sex iy 8.21 0.618 13.293 0.00000 7.00 9.42
opposite-sex iy 7.69 0.630 12.193 0.00000 6.45 8.92
same-sex so 2.04 1.987 1.028 0.30393 -1.85 5.94
opposite-sex so 1.15 0.407 2.819 0.00482 0.35 1.95
same-sex sy NA NA NA NA NA NA
opposite-sex sy 2.54 4.344 0.584 0.55892 -5.97 11.05
Note:
i = intercept, s = slope, o = older sibling, y = younger sibling
# correlated intercepts and slopes
as.data.frame(unclass(standardizedSolution(sexCON))) %>% 
  filter(op == "~~" & lhs %in% c("sy", "iy") & rhs %in% c("so", "io")) %>% 
  arrange(lhs) %>% 
  select("SameSex" = group, "Younger sibling" = lhs, "Older sibling" = rhs, Beta = est.std, SE = se, Z = z, "p-value" = pvalue, "CI lower" = ci.lower, "CI upper" = ci.upper) %>% 
  mutate(SameSex = ifelse(SameSex == 1, "same-sex", "opposite-sex")) %>% 
  slice(-c(2,4)) %>% 
  knitr::kable(caption = "Correlated intercepts and slopes", digits = 6) %>% 
  kable_styling() %>% 
  footnote(general = "i = intercept, s = slope, o = older sibling, y = younger sibling")
Correlated intercepts and slopes
SameSex Younger sibling Older sibling Beta SE Z p-value CI lower CI upper
same-sex iy io -0.0317 0.0863 -0.368 0.713 -0.201 0.137
opposite-sex iy io 0.0297 0.0953 0.311 0.755 -0.157 0.216
same-sex sy so -1.1208 3.7820 -0.296 0.767 -8.533 6.292
opposite-sex sy so -0.4284 0.8126 -0.527 0.598 -2.021 1.164
Note:
i = intercept, s = slope, o = older sibling, y = younger sibling

Sex similarity - Harm Avoidance HA

sexHA <- sem(lgmHA, data = yo, missing = "FIML",
                group = "samesex")

fitMeasures(sexHA, c("chisq", "df", "pvalue", "cfi", "rmsea", "srmr"), 
            output = "text")
## 
## Model Test User Model:
## 
##   Test statistic                               669.213
##   Degrees of freedom                               289
##   P-value                                        0.000
## 
## User Model versus Baseline Model:
## 
##   Comparative Fit Index (CFI)                    0.915
## 
## Root Mean Square Error of Approximation:
## 
##   RMSEA                                          0.065
## 
## Standardized Root Mean Square Residual:
## 
##   SRMR                                           0.073
# intercept and slope 
as.data.frame(unclass(standardizedSolution(sexHA))) %>% 
  filter(op == "~1" & lhs %in% c("iy", "io", "sy", "so")) %>% 
  select("SameSex" = group, "Parameters" = lhs, Beta = est.std, SE = se, Z = z, "p-value" = pvalue, "CI lower" = ci.lower, "CI upper" = ci.upper) %>% 
  mutate(SameSex = ifelse(SameSex == 1, "same-sex", "opposite-sex")) %>% 
  arrange(Parameters) %>% 
  knitr::kable(caption = "Intercept and Slope", digits = 6) %>% 
  kable_styling() %>% 
  footnote(general = "i = intercept, s = slope, o = older sibling, y = younger sibling")
Intercept and Slope
SameSex Parameters Beta SE Z p-value CI lower CI upper
same-sex io 4.954 0.283 17.50 0.000000 4.399 5.51
opposite-sex io 4.876 0.342 14.27 0.000000 4.206 5.55
same-sex iy 6.316 0.521 12.12 0.000000 5.294 7.34
opposite-sex iy 5.950 0.512 11.62 0.000000 4.946 6.95
same-sex so 1.396 0.802 1.74 0.081786 -0.176 2.97
opposite-sex so 0.865 0.271 3.19 0.001433 0.333 1.40
same-sex sy 0.751 0.223 3.36 0.000769 0.313 1.19
opposite-sex sy NA NA NA NA NA NA
Note:
i = intercept, s = slope, o = older sibling, y = younger sibling
# correlated intercepts and slopes
as.data.frame(unclass(standardizedSolution(sexHA))) %>% 
  filter(op == "~~" & lhs %in% c("sy", "iy") & rhs %in% c("so", "io")) %>% 
  arrange(lhs) %>% 
  select("SameSex" = group, "Younger sibling" = lhs, "Older sibling" = rhs, Beta = est.std, SE = se, Z = z, "p-value" = pvalue, "CI lower" = ci.lower, "CI upper" = ci.upper) %>% 
  mutate(SameSex = ifelse(SameSex == 1, "same-sex", "opposite-sex")) %>% 
  slice(-c(2,4)) %>% 
  knitr::kable(caption = "Correlated intercepts and slopes", digits = 6) %>% 
  kable_styling() %>% 
  footnote(general = "i = intercept, s = slope, o = older sibling, y = younger sibling")
Correlated intercepts and slopes
SameSex Younger sibling Older sibling Beta SE Z p-value CI lower CI upper
same-sex iy io 0.433 0.0787 5.497 0.0000 0.27836 0.587
opposite-sex iy io 0.190 0.0991 1.915 0.0555 -0.00447 0.384
same-sex sy so 0.302 0.2588 1.169 0.2424 -0.20469 0.810
opposite-sex sy so -0.123 0.1847 -0.664 0.5067 -0.48469 0.239
Note:
i = intercept, s = slope, o = older sibling, y = younger sibling

IV. Analyses with full data

General change trajectories and correlated change with 4 waves

These analyses analyzed the general change pattern using all 4 waves of data: IN, FU1, FU2, FU3. This is to compare with analyses in section III, which only included 3 waves, excluding FU2 for high missingness. Because these analyses made use of the maximum amount of data, they will be presented in reports and presentations for general change patterns.

Aggression AG

lgmAG <- '
#younger sibling
AG0y =~   AG_IN_y_p1  + p2 * AG_IN_y_p2   + p3 * AG_IN_y_p3
AG3y =~   AG_FU1_y_p1 + p2 * AG_FU1_y_p2  + p3 * AG_FU1_y_p3
AG7y =~   AG_FU2_y_p1 + p2 * AG_FU2_y_p2  + p3 * AG_FU2_y_p3
AG17y =~  AG_FU3_y_p1 + p2 * AG_FU3_y_p2  + p3 * AG_FU3_y_p3
                   
#older sibling
AG0o =~   AG_IN_o_p1  + p2 * AG_IN_o_p2   + p3 * AG_IN_o_p3
AG3o =~   AG_FU1_o_p1 + p2 * AG_FU1_o_p2  + p3 * AG_FU1_o_p3
AG7o =~   AG_FU2_o_p1 + p2 * AG_FU2_o_p2  + p3 * AG_FU2_o_p3
AG17o =~  AG_FU3_o_p1 + p2 * AG_FU3_o_p2  + p3 * AG_FU3_o_p3

#latent intercept and slopes
iy =~ 1*AG0y + 1*AG3y + 1*AG7y + 1*AG17y
io =~ 1*AG0o + 1*AG3o + 1*AG7o + 1*AG17o
sy =~ 0*AG0y + 3.3*AG3y + 7.6*AG7y + 17*AG17y
so =~ 0*AG0o + 3.3*AG3o + 7.6*AG7o + 17*AG17o
iy ~ 1
io ~ 1
sy ~ 1
so ~ 1

#fix zero latent intercepts
AG0y ~ 0*1
AG3y ~ 0*1
AG7y ~ 0*1
AG17y ~ 0*1
AG0o ~ 0*1
AG3o ~ 0*1
AG7o ~ 0*1
AG17o ~ 0*1

#fix zero/equal item intercepts
AG_IN_y_p1  ~ 0*1
AG_FU1_y_p1 ~ 0*1
AG_FU2_y_p1 ~ 0*1
AG_FU3_y_p1 ~ 0*1
AG_IN_o_p1  ~ 0*1
AG_FU1_o_p1 ~ 0*1
AG_FU2_o_p1 ~ 0*1
AG_FU3_o_p1 ~ 0*1

AG_IN_y_p2  ~ par2*1
AG_FU1_y_p2 ~ par2*1
AG_FU2_y_p2 ~ par2*1
AG_FU3_y_p2 ~ par2*1
AG_IN_o_p2  ~ par2*1
AG_FU1_o_p2 ~ par2*1
AG_FU2_o_p2 ~ par2*1
AG_FU3_o_p2 ~ par2*1

AG_IN_y_p3  ~ par3*1
AG_FU1_y_p3 ~ par3*1
AG_FU2_y_p3 ~ par3*1
AG_FU3_y_p3 ~ par3*1
AG_IN_o_p3  ~ par3*1
AG_FU1_o_p3 ~ par3*1
AG_FU2_o_p3 ~ par3*1
AG_FU3_o_p3 ~ par3*1

#residual covariances
AG_IN_y_p1 ~~ c(cov11)*AG_FU1_y_p1 + c(cov12)*AG_FU2_y_p1 + c(cov13)*AG_FU3_y_p1 
AG_FU1_y_p1 ~~ c(cov11)*AG_FU2_y_p1 + c(cov12)*AG_FU3_y_p1 
AG_FU2_y_p1 ~~ c(cov11)*AG_FU3_y_p1 

AG_IN_y_p2 ~~ c(cov21)*AG_FU1_y_p2 + c(cov22)*AG_FU2_y_p2 + c(cov23)*AG_FU3_y_p2 
AG_FU1_y_p2 ~~ c(cov21)*AG_FU2_y_p2 + c(cov22)*AG_FU3_y_p2 
AG_FU2_y_p2 ~~ c(cov21)*AG_FU3_y_p2 

AG_IN_y_p3 ~~ c(cov31)*AG_FU1_y_p3 + c(cov32)*AG_FU2_y_p3 + c(cov33)*AG_FU3_y_p3 
AG_FU1_y_p3 ~~ c(cov31)*AG_FU2_y_p3 + c(cov32)*AG_FU3_y_p3 
AG_FU2_y_p3 ~~ c(cov31)*AG_FU3_y_p3 

AG_IN_o_p1 ~~ c(cov11)*AG_FU1_o_p1 + c(cov12)*AG_FU2_o_p1 + c(cov13)*AG_FU3_o_p1 
AG_FU1_o_p1 ~~ c(cov11)*AG_FU2_o_p1 + c(cov12)*AG_FU3_o_p1 
AG_FU2_o_p1 ~~ c(cov11)*AG_FU3_o_p1 

AG_IN_o_p2 ~~ c(cov21)*AG_FU1_o_p2 + c(cov22)*AG_FU2_o_p2 + c(cov23)*AG_FU3_o_p2 
AG_FU1_o_p2 ~~ c(cov21)*AG_FU2_o_p2 + c(cov22)*AG_FU3_o_p2 
AG_FU2_o_p2 ~~ c(cov21)*AG_FU3_o_p2 

AG_IN_o_p3 ~~ c(cov31)*AG_FU1_o_p3 + c(cov32)*AG_FU2_o_p3 + c(cov33)*AG_FU3_o_p3 
AG_FU1_o_p3 ~~ c(cov31)*AG_FU2_o_p3 + c(cov32)*AG_FU3_o_p3 
AG_FU2_o_p3 ~~ c(cov31)*AG_FU3_o_p3 
'
#ad_sibAG <- sem(sibAG, data = yo[which(yo$adopt == 1),], missing = "FIML")
#summary(ad_sibAG, fit.measures = T, standardized = T)

#bio_sibAG <- sem(sibAG, data = yo[which(yo$adopt == 0),], missing = "FIML")
#summary(bio_sibAG, fit.measures = T, standardized = T)

#g_sibAG <- sem(sibAG, data = yo, missing = "FIML", group = "adopt", em.iter.max = 20000)
#summary(g_sibAG, fit.measures = T, standardized = T, ci = T)

sibAG <- sem(lgmAG, data = yo, missing = "FIML")

fitMeasures(sibAG, c("chisq", "df", "pvalue", "cfi", "rmsea", "srmr"), 
            output = "text")
## 
## Model Test User Model:
## 
##   Test statistic                               455.575
##   Degrees of freedom                               265
##   P-value                                        0.000
## 
## User Model versus Baseline Model:
## 
##   Comparative Fit Index (CFI)                    0.971
## 
## Root Mean Square Error of Approximation:
## 
##   RMSEA                                          0.034
## 
## Standardized Root Mean Square Residual:
## 
##   SRMR                                           0.137
as.data.frame(unclass(standardizedSolution(sibAG))) %>% 
  filter(op == "~1" & lhs %in% c("iy", "io", "sy", "so")) %>% 
  select("Parameters" = lhs, Beta = est.std, SE = se, Z = z, "p-value" = pvalue, "CI lower" = ci.lower, "CI upper" = ci.upper) %>% 
  knitr::kable(caption = "Intercept and Slope", digits = 6) %>% 
  kable_styling() %>% 
  footnote(general = "i = intercept, s = slope, o = older sibling, y = younger sibling")
Intercept and Slope
Parameters Beta SE Z p-value CI lower CI upper
iy 4.152 0.185 22.46 0 3.79 4.514
io 3.885 0.165 23.59 0 3.56 4.207
sy -1.043 0.132 -7.88 0 -1.30 -0.783
so -0.852 0.127 -6.68 0 -1.10 -0.602
Note:
i = intercept, s = slope, o = older sibling, y = younger sibling
as.data.frame(unclass(standardizedSolution(sibAG))) %>% 
  filter(op == "~~" & lhs %in% c("sy", "iy") & rhs %in% c("so", "io")) %>% 
  select("Younger sibling" = lhs, "Older sibling" = rhs, Beta = est.std, SE = se, Z = z, "p-value" = pvalue, "CI lower" = ci.lower, "CI upper" = ci.upper) %>% 
  knitr::kable(caption = "Correlated intercepts and slopes", digits = 6) %>% 
  kable_styling() %>% 
  footnote(general = "i = intercept, s = slope, o = older sibling, y = younger sibling")
Correlated intercepts and slopes
Younger sibling Older sibling Beta SE Z p-value CI lower CI upper
iy io 0.314 0.0522 6.02 0.000000 0.2121 0.417
iy so -0.252 0.0729 -3.46 0.000536 -0.3954 -0.110
sy so 0.215 0.0893 2.41 0.015864 0.0404 0.390
Note:
i = intercept, s = slope, o = older sibling, y = younger sibling
semPaths(sibAG, what = "col", whatLabels = "est", intercepts = T)

Control CON

lgmCON <- '
#younger sibling
CON0y =~   CON_IN_y_p1  + p2 * CON_IN_y_p2   + p3 * CON_IN_y_p3
CON3y =~   CON_FU1_y_p1 + p2 * CON_FU1_y_p2  + p3 * CON_FU1_y_p3
CON7y =~   CON_FU2_y_p1 + p2 * CON_FU2_y_p2  + p3 * CON_FU2_y_p3
CON17y =~  CON_FU3_y_p1 + p2 * CON_FU3_y_p2  + p3 * CON_FU3_y_p3
                   
#older sibling
CON0o =~   CON_IN_o_p1  + p2 * CON_IN_o_p2   + p3 * CON_IN_o_p3
CON3o =~   CON_FU1_o_p1 + p2 * CON_FU1_o_p2  + p3 * CON_FU1_o_p3
CON7o =~   CON_FU2_o_p1 + p2 * CON_FU2_o_p2  + p3 * CON_FU2_o_p3
CON17o =~  CON_FU3_o_p1 + p2 * CON_FU3_o_p2  + p3 * CON_FU3_o_p3

#latent intercept and slopes
iy =~ 1*CON0y + 1*CON3y + 1*CON7y + 1*CON17y
io =~ 1*CON0o + 1*CON3o + 1*CON7o + 1*CON17o
sy =~ 0*CON0y + 3.3*CON3y + 7.6*CON7y + 17*CON17y
so =~ 0*CON0o + 3.3*CON3o + 7.6*CON7o + 17*CON17o
iy ~ 1
io ~ 1
sy ~ 1
so ~ 1

#fix zero latent intercepts
CON0y ~ 0*1
CON3y ~ 0*1
CON7y ~ 0*1
CON17y ~ 0*1
CON0o ~ 0*1
CON3o ~ 0*1
CON7o ~ 0*1
CON17o ~ 0*1

#fix zero/equal item intercepts
CON_IN_y_p1  ~ 0*1
CON_FU1_y_p1 ~ 0*1
CON_FU2_y_p1 ~ 0*1
CON_FU3_y_p1 ~ 0*1
CON_IN_o_p1  ~ 0*1
CON_FU1_o_p1 ~ 0*1
CON_FU2_o_p1 ~ 0*1
CON_FU3_o_p1 ~ 0*1

CON_IN_y_p2  ~ par2*1
CON_FU1_y_p2 ~ par2*1
CON_FU2_y_p2 ~ par2*1
CON_FU3_y_p2 ~ par2*1
CON_IN_o_p2  ~ par2*1
CON_FU1_o_p2 ~ par2*1
CON_FU2_o_p2 ~ par2*1
CON_FU3_o_p2 ~ par2*1

CON_IN_y_p3  ~ par3*1
CON_FU1_y_p3 ~ par3*1
CON_FU2_y_p3 ~ par3*1
CON_FU3_y_p3 ~ par3*1
CON_IN_o_p3  ~ par3*1
CON_FU1_o_p3 ~ par3*1
CON_FU2_o_p3 ~ par3*1
CON_FU3_o_p3 ~ par3*1

#residual covariances
CON_IN_y_p1 ~~ c(cov11)*CON_FU1_y_p1 + c(cov12)*CON_FU2_y_p1 + c(cov13)*CON_FU3_y_p1 
CON_FU1_y_p1 ~~ c(cov11)*CON_FU2_y_p1 + c(cov12)*CON_FU3_y_p1 
CON_FU2_y_p1 ~~ c(cov11)*CON_FU3_y_p1 

CON_IN_y_p2 ~~ c(cov21)*CON_FU1_y_p2 + c(cov22)*CON_FU2_y_p2 + c(cov23)*CON_FU3_y_p2 
CON_FU1_y_p2 ~~ c(cov21)*CON_FU2_y_p2 + c(cov22)*CON_FU3_y_p2 
CON_FU2_y_p2 ~~ c(cov21)*CON_FU3_y_p2 

CON_IN_y_p3 ~~ c(cov31)*CON_FU1_y_p3 + c(cov32)*CON_FU2_y_p3 + c(cov33)*CON_FU3_y_p3 
CON_FU1_y_p3 ~~ c(cov31)*CON_FU2_y_p3 + c(cov32)*CON_FU3_y_p3 
CON_FU2_y_p3 ~~ c(cov31)*CON_FU3_y_p3 

CON_IN_o_p1 ~~ c(cov11)*CON_FU1_o_p1 + c(cov12)*CON_FU2_o_p1 + c(cov13)*CON_FU3_o_p1 
CON_FU1_o_p1 ~~ c(cov11)*CON_FU2_o_p1 + c(cov12)*CON_FU3_o_p1 
CON_FU2_o_p1 ~~ c(cov11)*CON_FU3_o_p1 

CON_IN_o_p2 ~~ c(cov21)*CON_FU1_o_p2 + c(cov22)*CON_FU2_o_p2 + c(cov23)*CON_FU3_o_p2 
CON_FU1_o_p2 ~~ c(cov21)*CON_FU2_o_p2 + c(cov22)*CON_FU3_o_p2 
CON_FU2_o_p2 ~~ c(cov21)*CON_FU3_o_p2 

CON_IN_o_p3 ~~ c(cov31)*CON_FU1_o_p3 + c(cov32)*CON_FU2_o_p3 + c(cov33)*CON_FU3_o_p3 
CON_FU1_o_p3 ~~ c(cov31)*CON_FU2_o_p3 + c(cov32)*CON_FU3_o_p3 
CON_FU2_o_p3 ~~ c(cov31)*CON_FU3_o_p3 
'

sibCON <- sem(lgmCON, data = yo, missing = "FIML")

fitMeasures(sibCON, c("chisq", "df", "pvalue", "cfi", "rmsea", "srmr"), 
            output = "text")
## 
## Model Test User Model:
## 
##   Test statistic                               514.279
##   Degrees of freedom                               265
##   P-value                                        0.000
## 
## User Model versus Baseline Model:
## 
##   Comparative Fit Index (CFI)                    0.955
## 
## Root Mean Square Error of Approximation:
## 
##   RMSEA                                          0.039
## 
## Standardized Root Mean Square Residual:
## 
##   SRMR                                           0.163
as.data.frame(unclass(standardizedSolution(sibCON))) %>% 
  filter(op == "~1" & lhs %in% c("iy", "io", "sy", "so")) %>% 
  select("Parameters" = lhs, Beta = est.std, SE = se, Z = z, "p-value" = pvalue, "CI lower" = ci.lower, "CI upper" = ci.upper) %>% 
  knitr::kable(caption = "Intercept and Slope", digits = 6) %>% 
  kable_styling() %>% 
  footnote(general = "i = intercept, s = slope, o = older sibling, y = younger sibling")
Intercept and Slope
Parameters Beta SE Z p-value CI lower CI upper
iy 8.01 0.437 18.31 0.000000 7.152 8.87
io 6.67 0.310 21.52 0.000000 6.064 7.28
sy 1.68 0.496 3.38 0.000724 0.705 2.65
so 1.60 0.681 2.35 0.018653 0.267 2.94
Note:
i = intercept, s = slope, o = older sibling, y = younger sibling
as.data.frame(unclass(standardizedSolution(sibCON))) %>% 
  filter(op == "~~" & lhs %in% c("sy", "iy") & rhs %in% c("so", "io") & z < 1.324) %>% 
  select("Younger sibling" = lhs, "Older sibling" = rhs, Beta = est.std, SE = se, Z = z, "p-value" = pvalue, "CI lower" = ci.lower, "CI upper" = ci.upper) %>% 
  knitr::kable(caption = "Correlated intercepts and slopes", digits = 6) %>% 
  kable_styling() %>% 
  footnote(general = "i = intercept, s = slope, o = older sibling, y = younger sibling")
Correlated intercepts and slopes
Younger sibling Older sibling Beta SE Z p-value CI lower CI upper
iy io -0.00522 0.0634 -0.0823 0.934 -0.129 0.119
iy so 0.15649 0.1328 1.1786 0.239 -0.104 0.417
sy so -0.35653 0.2607 -1.3676 0.171 -0.867 0.154
Note:
i = intercept, s = slope, o = older sibling, y = younger sibling
semPaths(sibCON, what = "col", whatLabels = "est", intercepts = T)

Harm Avoidance HA

lgmHA <- '
#younger sibling
HA0y =~   HA_IN_y_p1  + p2 * HA_IN_y_p2   + p3 * HA_IN_y_p3
HA3y =~   HA_FU1_y_p1 + p2 * HA_FU1_y_p2  + p3 * HA_FU1_y_p3
HA7y =~   HA_FU2_y_p1 + p2 * HA_FU2_y_p2  + p3 * HA_FU2_y_p3
HA17y =~  HA_FU3_y_p1 + p2 * HA_FU3_y_p2  + p3 * HA_FU3_y_p3
                   
#older sibling
HA0o =~   HA_IN_o_p1  + p2 * HA_IN_o_p2   + p3 * HA_IN_o_p3
HA3o =~   HA_FU1_o_p1 + p2 * HA_FU1_o_p2  + p3 * HA_FU1_o_p3
HA7o =~   HA_FU2_o_p1 + p2 * HA_FU2_o_p2  + p3 * HA_FU2_o_p3
HA17o =~  HA_FU3_o_p1 + p2 * HA_FU3_o_p2  + p3 * HA_FU3_o_p3

#latent intercept and slopes
iy =~ 1*HA0y + 1*HA3y + 1*HA7y + 1*HA17y
io =~ 1*HA0o + 1*HA3o + 1*HA7o + 1*HA17o
sy =~ 0*HA0y + 3.3*HA3y + 7.6*HA7y + 17*HA17y
so =~ 0*HA0o + 3.3*HA3o + 7.6*HA7o + 17*HA17o
iy ~ 1
io ~ 1
sy ~ 1
so ~ 1

#fix zero latent intercepts
HA0y ~ 0*1
HA3y ~ 0*1
HA7y ~ 0*1
HA17y ~ 0*1
HA0o ~ 0*1
HA3o ~ 0*1
HA7o ~ 0*1
HA17o ~ 0*1

#fix zero/equal item intercepts
HA_IN_y_p1  ~ 0*1
HA_FU1_y_p1 ~ 0*1
HA_FU2_y_p1 ~ 0*1
HA_FU3_y_p1 ~ 0*1
HA_IN_o_p1  ~ 0*1
HA_FU1_o_p1 ~ 0*1
HA_FU2_o_p1 ~ 0*1
HA_FU3_o_p1 ~ 0*1

HA_IN_y_p2  ~ par2*1
HA_FU1_y_p2 ~ par2*1
HA_FU2_y_p2 ~ par2*1
HA_FU3_y_p2 ~ par2*1
HA_IN_o_p2  ~ par2*1
HA_FU1_o_p2 ~ par2*1
HA_FU2_o_p2 ~ par2*1
HA_FU3_o_p2 ~ par2*1

HA_IN_y_p3  ~ par3*1
HA_FU1_y_p3 ~ par3*1
HA_FU2_y_p3 ~ par3*1
HA_FU3_y_p3 ~ par3*1
HA_IN_o_p3  ~ par3*1
HA_FU1_o_p3 ~ par3*1
HA_FU2_o_p3 ~ par3*1
HA_FU3_o_p3 ~ par3*1

#residual covariances
HA_IN_y_p1 ~~ c(cov11)*HA_FU1_y_p1 + c(cov12)*HA_FU2_y_p1 + c(cov13)*HA_FU3_y_p1 
HA_FU1_y_p1 ~~ c(cov11)*HA_FU2_y_p1 + c(cov12)*HA_FU3_y_p1 
HA_FU2_y_p1 ~~ c(cov11)*HA_FU3_y_p1 

HA_IN_y_p2 ~~ c(cov21)*HA_FU1_y_p2 + c(cov22)*HA_FU2_y_p2 + c(cov23)*HA_FU3_y_p2 
HA_FU1_y_p2 ~~ c(cov21)*HA_FU2_y_p2 + c(cov22)*HA_FU3_y_p2 
HA_FU2_y_p2 ~~ c(cov21)*HA_FU3_y_p2 

HA_IN_y_p3 ~~ c(cov31)*HA_FU1_y_p3 + c(cov32)*HA_FU2_y_p3 + c(cov33)*HA_FU3_y_p3 
HA_FU1_y_p3 ~~ c(cov31)*HA_FU2_y_p3 + c(cov32)*HA_FU3_y_p3 
HA_FU2_y_p3 ~~ c(cov31)*HA_FU3_y_p3 

HA_IN_o_p1 ~~ c(cov11)*HA_FU1_o_p1 + c(cov12)*HA_FU2_o_p1 + c(cov13)*HA_FU3_o_p1 
HA_FU1_o_p1 ~~ c(cov11)*HA_FU2_o_p1 + c(cov12)*HA_FU3_o_p1 
HA_FU2_o_p1 ~~ c(cov11)*HA_FU3_o_p1 

HA_IN_o_p2 ~~ c(cov21)*HA_FU1_o_p2 + c(cov22)*HA_FU2_o_p2 + c(cov23)*HA_FU3_o_p2 
HA_FU1_o_p2 ~~ c(cov21)*HA_FU2_o_p2 + c(cov22)*HA_FU3_o_p2 
HA_FU2_o_p2 ~~ c(cov21)*HA_FU3_o_p2 

HA_IN_o_p3 ~~ c(cov31)*HA_FU1_o_p3 + c(cov32)*HA_FU2_o_p3 + c(cov33)*HA_FU3_o_p3 
HA_FU1_o_p3 ~~ c(cov31)*HA_FU2_o_p3 + c(cov32)*HA_FU3_o_p3 
HA_FU2_o_p3 ~~ c(cov31)*HA_FU3_o_p3 
'

sibHA <- sem(lgmHA, data = yo, missing = "FIML")

fitMeasures(sibHA, c("chisq", "df", "pvalue", "cfi", "rmsea", "srmr"), 
            output = "text")
## 
## Model Test User Model:
## 
##   Test statistic                               757.383
##   Degrees of freedom                               265
##   P-value                                        0.000
## 
## User Model versus Baseline Model:
## 
##   Comparative Fit Index (CFI)                    0.900
## 
## Root Mean Square Error of Approximation:
## 
##   RMSEA                                          0.055
## 
## Standardized Root Mean Square Residual:
## 
##   SRMR                                           0.163
as.data.frame(unclass(standardizedSolution(sibHA))) %>% 
  filter(op == "~1" & lhs %in% c("iy", "io", "sy", "so")) %>% 
  select("Parameters" = lhs, Beta = est.std, SE = se, Z = z, "p-value" = pvalue, "CI lower" = ci.lower, "CI upper" = ci.upper) %>% 
  knitr::kable(caption = "Intercept and Slope", digits = 6) %>% 
  kable_styling() %>% 
  footnote(general = "i = intercept, s = slope, o = older sibling, y = younger sibling")
Intercept and Slope
Parameters Beta SE Z p-value CI lower CI upper
iy 6.162 0.361 17.07 0.000000 5.455 6.87
io 4.942 0.222 22.26 0.000000 4.506 5.38
sy 0.884 0.158 5.59 0.000000 0.574 1.19
so 1.060 0.284 3.73 0.000193 0.503 1.62
Note:
i = intercept, s = slope, o = older sibling, y = younger sibling
as.data.frame(unclass(standardizedSolution(sibHA))) %>% 
  filter(op == "~~" & lhs %in% c("sy", "iy") & rhs %in% c("so", "io")) %>% 
  select("Younger sibling" = lhs, "Older sibling" = rhs, Beta = est.std, SE = se, Z = z, "p-value" = pvalue, "CI lower" = ci.lower, "CI upper" = ci.upper) %>% 
  knitr::kable(caption = "Correlated intercepts and slopes", digits = 6) %>% 
  kable_styling() %>% 
  footnote(general = "i = intercept, s = slope, o = older sibling, y = younger sibling")
Correlated intercepts and slopes
Younger sibling Older sibling Beta SE Z p-value CI lower CI upper
iy io 0.3276 0.0613 5.347 0.000 0.207 0.4476
iy so -0.1295 0.0996 -1.300 0.194 -0.325 0.0657
sy so 0.0782 0.1094 0.715 0.475 -0.136 0.2926
Note:
i = intercept, s = slope, o = older sibling, y = younger sibling
semPaths(sibHA, what = "col", whatLabels = "est", intercepts = T)

Adoption status

Adoption status - Aggression AG

# extract latent intercepts and slopes
adoptAG <- lavPredict(sibAG) %>%
  as.data.frame() %>%
  select(iy, io, sy, so)

# scale all variables
adoptAG <- scale(adoptAG, scale = F) %>% as.data.frame()

# add adoption variable
adoptAG$adopt <- factor(yo$adopt, levels = c(0,1), 
                        labels = c("non-adoptive", "adoptive"))

# moderation
summary(lm(iy ~ io * adopt, data = adoptAG))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Aggression intercept ", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Aggression intercept
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.056 0.026 2.18 0.029
io 0.501 0.059 8.47 0.000
adoptadoptive -0.082 0.032 -2.59 0.010
io:adoptadoptive -0.216 0.072 -3.01 0.003
summary(lm(sy ~ so * adopt, data = adoptAG))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Aggression slope ", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Aggression slope
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.002 0.001 -1.750 0.081
so 0.292 0.057 5.154 0.000
adoptadoptive 0.003 0.001 2.194 0.029
so:adoptadoptive -0.048 0.069 -0.705 0.481
# interaction plot
plot_model(lm(iy ~ io * adopt, data = adoptAG), 
           type = "int",
           axis.title = c("Older sibling", "Younger sibling"),
           title = "Aggression intercept using Adoption status") +
  theme_classic()

Adoption status - Control CON

# extract latent intercepts and slopes
adoptCON <- lavPredict(sibCON) %>%
  as.data.frame() %>%
  select(iy, io, sy, so)

# scale all variables
adoptCON <- scale(adoptCON, scale = F) %>% as.data.frame()

# add adoption variable
adoptCON$adopt <- factor(yo$adopt, levels = c(0,1), 
                         labels = c("non-adoptive", "adoptive"))

# moderation
summary(lm(iy ~ io * adopt, data = adoptCON))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Control intercept ", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Control intercept
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.013 0.018 -0.684 0.494
io 0.059 0.058 1.012 0.312
adoptadoptive 0.019 0.023 0.821 0.412
io:adoptadoptive -0.074 0.069 -1.062 0.289
summary(lm(sy ~ so * adopt, data = adoptCON))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Control slope ", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Control slope
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.000 0.730 0.466
so -0.502 0.056 -8.957 0.000
adoptadoptive 0.000 0.001 -0.879 0.380
so:adoptadoptive 0.077 0.067 1.151 0.250

Adoption status - Harm Avoidance HA

# extract latent intercepts and slopes
adoptHA <- lavPredict(sibHA) %>%
  as.data.frame() %>%
  select(iy, io, sy, so)

# scale all variables
adoptHA <- scale(adoptHA, scale = F) %>% as.data.frame()

# add adoption variable
adoptHA$adopt <- factor(yo$adopt, levels = c(0,1), 
                        labels = c("non-adoptive", "adoptive"))

# moderation
summary(lm(iy ~ io * adopt, data = adoptHA))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Harm Avoidance intercept ", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Harm Avoidance intercept
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.068 0.021 -3.25 0.001
io 0.443 0.045 9.80 0.000
adoptadoptive 0.106 0.026 4.09 0.000
io:adoptadoptive -0.201 0.056 -3.60 0.000
summary(lm(sy ~ so * adopt, data = adoptHA))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Harm Avoidance slope ", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Harm Avoidance slope
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.001 0.001 -0.558 0.577
so 0.096 0.068 1.417 0.157
adoptadoptive 0.001 0.001 0.705 0.481
so:adoptadoptive 0.042 0.086 0.492 0.623
# interaction plot
plot_model(lm(iy ~ io * adopt, data = adoptHA), 
           type = "int",
           axis.title = c("Older sibling", "Younger sibling"),
           title = "Harm Avoidance intercept using Adoption status") +
  theme_classic()

Sex similarity

Sex similarity - Aggression AG

# extract latent intercepts and slopes
sexAG <- lavPredict(sibAG) %>%
  as.data.frame() %>%
  select(iy, io, sy, so)

# scale all variables
sexAG <- scale(sexAG, scale = F) %>% as.data.frame()

# add adoption variable
sexAG$samesex <- factor(yo$samesex, levels = c(0,1), 
                        labels = c("different-sex", "same-sex"))

# moderation
summary(lm(iy ~ io * samesex, data = sexAG))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Aggression intercept ", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Aggression intercept
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.010 0.024 0.396 0.692
io 0.187 0.056 3.357 0.001
samesexsame-sex -0.013 0.031 -0.407 0.684
io:samesexsame-sex 0.258 0.070 3.693 0.000
summary(lm(sy ~ so * samesex, data = sexAG))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Aggression slope ", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Aggression slope
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.001 0.325 0.745
so 0.300 0.054 5.515 0.000
samesexsame-sex -0.001 0.001 -0.421 0.674
so:samesexsame-sex -0.055 0.067 -0.811 0.418
# interaction plot
plot_model(lm(iy ~ io * samesex, data = sexAG), 
           type = "int",
           axis.title = c("Older sibling", "Younger sibling"),
           title = "Aggression intercept using Sex similarity") +
  theme_classic()

Sex similarity - Control CON

# extract latent intercepts and slopes
sexCON <- lavPredict(sibCON) %>%
  as.data.frame() %>%
  select(iy, io, sy, so)

# scale all variables
sexCON <- scale(sexCON, scale = F) %>% as.data.frame()

# add adoption variable
sexCON$samesex <- factor(yo$samesex, levels = c(0,1), 
                        labels = c("different-sex", "same-sex"))

# moderation
summary(lm(iy ~ io * samesex, data = sexCON))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Control intercept ", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Control intercept
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.018 0.017 -1.044 0.297
io 0.029 0.049 0.594 0.553
samesexsame-sex 0.030 0.022 1.348 0.178
io:samesexsame-sex -0.040 0.064 -0.630 0.529
summary(lm(sy ~ so * samesex, data = sexCON))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Control slope ", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Control slope
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.000 -0.234 0.815
so -0.456 0.046 -9.838 0.000
samesexsame-sex 0.000 0.001 0.303 0.762
so:samesexsame-sex 0.015 0.061 0.253 0.800

Sex similarity - Harm Avoidance

# extract latent intercepts and slopes
sexHA <- lavPredict(sibHA) %>%
  as.data.frame() %>%
  select(iy, io, sy, so)

# scale all variables
sexHA <- scale(sexHA, scale = F) %>% as.data.frame()

# add adoption variable
sexHA$samesex <- factor(yo$samesex, levels = c(0,1), 
                        labels = c("different-sex", "same-sex"))

# moderation
summary(lm(iy ~ io * samesex, data = sexHA))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Harm Avoidance intercept ", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Harm Avoidance intercept
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.031 0.020 1.55 0.122
io 0.278 0.044 6.32 0.000
samesexsame-sex -0.053 0.026 -2.07 0.039
io:samesexsame-sex 0.069 0.056 1.23 0.219
summary(lm(sy ~ so * samesex, data = sexHA))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Harm Avoidance slope ", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Harm Avoidance slope
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.001 0.001 0.534 0.593
so 0.011 0.061 0.182 0.856
samesexsame-sex -0.001 0.001 -0.692 0.489
so:samesexsame-sex 0.206 0.083 2.469 0.014
# interaction plot
plot_model(lm(sy ~ so * samesex, data = sexHA), 
           type = "int",
           axis.title = c("Older sibling", "Younger sibling"),
           title = "Harm Avoidance slope using Sex similarity") +
  theme_classic()

Age gap

Here, we examined whether a smaller age gap between siblings would result in higher correlated change patterns compared to siblings who are further apart in age.

In order to fit the latent interaction model, factor scores for the latent intercepts and slopes are extracted from the LGM of general change using full data. All variables are then mean-centered.

# descriptives
yo$gap <- yo$IN_AGE_o - yo$IN_AGE_y
yo$gap %>% 
  descr(stats = "common", order = "p")
## Descriptive Statistics  
## yo$gap  
## N: 614  
## 
##                      gap
## --------------- --------
##            Mean     2.34
##         Std.Dev     0.89
##             Min     0.04
##          Median     2.26
##             Max     4.93
##         N.Valid   606.00
##       Pct.Valid    98.70
# histogram
ggplot(data = yo, aes(gap)) +
  geom_histogram(binwidth = 0.1, fill = "#710c0c") + 
  geom_vline(xintercept = mean(yo$gap, na.rm = T),
             color = "#f1c232", size = 1) +
  annotate("text", 
           label = paste0("Mean = ", round(mean(yo$gap, na.rm = T), 2),
                          ", SD = ",round(sd(yo$gap, na.rm = T), 2)),
           x = 4, y = 20) + 
  labs(
    title = "Distribution of Between-Sibling Age Gap",
    x = "Age Gap (in years)",
    y = NULL
  ) +
  theme_classic()

Age gap - Aggression AG

Age gap did not moderate the relationship between sibling Aggression scores or change over time.

# extract latent intercepts and slopes
ageAG <- lavPredict(sibAG) %>%
  as.data.frame() %>%
  select(iy, io, sy, so)
ageAG$gap <- yo$gap

# scale all variables
ageAG <- scale(ageAG, scale = F) %>% as.data.frame()

# moderation
summary(lm(iy ~ io * gap, data = ageAG))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Aggression intercept ", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Aggression intercept
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.001 0.015 -0.082 0.935
io 0.351 0.034 10.289 0.000
gap -0.026 0.017 -1.516 0.130
io:gap -0.034 0.038 -0.888 0.375
summary(lm(sy ~ so * gap, data = ageAG))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Aggression slope ", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Aggression slope
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.001 0.108 0.914
so 0.268 0.033 8.209 0.000
gap 0.001 0.001 1.220 0.223
so:gap 0.004 0.036 0.107 0.914

Age gap - Control CON

Age gap did not moderate the relationship between sibling Control scores, but it did moderate their correlated change over time \((B = -0.075, SE = 0.035, t = -2.16, p = 0.031)\). Siblings who are further apart in age showed more strongly negative correlated change in Control over time.

# extract latent intercepts and slopes
ageCON <- lavPredict(sibCON) %>%
  as.data.frame() %>%
  select(iy, io, sy, so)
ageCON$gap <- yo$gap

# scale all variables
ageCON <- scale(ageCON, scale = F) %>% as.data.frame()

# moderation
summary(lm(iy ~ io * gap, data = ageCON))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Control intercept ", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Control intercept
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.011 0.014 0.989
io 0.011 0.031 0.364 0.716
gap 0.009 0.012 0.786 0.432
io:gap -0.007 0.035 -0.198 0.843
summary(lm(sy ~ so * gap, data = ageCON))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Control slope ", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Control slope
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.000 -0.094 0.925
so -0.447 0.030 -14.786 0.000
gap 0.000 0.000 -0.927 0.354
so:gap -0.075 0.035 -2.160 0.031
# interaction plot at minimum and maximum age gap
plot_model(lm(sy ~ so * gap, data = ageCON), 
           type = "int",
           axis.title = c("Older sibling", "Younger sibling"),
           title = "Change in Control over time") +
  theme_classic()

Age gap - Harm Avoidance HA

Age gap did not moderate the relationship between sibling Harm Avoidance scores or change over time.

Interestingly, age gap was a significant predictor of Harm Avoidance score such that younger siblings had higher average HA scores with higher between-sibling age gaps \((B = 0.038, SE = 0.014, t = 2.70, p = 0.007)\).

# extract latent intercepts and slopes
ageHA <- lavPredict(sibHA) %>%
  as.data.frame() %>%
  select(iy, io, sy, so)
ageHA$gap <- yo$gap

# scale all variables
ageHA <- scale(ageHA, scale = F) %>% as.data.frame()

# moderation
summary(lm(iy ~ io * gap, data = ageHA))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Harm Avoidance intercept ", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Harm Avoidance intercept
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.001 0.013 0.047 0.962
io 0.310 0.027 11.384 0.000
gap 0.038 0.014 2.696 0.007
io:gap -0.046 0.029 -1.576 0.115
summary(lm(sy ~ so * gap, data = ageHA))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Harm Avoidance sllope ", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Harm Avoidance sllope
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.001 0.013 0.989
so 0.124 0.042 2.936 0.003
gap 0.001 0.001 0.721 0.471
so:gap -0.069 0.052 -1.314 0.189

Relationship quality

Sibling relationship was measured by the Sibling Relationship Questionnaire (SRQ; Furman, & Buhrmester, 1985). The scale has 48 items. We excluded items 2, 18, 34 (subscale maternal partiality), and items 7, 23, 39 (subscale paternal partiality) during data collection. This was measured at the first two waves: IN and FU1. There are a total of 14 subscales, each with 3 items, and they can be organized into 3 (overlapping) factors. The original paper included a 4th factor, Rivalry, which consists of Competition and Parental partiality (which we did not measure).

  1. Warmth/Closeness:
  • Initimacy
  • Prosocial behavior
  • Companionship
  • Similarity
  • Nurturance of sibling
  • Nurturance by sibling
  • Admiration of sibling
  • Admiration by sibling
  • Affection
  1. Relative status/power:
  • Nurturance by sibling (R)
  • Nurturance of sibling
  • Admiration by sibling
  • Admiration of sibling (R)
  • Dominance by sibling (R)
  • Dominance over sibling
  1. Conflict:
  • Admiration by sibling (R)
  • Affection (R)
  • Dominance by sibling
  • Dominance over sibling
  • Quarreling
  • Antagonism
  • Competition
# descriptives
mpq %>% 
  select(S_PROSOC:S_QUARR) %>% 
  descr(stats = "common", order = "p")
## Descriptive Statistics  
## mpq  
## N: 1231  
## 
##                   S_PROSOC   S_YNURE   S_ENURY   S_YDOME   S_EDOMY   S_AFFECT   S_COMPAN   S_ANTAG
## --------------- ---------- --------- --------- --------- --------- ---------- ---------- ---------
##            Mean       3.06      2.93      2.83      2.33      2.30       3.83       2.94      2.72
##         Std.Dev       0.70      0.77      0.84      0.86      0.84       0.89       0.87      0.86
##             Min       1.00      1.00      1.00      1.00      1.00       1.00       1.00      1.00
##          Median       3.00      3.00      3.00      2.33      2.33       4.00       3.00      2.67
##             Max       5.00      5.00      5.00      5.00      5.00       5.00       5.00      5.00
##         N.Valid    1219.00   1219.00   1219.00   1219.00   1219.00    1217.00    1217.00   1217.00
##       Pct.Valid      99.03     99.03     99.03     99.03     99.03      98.86      98.86     98.86
## 
## Table: Table continues below
## 
##  
## 
##                   S_SIMLR   S_INTIM   S_COMPET   S_YADME   S_EADMY   S_QUARR
## --------------- --------- --------- ---------- --------- --------- ---------
##            Mean      2.85      2.38       2.49      3.45      3.17      2.81
##         Std.Dev      0.88      1.05       0.93      0.91      0.90      0.92
##             Min      1.00      1.00       1.00      1.00      1.00      1.00
##          Median      3.00      2.33       2.33      3.67      3.00      3.00
##             Max      5.00      5.00       5.00      5.00      5.00      5.00
##         N.Valid   1217.00   1217.00    1217.00   1217.00   1215.00   1216.00
##       Pct.Valid     98.86     98.86      98.86     98.86     98.70     98.78

We will use relationship quality data at intake for all participants. However, there are 26 participants who did not have relationship data at IN but had FU1 data that will be used instead.

Explanatory factor analysis

We ran an explanatory factor analysis to examine the factor structure and extract factor scores.

This resulted in two main factors, similarly for younger and older siblings:

Factor 1 resembles the original paper’s Warmth/Closeness; Factor 2 resembles Conflict.

# younger siblings
efa_y <- yo %>% 
  select(IDYRFAM, starts_with("S_")) %>%
  select(IDYRFAM, ends_with("_y")) %>%
  na.omit()

scree(efa_y[, -1], pc = FALSE, main = "Scree plot for younger siblings")

efa_fit_y <- factanal(efa_y[, -1], 2, rotation = "promax", 
                  score = "Bartlett")
print(efa_fit_y$loadings, digits = 3, cutoff = 0.3, sort = T)
## 
## Loadings:
##            Factor1 Factor2
## S_PROSOC_y  0.836         
## S_YNURE_y   0.644         
## S_ENURY_y   0.755         
## S_AFFECT_y  0.737         
## S_COMPAN_y  0.815         
## S_SIMLR_y   0.689         
## S_INTIM_y   0.749         
## S_YADME_y   0.749         
## S_EADMY_y   0.751         
## S_YDOME_y           0.505 
## S_EDOMY_y           0.611 
## S_ANTAG_y           0.846 
## S_COMPET_y          0.512 
## S_QUARR_y           0.835 
## 
##                Factor1 Factor2
## SS loadings      5.220   2.408
## Proportion Var   0.373   0.172
## Cumulative Var   0.373   0.545
# older siblings
efa_o <- yo %>% 
  select(IDYRFAM, starts_with("S_")) %>%
  select(IDYRFAM, ends_with("_o")) %>%
  na.omit()

scree(efa_o[, -1], pc = FALSE, main = "Scree plot for older siblings")

efa_fit_o <- factanal(efa_o[, -1], 2, rotation = "promax", 
                  score = "Bartlett")
print(efa_fit_o$loadings, digits = 3, cutoff = 0.3, sort = T)
## 
## Loadings:
##            Factor1 Factor2
## S_PROSOC_o  0.850         
## S_YNURE_o   0.748         
## S_ENURY_o   0.745         
## S_AFFECT_o  0.769         
## S_COMPAN_o  0.820         
## S_SIMLR_o   0.729         
## S_INTIM_o   0.721         
## S_YADME_o   0.764         
## S_EADMY_o   0.736         
## S_YDOME_o           0.656 
## S_ANTAG_o           0.828 
## S_COMPET_o          0.604 
## S_QUARR_o           0.840 
## S_EDOMY_o           0.434 
## 
##                Factor1 Factor2
## SS loadings       5.47   2.464
## Proportion Var    0.39   0.176
## Cumulative Var    0.39   0.566

Relationship - Aggression AG

1. Using younger sibling’s relationship ratings:

There were significant interaction effects between relationship quality and sibling similarity in Aggression, but not in changes in Aggression over time.

In particular, there was a stronger between-sibling correlation in Aggression when the younger sibling indicated higher Warmth/Closeness scores, \(B = 0.081, SE = 0.030, t = 2.724, p = 0.007\). Interestingly, between-sibling correlation in Aggression was also stronger when the younger sibling indicated higher Conflict scores, \(B = 0.057, SE = 0.028, t = 2.057, p = 0.040\).

Further, younger sibling’s Conflict scores were associated with their own higher Aggression intercept \((B = 0.088, SE = 0.014, t = 6.234, p < 0.001)\) and slower decrease in Aggression over time \((B = -0.003, SE = =.001, t = -5.097, p < 0.001)\).

#### younger siblings

# merge rela scores with latent intercepts and slopes
relaAG_y <- cbind(ageAG, yo$IDYRFAM)
efa_y <- cbind(efa_y$IDYRFAM, efa_fit_y$scores)
colnames(efa_y)[1] <- colnames(relaAG_y)[6] <- "IDYRFAM"
relaAG_y <- merge(relaAG_y, efa_y)

# scale all variables
relaAG_y <- scale(relaAG_y[, -1], scale = F) %>% as.data.frame()

# moderation
summary(lm(iy ~ io * Factor1, data = relaAG_y))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Aggression intercept using younger sibling's Warmth ratings", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Aggression intercept using younger sibling’s Warmth ratings
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.007 0.015 0.447 0.655
io 0.344 0.035 9.898 0.000
Factor1 -0.026 0.015 -1.708 0.088
io:Factor1 0.081 0.030 2.724 0.007
summary(lm(iy ~ io * Factor2, data = relaAG_y))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Aggression intercept using younger sibling's Conflict ratings", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Aggression intercept using younger sibling’s Conflict ratings
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.004 0.015 -0.276 0.783
io 0.321 0.034 9.571 0.000
Factor2 0.088 0.014 6.234 0.000
io:Factor2 0.057 0.028 2.057 0.040
summary(lm(sy ~ so * Factor1, data = relaAG_y))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Aggression slope using younger sibling's Warmth ratings", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Aggression slope using younger sibling’s Warmth ratings
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.001 -0.149 0.882
so 0.263 0.032 8.103 0.000
Factor1 0.001 0.001 1.027 0.305
so:Factor1 0.045 0.029 1.533 0.126
summary(lm(sy ~ so * Factor2, data = relaAG_y))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Aggression slope using younger sibling's Conflict ratings", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Aggression slope using younger sibling’s Conflict ratings
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.001 0.029 0.977
so 0.249 0.032 7.792 0.000
Factor2 -0.003 0.001 -5.097 0.000
so:Factor2 0.010 0.029 0.338 0.735
# interaction plot at minimum and maximum relationship ratings
plot_model(lm(iy ~ io * Factor1, data = relaAG_y), 
           type = "int",
           axis.title = c("Older sibling", "Younger sibling"),
           title = "Aggression intercept using younger sibling's Warmth ratings") +
  theme_classic()

plot_model(lm(iy ~ io * Factor2, data = relaAG_y), 
           type = "int",
           axis.title = c("Older sibling", "Younger sibling"),
           title = "Aggression intercept using younger sibling's Conflict ratings") +
  theme_classic()

2. Using older sibling’s relationship ratings:

Results were different when we used older sibling’s relationship ratings. The only significant interaction effect was to predict Aggression intercept. In particular, there was a higher between-sibling correlation in Aggression when the older sibling provided higher Warmth scores, \(B = 0.104, SE = 0.031, t = 3.303, p = 0.001\). Older siblings’ ratings of Warmth and Conflict did not have any association with correlated change in Aggression.

#### older siblings

# merge rela scores with latent intercepts and slopes
relaAG_o <- cbind(ageAG, yo$IDYRFAM)
efa_o <- cbind(efa_o$IDYRFAM, efa_fit_o$scores)
colnames(efa_o)[1] <- colnames(relaAG_o)[6] <- "IDYRFAM"
relaAG_o <- merge(relaAG_o, efa_o)

# scale all variables
relaAG_o <- scale(relaAG_o[, -1], scale = F) %>% as.data.frame()

# moderation
summary(lm(iy ~ io * Factor1, data = relaAG_o))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Aggression intercept using older sibling's Warmth ratings", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Aggression intercept using older sibling’s Warmth ratings
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.012 0.016 0.765 0.445
io 0.362 0.035 10.301 0.000
Factor1 0.006 0.015 0.409 0.683
io:Factor1 0.104 0.031 3.303 0.001
summary(lm(iy ~ io * Factor2, data = relaAG_o))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Aggression intercept using older sibling's Conflict ratings", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Aggression intercept using older sibling’s Conflict ratings
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.004 0.016 -0.273 0.785
io 0.330 0.037 8.898 0.000
Factor2 0.022 0.016 1.398 0.163
io:Factor2 0.025 0.029 0.834 0.405
summary(lm(sy ~ so * Factor1, data = relaAG_o))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Aggression slope using older sibling's Warmth ratings", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Aggression slope using older sibling’s Warmth ratings
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.001 -0.244 0.807
so 0.278 0.033 8.492 0.000
Factor1 -0.002 0.001 -2.381 0.018
so:Factor1 0.043 0.030 1.402 0.161
summary(lm(sy ~ so * Factor2, data = relaAG_o))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Aggression slope using older sibling's Conflict ratings", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Aggression slope using older sibling’s Conflict ratings
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.001 0.186 0.852
so 0.242 0.033 7.283 0.000
Factor2 -0.002 0.001 -2.572 0.010
so:Factor2 0.027 0.031 0.877 0.381
# interaction plot at minimum and maximum relationship ratings
plot_model(lm(iy ~ io * Factor1, data = relaAG_o), 
           type = "int",
           axis.title = c("Older sibling", "Younger sibling"),
           title = "Aggression intercept using older sibling's Warmth ratings") +
  theme_classic()

Relationship - Control CON

1. Using younger sibling’s relationship ratings:

Relationship quality, as rated by the younger siblings, had no association with between-sibling correlation in Control scores or changes in Control over time.

Younger siblings’ ratings of Warmth was associated with higher intercepts of their own Control scores \((B = 0.036, SE = 0.010, t = 3.478, p = 0.001)\) but also a slower increase in their Control scores over time \((B = -0.001, SE = 0.00, t = -2.036, p = 0.042)\).

#### younger siblings

# merge rela scores with latent intercepts and slopes
relaCON_y <- cbind(ageCON, yo$IDYRFAM)
colnames(relaCON_y)[6] <- "IDYRFAM"
relaCON_y <- merge(relaCON_y, efa_y)

# scale all variables
relaCON_y <- scale(relaCON_y[, -1], scale = F) %>% as.data.frame()

# moderation
summary(lm(iy ~ io * Factor1, data = relaCON_y))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Control intercept using younger sibling's relationship ratings", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Control intercept using younger sibling’s relationship ratings
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.001 0.011 -0.058 0.953
io -0.008 0.032 -0.256 0.798
Factor1 0.036 0.010 3.478 0.001
io:Factor1 0.017 0.029 0.590 0.556
summary(lm(iy ~ io * Factor2, data = relaCON_y))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Control intercept using younger sibling's relationship ratings", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Control intercept using younger sibling’s relationship ratings
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.001 0.011 -0.130 0.897
io -0.018 0.031 -0.567 0.571
Factor2 -0.057 0.010 -5.731 0.000
io:Factor2 -0.040 0.027 -1.492 0.136
summary(lm(sy ~ so * Factor1, data = relaCON_y))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Control slope using younger sibling's relationship ratings", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Control slope using younger sibling’s relationship ratings
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.00 0.033 0.974
so -0.454 0.03 -14.944 0.000
Factor1 -0.001 0.00 -2.036 0.042
so:Factor1 0.016 0.03 0.525 0.600
summary(lm(sy ~ so * Factor2, data = relaCON_y))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Control slope using younger sibling's relationship ratings", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Control slope using younger sibling’s relationship ratings
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.000 -0.004 0.997
so -0.449 0.030 -14.932 0.000
Factor2 0.001 0.000 3.793 0.000
so:Factor2 -0.016 0.028 -0.590 0.555

2. Using older sibling’s relationship ratings:

Similarly to younger siblings’ ratings, older siblings’ ratings of relationship quality had no association with between-sibling correlation in Control scores or changes in Control over time.

#### older siblings

# merge rela scores with latent intercepts and slopes
relaCON_o <- cbind(ageCON, yo$IDYRFAM)
colnames(relaCON_o)[6] <- "IDYRFAM"
relaCON_o <- merge(relaCON_o, efa_o)

# scale all variables
relaCON_o <- scale(relaCON_o[, -1], scale = F) %>% as.data.frame()

# moderation
summary(lm(iy ~ io * Factor1, data = relaCON_o))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Control intercept using older sibling's relationship ratings", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Control intercept using older sibling’s relationship ratings
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.001 0.011 -0.128 0.899
io -0.004 0.032 -0.134 0.893
Factor1 0.018 0.011 1.633 0.103
io:Factor1 0.022 0.028 0.784 0.434
summary(lm(iy ~ io * Factor2, data = relaCON_o))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Control intercept using older sibling's relationship ratings", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Control intercept using older sibling’s relationship ratings
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.002 0.011 -0.156 0.876
io -0.013 0.032 -0.402 0.688
Factor2 -0.032 0.010 -3.063 0.002
io:Factor2 -0.025 0.028 -0.867 0.387
summary(lm(sy ~ so * Factor1, data = relaCON_o))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Control slope using older sibling's relationship ratings", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Control slope using older sibling’s relationship ratings
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.000 0.021 0.983
so -0.453 0.031 -14.622 0.000
Factor1 0.000 0.000 -0.452 0.651
so:Factor1 0.004 0.028 0.147 0.883
summary(lm(sy ~ so * Factor2, data = relaCON_o))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Control slope using older sibling's relationship ratings", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Control slope using older sibling’s relationship ratings
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.000 -0.049 0.961
so -0.461 0.030 -15.223 0.000
Factor2 0.001 0.000 4.156 0.000
so:Factor2 0.016 0.028 0.571 0.568

Relationship - Harm Avoidance HA

There was absolutely no main or interaction effects involving relationship quality in predicting Harm Avoidance intercepts or slopes.

#### younger siblings

# merge rela scores with latent intercepts and slopes
relaHA_y <- cbind(ageHA, yo$IDYRFAM)
colnames(relaHA_y)[6] <- "IDYRFAM"
relaHA_y <- merge(relaHA_y, efa_y)

# scale all variables
relaHA_y <- scale(relaHA_y[, -1], scale = F) %>% as.data.frame()

# moderation
summary(lm(iy ~ io * Factor1, data = relaHA_y))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Harm Avoidance intercept using older sibling's relationship ratings", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Harm Avoidance intercept using older sibling’s relationship ratings
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.001 0.013 -0.084 0.933
io 0.312 0.028 11.275 0.000
Factor1 0.012 0.012 0.944 0.345
io:Factor1 0.018 0.026 0.696 0.486
summary(lm(iy ~ io * Factor2, data = relaHA_y))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Harm Avoidance intercept using older sibling's relationship ratings", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Harm Avoidance intercept using older sibling’s relationship ratings
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.013 -0.034 0.973
io 0.313 0.027 11.382 0.000
Factor2 -0.007 0.012 -0.585 0.559
io:Factor2 -0.014 0.026 -0.550 0.582
summary(lm(sy ~ so * Factor1, data = relaHA_y))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Harm Avoidance slope using older sibling's relationship ratings", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Harm Avoidance slope using older sibling’s relationship ratings
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.001 0.061 0.951
so 0.123 0.042 2.914 0.004
Factor1 0.000 0.001 0.335 0.738
so:Factor1 0.049 0.041 1.193 0.233
summary(lm(sy ~ so * Factor2, data = relaHA_y))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Harm Avoidance slope using older sibling's relationship ratings", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Harm Avoidance slope using older sibling’s relationship ratings
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.001 -0.002 0.998
so 0.119 0.042 2.824 0.005
Factor2 0.000 0.001 0.313 0.754
so:Factor2 -0.007 0.042 -0.165 0.869
#### older siblings

# merge rela scores with latent intercepts and slopes
relaHA_o <- cbind(ageHA, yo$IDYRFAM)
colnames(relaHA_o)[6] <- "IDYRFAM"
relaHA_o <- merge(relaHA_o, efa_o)

# scale all variables
relaHA_o <- scale(relaHA_o[, -1], scale = F) %>% as.data.frame()

# moderation
summary(lm(iy ~ io * Factor1, data = relaHA_o))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Harm Avoidance intercept using older sibling's relationship ratings", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Harm Avoidance intercept using older sibling’s relationship ratings
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.003 0.013 -0.237 0.812
io 0.314 0.028 11.228 0.000
Factor1 -0.006 0.012 -0.443 0.658
io:Factor1 0.036 0.025 1.450 0.148
summary(lm(iy ~ io * Factor2, data = relaHA_o))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Harm Avoidance intercept using older sibling's relationship ratings", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Harm Avoidance intercept using older sibling’s relationship ratings
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.013 -0.005 0.996
io 0.311 0.028 11.284 0.000
Factor2 0.013 0.012 1.121 0.263
io:Factor2 -0.002 0.024 -0.090 0.928
summary(lm(sy ~ so * Factor1, data = relaHA_o))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Harm Avoidance slope using older sibling's relationship ratings", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Harm Avoidance slope using older sibling’s relationship ratings
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.001 0.011 0.991
so 0.116 0.042 2.733 0.006
Factor1 0.000 0.001 0.269 0.788
so:Factor1 0.006 0.041 0.156 0.876
summary(lm(sy ~ so * Factor2, data = relaHA_o))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Harm Avoidance slope using older sibling's relationship ratings", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Harm Avoidance slope using older sibling’s relationship ratings
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.001 -0.006 0.995
so 0.115 0.042 2.723 0.007
Factor2 0.000 0.001 0.632 0.527
so:Factor2 -0.016 0.042 -0.386 0.700

Life events

Life events data were collected from a Life Event Interview at intake, follow-up 1, and follow-up 2. These events were categorized into 3 groups following previous research byBillig et al., 1996:

# discrepancy count between siblings
fam_list <- c("Q1B","Q3A","Q10","Q11A","Q17","Q17A","Q18B", 
              "Q19AP","Q20AP","Q21A","Q21B","Q15","Q22S","Q35",
              "Q41D","Q49A","Q49B","Q41C","Q22P","Q43F","Q46P")
inf_list <- c("Q7","Q8","Q9","Q24","Q25","Q26","Q27",  
              "Q29E","Q51B")
ninf_list <- c("Q4A","Q5","Q6A","Q14B","Q20B","Q28B1","Q29B",
               "Q29C","Q29D","Q38B","Q38H","Q38C","Q13","Q30A",
               "Q31","Q16F","Q16D","Q16B")

count <- vector(mode = "numeric", length = nrow(yo))
for(i in c(inf_list, ninf_list)){
  current <- yo %>% select(starts_with(i))
  count <- count + as.numeric(current[,1] == current[,2])
}
yo$lei_shared <- count

# descriptives
fam <- lei %>%
  select(all_of(fam_list))
inf <- lei %>%
  select(all_of(inf_list))
ninf <- lei %>%
  select(all_of(ninf_list))
colnames(fam) <- var_label(fam)
colnames(inf) <- var_label(inf)
colnames(ninf) <- var_label(ninf)
fam <- fam %>%
  mutate_all(.funs = function(x){
  factor(x, levels = c(0:1), 
         labels = c("No", "Yes"))
})
inf <- inf %>%
  mutate_all(.funs = function(x){
  factor(x, levels = c(0:1), 
         labels = c("No", "Yes"))
})
ninf <- ninf %>%
  mutate_all(.funs = function(x){
  factor(x, levels = c(0:1), 
         labels = c("No", "Yes"))
})
  1. Family related events (FAM): events that happened to the family or to individuals within the family
ggplot(data = lei, aes(FAM)) +
  geom_histogram(binwidth = 1, fill = "#710c0c") + 
  geom_vline(xintercept = mean(lei$FAM, na.rm = T),
             color = "#f1c232", size = 1) +
  annotate("text", 
           label = paste0("Mean = ", round(mean(lei$FAM, na.rm = T), 2),
                          ", SD = ",round(sd(lei$FAM, na.rm = T), 2)),
           x = 10, y = 150) + 
  labs(
    title = "Distribution of Family-Related Events",
    x = "Count of events",
    y = NULL
  ) +
  theme_classic()

plot(likert(fam))

  1. Independent non-family events (INF): non-family events that were independent of the respondent’s behavior
ggplot(data = lei, aes(INF)) +
  geom_histogram(binwidth = 1, fill = "#710c0c") + 
  geom_vline(xintercept = mean(lei$INF, na.rm = T),
             color = "#f1c232", size = 1) +
  annotate("text", 
           label = paste0("Mean = ", round(mean(lei$INF, na.rm = T), 2),
                          ", SD = ",round(sd(lei$INF, na.rm = T), 2)),
           x = 7.5, y = 150) + 
  labs(
    title = "Distribution of Independent Non-Family Events",
    x = "Count of events",
    y = NULL
  ) +
  theme_classic()

plot(likert(inf))

  1. Non-independent non-family events (NINF): non-family events in which the respondent’s behavior may have influenced whether or not the event occurred
ggplot(data = lei, aes(NINF)) +
  geom_histogram(binwidth = 1, fill = "#710c0c") + 
  geom_vline(xintercept = mean(lei$NINF, na.rm = T),
            color = "#f1c232", size = 1) +
  annotate("text", 
           label = paste0("Mean = ", round(mean(lei$NINF, na.rm = T), 2),
                          ", SD = ",round(sd(lei$NINF, na.rm = T), 2)),
           x = 10, y = 150) + 
  labs(
    title = "Distribution of Non-Independent Non-Family Events",
    x = "Count of events",
    y = NULL
  ) +
  theme_classic()

plot(likert(ninf))

In the following analyses, we used the number of family-related events (as reported by the older siblings), as well as the count of similar non-family events that the siblings both experienced.

ggplot(data = yo, aes(lei_shared)) +
  geom_histogram(binwidth = 1, fill = "#710c0c") + 
  geom_vline(xintercept = mean(yo$lei_shared, na.rm = T),
             color = "#f1c232", size = 1) +
  annotate("text", 
           label = paste0("Mean = ", round(mean(yo$lei_shared, na.rm = T), 2),
                          ", SD = ",round(sd(yo$lei_shared, na.rm = T), 2)),
           x = 15, y = 50) + 
  labs(
    title = "Distribution of Similar Non-Family Events",
    x = "Count of events",
    y = NULL
  ) +
  theme_classic()

Life events - Aggression AG

There were significant interaction effects between family-related events and sibling similarity in changes in Aggression over time.

In particular, there was a stronger between-sibling correlation in Aggression development when there were more family-related events reported, \(B = 0.031, SE = 0.012, t = 2.584, p = 0.010\).

Further, interestingly, there were significant main effects between life events and Aggression (in younger siblings) such that:

  • Family-related events were associated with higher Aggression intercept \((B = 0.033, SE = 0.006, t = 5.730, p < 0.001)\) and faster decrease in Aggression \((B = -0.001, SE = 0.000, t = -2.750, p = 0.006)\)
  • Similarity in non-family events were associated with lower Aggression intercept \((B = -0.025, SE = 0.005 t = -4.696, p < 0.001)\) and slower decrease in Aggression \((B = 0.000, SE = 0.000, t = -2.001, p = 0.046)\)
# merge lei counts with latent intercepts and slopes
leiAG <- cbind(select(ageAG, c(io,iy,so,sy)), yo$IDYRFAM)
colnames(leiAG)[5] <- "IDYRFAM"
leiAG <- merge(leiAG, select(yo, c(IDYRFAM, FAM_o, lei_shared)))

# scale all variables
leiAG <- scale(leiAG[, -1], scale = F) %>% as.data.frame()

# moderation
summary(lm(iy ~ io * FAM_o, data = leiAG))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Aggression intercept using count of family-related events", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Aggression intercept using count of family-related events
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.001 0.015 -0.060 0.953
io 0.334 0.033 10.042 0.000
FAM_o 0.033 0.006 5.730 0.000
io:FAM_o 0.010 0.012 0.764 0.445
summary(lm(iy ~ io * lei_shared, data = leiAG))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Aggression intercept using count of similar non-family events", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Aggression intercept using count of similar non-family events
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.015 0.020 0.984
io 0.318 0.034 9.238 0.000
lei_shared -0.025 0.005 -4.696 0.000
io:lei_shared 0.002 0.012 0.134 0.893
summary(lm(sy ~ so * FAM_o, data = leiAG))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Aggression slope using count of family-related events", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Aggression slope using count of family-related events
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.001 0.224 0.823
so 0.254 0.032 7.977 0.000
FAM_o -0.001 0.000 -2.750 0.006
so:FAM_o 0.031 0.012 2.584 0.010
summary(lm(sy ~ so * lei_shared, data = leiAG))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Aggression slope using count of similar non-family events", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Aggression slope using count of similar non-family events
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.001 0.087 0.930
so 0.255 0.032 7.891 0.000
lei_shared 0.000 0.000 2.001 0.046
so:lei_shared -0.007 0.010 -0.723 0.470
# interaction plot at minimum and maximum family events
plot_model(lm(sy ~ so * FAM_o, data = leiAG), 
           type = "int",
           axis.title = c("Older sibling", "Younger sibling"),
           title = "Aggression slope using count of family-related events") +
  theme_classic()

Life events - Control CON

There were no interaction effects between life events and between-sibling correlations in Control or changes in Control over time.

Similarly to Aggression, however, there were significant main effects of life events on Control such that:

  • Family-related events were associated with lower Control intercept \((B = -0.018, SE = 0.004, t = -4.323, p < 0.001)\) and faster increase in Control \((B = 0.000, SE = 0.000, t = 3.173, p = 0.002)\)
  • Similarity in non-family events were associated with higher Control intercept \((B = 0.015, SE = 0.004, t = 3.937, p < 0.001)\) and slower increase in Control \((B = 0.000, SE = 0.000, t = -4.049, p < 0.001)\).
# merge lei counts with latent intercepts and slopes
leiCON <- cbind(select(ageCON, c(io,iy,so,sy)), yo$IDYRFAM)
colnames(leiCON)[5] <- "IDYRFAM"
leiCON <- merge(leiCON, select(yo, c(IDYRFAM, FAM_o, lei_shared)))

# scale all variables
leiCON <- scale(leiCON[, -1], scale = F) %>% as.data.frame()

# moderation
summary(lm(iy ~ io * FAM_o, data = leiCON))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Control intercept using count of family-related events", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Control intercept using count of family-related events
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.011 0.005 0.996
io 0.001 0.031 0.019 0.985
FAM_o -0.018 0.004 -4.324 0.000
io:FAM_o 0.001 0.012 0.103 0.918
summary(lm(iy ~ io * lei_shared, data = leiCON))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Control intercept using count of similar non-family events", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Control intercept using count of similar non-family events
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.001 0.011 -0.086 0.931
io -0.016 0.032 -0.506 0.613
lei_shared 0.015 0.004 3.937 0.000
io:lei_shared 0.007 0.011 0.617 0.537
summary(lm(sy ~ so * FAM_o, data = leiCON))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Control slope using count of family-related events", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Control slope using count of family-related events
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.000 0.005 0.996
so -0.446 0.030 -14.834 0.000
FAM_o 0.000 0.000 3.173 0.002
so:FAM_o 0.003 0.012 0.238 0.812
summary(lm(sy ~ so * lei_shared, data = leiCON))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Control slope using count of similar non-family events", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Control slope using count of similar non-family events
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.000 -0.088 0.930
so -0.459 0.030 -15.280 0.000
lei_shared 0.000 0.000 -4.049 0.000
so:lei_shared -0.007 0.011 -0.622 0.534

Life events - Harm Avoidance HA

Similarity in non-family events significantly moderated between-sibling correlation in both intercepts and slopes of Harm Avoidance.

In particular, siblings with more similar non-family events were more similar in Harm Avoidance intercept \((B = 0.024, SE = 0.010, t = 2.494, p = 0.013)\) and slope \((B = 0.030, SE = 0.015, t = 2.016, p = 0.044)\).

There were significant main effects of life events on changes in Harm Avoidance overtime such that:

  • Family-related events were associated with faster increase in Harm Avoidance Control \((B = 0.001, SE = 0.000, t = 2.408, p = 0.016)\)
  • Similarity in non-family events were associated with slower increase in Harm Avoidance \((B = -0.001, SE = 0.000, t = -2.682, p = 0.008)\).
# merge lei counts with latent intercepts and slopes
leiHA <- cbind(select(ageHA, c(io,iy,so,sy)), yo$IDYRFAM)
colnames(leiHA)[5] <- "IDYRFAM"
leiHA <- merge(leiHA, select(yo, c(IDYRFAM, FAM_o, lei_shared)))

# scale all variables
leiHA <- scale(leiHA[, -1], scale = F) %>% as.data.frame()

# moderation
summary(lm(iy ~ io * FAM_o, data = leiHA))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Harm Avoidance intercept using count of family-related events", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Harm Avoidance intercept using count of family-related events
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.012 0.006 0.995
io 0.314 0.027 11.568 0.000
FAM_o -0.007 0.005 -1.368 0.172
io:FAM_o 0.009 0.010 0.828 0.408
summary(lm(iy ~ io * lei_shared, data = leiHA))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Harm Avoidance intercept using count of similar non-family events", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Harm Avoidance intercept using count of similar non-family events
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.003 0.013 -0.248 0.804
io 0.314 0.027 11.472 0.000
lei_shared 0.006 0.004 1.336 0.182
io:lei_shared 0.024 0.010 2.494 0.013
summary(lm(sy ~ so * FAM_o, data = leiHA))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Harm Avoidance slope using count of family-related events", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Harm Avoidance slope using count of family-related events
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.001 0.012 0.990
so 0.117 0.042 2.797 0.005
FAM_o 0.001 0.000 2.408 0.016
so:FAM_o -0.004 0.015 -0.280 0.779
summary(lm(sy ~ so * lei_shared, data = leiHA))$coefficients %>%
  knitr::kable(caption = "Predicting younger siblings's Harm Avoidance slope using count of similar non-family events", digits = 3) %>% 
  kable_styling()
Predicting younger siblings’s Harm Avoidance slope using count of similar non-family events
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.000 0.001 0.082 0.935
so 0.121 0.042 2.901 0.004
lei_shared -0.001 0.000 -2.682 0.008
so:lei_shared 0.030 0.015 2.016 0.044
# interaction plot at minimum and maximum family events
plot_model(lm(iy ~ io * lei_shared, data = leiHA), 
           type = "int",
           axis.title = c("Older sibling", "Younger sibling"),
           title = "Harm Avoidance intercept using count of similar non-family events") +
  theme_classic()

plot_model(lm(sy ~ so * lei_shared, data = leiHA), 
           type = "int",
           axis.title = c("Older sibling", "Younger sibling"),
           title = "Harm Avoidance slope using count of similar non-family events") +
  theme_classic()