#::::::::::::::::: PSY9140 SEM course Day 4 :::::::::::::::::::::::::::::###

################### (0) Preparations #######################################
# installing packages; has just to be done once.
# install.packages("lavaan")
# install.packages("psych")
# install.packages("lavaanPlot")
# install.packages("semPlot")
# install.packages("semTable")
# install.packages("ggcorrplot")

# load packages. Has to be done each time R is started.
library(lavaan)
library(psych)
library(lavaanPlot)
library(semPlot)
library(semTable)
library(ggcorrplot)


################### (1) Exercise 1 #######################################

# load the datafile "data3.csv" as a dataframe with the name "df1" by using the "read.csv" command
df1 <- read.csv("https://www.sv.uio.no/psi/personer/vit/tilmanns/psy9140/data3.csv")

# descriptive statistics for all variables in "df1" by using "describe" from the "psych" package
describe(df1)

# (1) Specify the model shown in the figure

# Model specification
model <- "diet3 ~ diet2 + body2
          body3 ~ body2 + diet2
          diet2 ~ diet1 + body1
          body2 ~ body1 + diet1
          diet3 ~~ body3
          diet2 ~~ body2
          diet1 ~~ body1"

# Running the model
fit <- sem(model, missing = "ML", meanstructure = TRUE, data = df1)

# Providing output for the model
summary(fit,  fit.measures = TRUE, standardized=TRUE, modindices = TRUE)

# (2) Check model fit and re-specify the model, according to modification indices and conceptual considerations.

# Answer: Model fit shows that at least the autorgressions from T1 to T3 should be estimated. They are estimated here.
model <- "diet3 ~ diet2 + body2 + diet1
          body3 ~ body2 + diet2 + body1
          diet2 ~ diet1 + body1
          body2 ~ body1 + diet1
          diet3 ~~ body3
          diet2 ~~ body2
          diet1 ~~ body1"

# Running the model
fit <- sem(model, missing = "ML", meanstructure = TRUE, data = df1)

# Providing output for the model
summary(fit,  fit.measures = TRUE, standardized=TRUE)

# (3) Both girls and boys are included in the sample. Specify a model with adjustment for gender.

model <- "diet3 ~ diet2 + body2 + diet1 + girl
          body3 ~ body2 + diet2 + body1 + girl
          diet2 ~ diet1 + body1 + girl
          body2 ~ body1 + diet1 + girl
          diet3 ~~ body3
          diet2 ~~ body2
          diet1 ~~ body1 + girl
          body1 ~~ girl"

# Running the model
fit <- sem(model, missing = "ML", meanstructure = TRUE, data = df1)

# Providing output for the model
summary(fit,  fit.measures = TRUE, standardized=TRUE)


################### (2) Exercise 2 #######################################

# load the datafile "data4.csv" as a dataframe with the name "df1" by using the "read.csv" command
df2 <- read.csv("https://www.sv.uio.no/psi/personer/vit/tilmanns/psy9140/data4.csv")

# descriptive statistics for all variables in "df2" by using "describe" from the "psych" package
describe(df2)

# (1) Use the input file day4.R, Exercise 2. Run the model and draw a path diagram of the model that is estimated.

# Specify the model
model <- "# Latent factors diet
            diet1 =~ diet11 + diet12 + diet13 + diet14
            diet2 =~ diet21 + diet22 + diet23 + diet24
          # Latent factors body
            body1 =~ body11 + body12 + body13 + body14 + body15
            body2 =~ body21 + body22 + body23 + body24 + body25
          # Covariances
            diet1 + diet2  ~~ body1 + body2
            diet1 ~~ diet2
            body1 ~~ body2"

# Run the model
fit <- sem(model, missing = "ML", meanstructure = TRUE, data = df2)

# Increase the number of rows printed in the output
options(max.print=10000)

# Providing output for the model
summary(fit,  fit.measures = TRUE, standardized=TRUE, modindices = TRUE)

# I often prefer to draw the diagram with paper and pencil, to get a better overview over the model, 
# but if you want use semPlot:
# Path diagram with a design with good readability. Intercepts are not depicted to increase readability
# This is one of many possible ways to draw the model. 
semPaths(fit, whatLabels = "std", layout = "spring", layoutSplit = TRUE, curve = .3, 
         nCharNodes = 0, measurementLayout = "tree3", intercepts = FALSE, subScale = .5, subScale2 = .5)

# (2) The fit indices show that the model does not fit the data well. How could you improve the model in a way
# that is conceptually meaningful?

# Specify the model
model <- "# Latent factors diet
            diet1 =~ diet11 + diet12 + diet13 + diet14
            diet2 =~ diet21 + diet22 + diet23 + diet24
          # Latent factors body
            body1 =~ body11 + body12 + body13 + body14 + body15
            body2 =~ body21 + body22 + body23 + body24 + body25
          # Covariances
            diet1 + diet2  ~~ body1 + body2
            diet1 ~~ diet2
            body1 ~~ body2
          # Covariances between residuals  
            diet11 ~~ diet21          
            diet12 ~~ diet22          
            diet13 ~~ diet23          
            diet14 ~~ diet24          
            body11 ~~ body21
            body12 ~~ body22
            body13 ~~ body23
            body14 ~~ body24
            body15 ~~ body25"

# Run the model
fit <- sem(model, missing = "ML", meanstructure = TRUE, data = df2)

# Increase the number of rows printed in the output
options(max.print=10000)

# Providing output for the model
summary(fit,  fit.measures = TRUE, standardized=TRUE, modindices = TRUE)

# (3) Re-specify the model to obtain measurement invariance across time.

# Specify the model
model <- "# Latent factors diet
            diet1 =~ diet11 + d2*diet12 + d3*diet13 + d4*diet14
            diet2 =~ diet21 + d2*diet22 + d3*diet23 + d4*diet24
          # Latent factors body
            body1 =~ body11 + b2*body12 + b3*body13 + b4*body14 + b5*body15
            body2 =~ body21 + b2*body22 + b3*body23 + b4*body24 + b5*body25
          # Covariances
            diet1 + diet2  ~~ body1 + body2
            diet1 ~~ diet2
            body1 ~~ body2
          # Covariances between residuals  
            diet11 ~~ diet21          
            diet12 ~~ diet22          
            diet13 ~~ diet23          
            diet14 ~~ diet24          
            body11 ~~ body21
            body12 ~~ body22
            body13 ~~ body23
            body14 ~~ body24
            body15 ~~ body25"

# Run the model
fit <- sem(model, missing = "ML", meanstructure = TRUE, data = df2)

# Increase the number of rows printed in the output
options(max.print=10000)

# Providing output for the model
summary(fit,  fit.measures = TRUE, standardized=TRUE, modindices = TRUE)

# (4) Re-specify the model to obtain a cross- lagged, autoregressive model. 

# Specify the model
model <- "# Latent factors diet
            diet1 =~ diet11 + d2*diet12 + d3*diet13 + d4*diet14
            diet2 =~ diet21 + d2*diet22 + d3*diet23 + d4*diet24
          # Latent factors body
            body1 =~ body11 + b2*body12 + b3*body13 + b4*body14 + b5*body15
            body2 =~ body21 + b2*body22 + b3*body23 + b4*body24 + b5*body25
          # Covariances
            diet2 ~ diet1 + body1
            body2 ~ body1 + diet1 
            diet1 ~~ body1
            diet2 ~~ body2
            # Covariances between residuals  
            diet11 ~~ diet21          
            diet12 ~~ diet22          
            diet13 ~~ diet23          
            diet14 ~~ diet24          
            body11 ~~ body21
            body12 ~~ body22
            body13 ~~ body23
            body14 ~~ body24
            body15 ~~ body25"

# Run the model
fit <- sem(model, missing = "ML", meanstructure = TRUE, data = df2)

# Increase the number of rows printed in the output
options(max.print=10000)

# Providing output for the model
summary(fit,  fit.measures = TRUE, standardized=TRUE)

################### (3) Exercise 3 #######################################

# (1) Use the script day4.R, Exercise 3 . Estimate a growth curve based on the mean
# scores of body image (variables body1 to body3 ) at three time points.

# Specify the model in the next line
model <- "i =~ 1*body1 + 1*body2 + 1*body3
          s =~ 0*body1 + 1*body2 + 2*body3
          i ~~ s"

# Running the model
fit <- growth(model, missing = "ML", meanstructure = TRUE, data = df1)

# Providing output for the model
summary(fit, fit.measures = TRUE, standardized=TRUE)

# (2) What kind of information do the results provide about the mean and 
# variance of the intercept and the slope of body image?

# Answer: Mean intercept = 3.43, meaning that the estimated mean at T1 is 3.43.
#         Mean slope = 0.03, meaning that body image is increasing with 0.03 from one time point
#         to the next with on average 0.03 units. The variance for the intercept and slope is significant.

# (3) The second data collection was two years after the first data collection. The third data collection was seven
# years after the first data collection. Estimate a new growth curve model that takes into account the uneven
# intervals between time points. How can we interpret the mean of the slope?

# Specify the model in the next line
model <- "i =~ 1*body1 + 1*body2 + 1*body3
          s =~ 0*body1 + 2*body2 + 7*body3
          i ~~ s"

# Running the model
fit <- growth(model, missing = "ML", meanstructure = TRUE, data = df1)

# Providing output for the model
summary(fit, fit.measures = TRUE, standardized=TRUE)

# Answer: The mean of the slope indicates that body image increases on average with .008 units per year.


################### (4) Exercise 4 #####################################

# (1) Run the code in day4.R, Exercise 4. 

# Model specification
model <- "# LGC specification
            i =~ 1*body1 + 1*body2 + 1*body3
            s =~ 0*body1 + 2*body2 + 7*body3
          # Covariance between i and s
            i ~~ s
          # Regression
            i + s ~ girl"

# Running the model
fit <- growth(model, missing = "ML", meanstructure = TRUE, data = df1)

# Providing output for the model
summary(fit, fit.measures = TRUE, standardized=TRUE)

# (2) How is gender related to the intercept and slope of body image, and what do such relationships 
# tell us about how girls' and boys' body image is developing over time?

# Answer: The regression coefficient for girl --> i is -0.431 (p<.05) and for girl --> s is 0.004 (p>.05)
# The results indicate that the estimated level of body image at T1 for boys (who are coded 0) is 3.683 
# (the intercept of the intercept), and the estimated level for girls is 3.252 (i.e., 3.683 - 0.431)
# Moreover, the estimated growth in body image from one year to the next for boys is 0.006 (intercept of the slope), 
# and the estimated growth for girls is 0.010 (i.e., .006 + 0.004). However, the gender difference in the slope is not significant.


# (3) Model a growth curve for dieting  and interpret the estimates of the slope and the intercept.

# Model specification
model <- "# LGC specification
            i =~ 1*diet1 + 1*diet2 + 1*diet3
            s =~ 0*diet1 + 2*diet2 + 7*diet3
          # Covariance between i and s
            i ~~ s"

# Running the model
fit <- growth(model, missing = "ML", meanstructure = TRUE, data = df1)

# Providing output for the model
summary(fit, fit.measures = TRUE, standardized=TRUE)

# (4) Include gender as time invariant covariate, predicting the intercept and the slope of dieting. 
# Is there any problem with this model?

# Model specification
model <- "# LGC specification
            i =~ 1*diet1 + 1*diet2 + 1*diet3
            s =~ 0*diet1 + 2*diet2 + 7*diet3
          # Covariance between i and s
            i ~~ s
          # Regression
            i + s ~ girl"

# Running the model
fit <- growth(model, missing = "ML", meanstructure = TRUE, data = df1)

# Providing output for the model
summary(fit, fit.measures = TRUE, standardized=TRUE)

# Answer: The RMSEA indicates low model fit. However, CFI and TLI are ok.


################### (5) Exercise 5 #######################################

# (1) Run the code. Two growth curves are estimated in one model: One for dieting and one for body image. 
# Examine how intercepts and slopes are correlated with each other.

# Model specification
model <- "# LGC specification
            i_b =~ 1*body1 + 1*body2 + 1*body3
            s_b =~ 0*body1 + 2*body2 + 7*body3
            i_d =~ 1*diet1 + 1*diet2 + 1*diet3
            s_d =~ 0*diet1 + 2*diet2 + 7*diet3
          # Covariance between i and s
            i_b ~~ s_b
            i_d ~~ s_d
            i_d ~~ i_b
            s_d ~~ s_b
            i_d ~~ s_b
            i_b ~~ s_d"

# Running the model
fit <- growth(model, missing = "ML", meanstructure = TRUE, data = df1)

# Providing output for the model
summary(fit, fit.measures = TRUE, standardized=TRUE)

# (2) Re-specify the model such that the intercept of dieting predicts the slope of body image. 
# The intercept of body image should predict the slope of dieting. 

# Model specification
model <- "# LGC specification
            i_b =~ 1*body1 + 1*body2 + 1*body3
            s_b =~ 0*body1 + 2*body2 + 7*body3
            i_d =~ 1*diet1 + 1*diet2 + 1*diet3
            s_d =~ 0*diet1 + 2*diet2 + 7*diet3
          # Covariance between i and s
            i_b ~~ s_b
            i_d ~~ s_d
            i_d ~~ i_b
            s_d ~~ s_b
            s_b ~ i_d
            s_d ~ i_b"

# Running the model
fit <- growth(model, missing = "ML", meanstructure = TRUE, data = df1)

# Providing output for the model
summary(fit, fit.measures = TRUE, standardized=TRUE)

# (3) Draw a diagram of the model you have just estimated. 
# Path diagram with a design with good readability. There are other solutions possible. 
semPaths(fit, whatLabels = "par", layout = "tree")


################### (6) Exercise 6 #######################################

# (1) Run the code and interpret the means of the intercept and slope.

# load the datafile "data5.csv" as a dataframe with the name "df3" by using the "read.csv" command
df3 <- read.csv("https://www.sv.uio.no/psi/personer/vit/tilmanns/psy9140/data5.csv")

# descriptive statistics for all variables in "df1" by using "describe" from the "psych" package
describe(df3)

# Specify the model in the next line
model <- "# LGC specification
            i =~ 1*body1 + 1*body2 + 1*body3 + 1*body4
            s =~ 0*body1 + 2*body2 + 7*body3 + 13*body4" 

# Running the model
fit <- growth(model, missing = "ML", meanstructure = TRUE, data = df3)

# Providing output for the model
summary(fit, fit.measures = TRUE, standardized=TRUE)

# Answer: The estimated mean level of body image at T1 is 3.439. 
# The estimated growth in body image from one year to the next is 0.005. 

# (2) Include a quadratic slope in the model.

# Model specification
model <- "# LGC specification
          i =~ 1*body1 + 1*body2 + 1*body3 + 1*body4
	        s =~ 0*body1 + .2*body2 + .7*body3 + 1.3*body4
      	  q =~ 0*body1 + .04*body2 + .49*body3 + 1.69*body4" 

# Running the model
fit <- growth(model, missing = "ML", meanstructure = TRUE, data = df3)

# Providing output for the model
summary(fit, fit.measures = TRUE, standardized=TRUE)

# (3) Try to draw a graph representing the development of body image according to the new, non-linear trajectory.

# Answer: I would recommend to draw the graph by using paper and pencil to get familiar
# with how such models represent growth. The model can also be drawn by for example using the ggplot2 package, see below.

# If not installed yet, the ggplot2 package has to be installed first.
# install.packages("ggplot2")

library(ggplot2)

ggplot(data.frame(x=c(0, 1.3)), aes(x)) + 
  theme_classic() +
  theme(axis.text = element_text(color = "black", size = 14)) + # value label size
  theme(axis.title = element_text(size = 16)) + # axis title size
  theme(axis.ticks = element_line(size = 1)) + # thickness of axis ticks
  theme(axis.ticks.length = unit(.3,"cm")) + # length of axis ticks
  theme(axis.line = element_line(color = "black", size = 1)) + # size of x and y axis
  stat_function(fun=function(x) 3.431 + .125*x - .059*x^2, size = 1) + # provides the growth curve function
  coord_cartesian(xlim = c(0, 1.3), ylim = c(3.3, 3.6)) + # range of graph
  scale_x_continuous(breaks=seq(0, 1.3, .1), expand = c(0,0)) + #Labels specifies x-axis value labels
  xlab("Time in decades (0.1 = 1 year)") +
  ylab("Body image")


