1. Pre-processing (for semesters 1 and 2)

# install.packages("devtools")
# devtools::install_github("jrosen48/jmRtools")
Sys.setenv(TZ='America/Detroit')

library(jmRtools)
library(readxl)
library(tidyverse)
library(lubridate)
RR_Course_Data <- read_csv("RR_Course_Data.csv")

CS1 <- read_csv("data/CS1.csv") # this is the pre-survey for the Fall, 2015 and Spring, 2016 semesters
CS1_ss <- dplyr::filter(CS1, 
                        !is.na(Q1MaincellgroupRow1),
                        opdata_username != "_49147_1",
                        opdata_username != "_93993_1",
                        opdata_username != "@X@user.pk_string@X@",
                        opdata_username != "_80624_1",
                        opdata_CourseID != "@X@course.course_id@X@",
                        opdata_username != "") # must revisit

ps12 <- dplyr::arrange(CS1_ss, opdata_username, opdata_CourseID, StartDate)

# ps12$Q1MaincellgroupRow4_rc <- car::recode(ps12$Q1MaincellgroupRow4, "1=5; 2=4; 5=1; 4=2")
ps12$Q1MaincellgroupRow7_rc <- car::recode(ps12$Q1MaincellgroupRow7, "1=5; 2=4; 5=1; 4=2")

ps12$int <- (ps12$Q1MaincellgroupRow1 + ps12$Q1MaincellgroupRow8 + ps12$Q1MaincellgroupRow10+ ps12$Q1MaincellgroupRow5) / 4
ps12$uv <- (ps12$Q1MaincellgroupRow2 + ps12$Q1MaincellgroupRow6+ ps12$Q1MaincellgroupRow9) / 3 # dropped 7 (is this supposed to be dropped 4?)
ps12$percomp <- (ps12$Q1MaincellgroupRow3 + ps12$Q1MaincellgroupRow7_rc) / 2

x <- str_split(ps12$opdata_CourseID, "-")

ps12_f <- mutate(ps12,
                 subject = map_chr(x, ~ .[1]),
                 semester = map_chr(x, ~ .[2]),
                 section = map_chr(x, ~ .[3]))

ps12_f <- select(ps12_f,
                 student_ID = opdata_username,
                 course_ID = opdata_CourseID,
                 subject, semester, section,
                 int, uv, percomp)

ps12_f <- mutate(ps12_f, student_ID = str_sub(student_ID, start = 2L, end = -3L))
ps12_f <- arrange(ps12_f, student_ID)

CS2 <- read_csv("data/CS2.csv") # this is the pre-survey for the Fall, 2015 and Spring, 2016 semesters
CS2$Q1MaincellgroupRow7_rc <- car::recode(CS2$Q1MaincellgroupRow7, "1=5; 2=4; 5=1; 4=2")
CS2$post_int <- (CS2$Q1MaincellgroupRow1 + CS2$Q1MaincellgroupRow8 + CS2$Q1MaincellgroupRow10+ CS2$Q1MaincellgroupRow5) / 4
CS2$post_uv <- (CS2$Q1MaincellgroupRow2 + CS2$Q1MaincellgroupRow6+ CS2$Q1MaincellgroupRow9) / 3 # dropped 7 (is this supposed to be dropped 4?)
CS2$post_percomp <- (CS2$Q1MaincellgroupRow3 + CS2$Q1MaincellgroupRow7_rc) / 2
CS2$date <- lubridate::ymd_hm(CS2$CompletedDate, tz = "America/Detroit")
CS2 <- arrange(CS2, date)

CS2 <- CS2 %>% 
    mutate(student_ID = str_sub(opdata_username, start = 2L, end = -3L)) %>% 
    select(student_ID, contains("post"), date)

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

CS2 <- filter(CS2, 
              student_ID != "49147",
              student_ID != "93993",
              student_ID != "80624",
              student_ID != "@X@user.pk_string@X@",
              student_ID != "@X@course.course_id@X@",
              student_ID != "")

CS2 <- distinct(CS2, student_ID, .keep_all = T)
CS2 <- select(CS2, -date)
CS2 <- arrange(CS2, student_ID)

ps12_f <- left_join(ps12_f, CS2, by = "student_ID")

2. Pre-processing (for semester 3)

ps3 <- read_excel("~/Dropbox/1_Research/utility_value_intervention_online_science/CS_1_7_13_17.xls")

ps3$Q1MaincellgroupRow61_rc <- car::recode(ps3$Q1MaincellgroupRow61, "1=5; 2=4; 5=1; 4=2")

# ps3$int <- (ps3$Q1MaincellgroupRow01 + ps3$Q1MaincellgroupRow71 + ps3$Q1MaincellgroupRow91+ ps3$Q1MaincellgroupRow41) / 4
# ps3$uv <- (ps3$Q1MaincellgroupRow11 + ps3$Q1MaincellgroupRow51+ ps3$Q1MaincellgroupRow81) / 3 # dropped 7
# ps3$percomp <- (ps3$Q1MaincellgroupRow21 + ps3$Q1MaincellgroupRow61_rc) / 2

ps3 <- ps3 %>% 
    mutate(int = composite_mean_maker(ps3, Q1MaincellgroupRow01, Q1MaincellgroupRow71, Q1MaincellgroupRow91, Q1MaincellgroupRow41),
           uv = composite_mean_maker(ps3, Q1MaincellgroupRow11, Q1MaincellgroupRow51, Q1MaincellgroupRow81),
           percomp = composite_mean_maker(ps3, Q1MaincellgroupRow11, Q1MaincellgroupRow51, Q1MaincellgroupRow81)) %>% 
    filter(opdata_CourseID != "@X@course.course_id@X@") %>% 
    separate(opdata_CourseID, c("subject", "semester", "section"), sep = "-", remove = F) 

ps3_f <- select(ps3,
                student_ID = opdata_username,
                course_ID = opdata_CourseID,
                subject, semester, section,
                int, uv, percomp)

df2 <- read_excel("~/Dropbox/1_Research/utility_value_intervention_online_science/CS_2_7_13_17.xls")
df2$post_int <- (df2$Q2MaincellgroupRow01 + df2$Q2MaincellgroupRow71 + df2$Q2MaincellgroupRow91 + df2$Q2MaincellgroupRow41) / 4
df2$post_uv <- (df2$Q2MaincellgroupRow11 + df2$Q2MaincellgroupRow51+ df2$Q2MaincellgroupRow81) / 3 # dropped 7
df2$post_percomp <- (df2$Q2MaincellgroupRow21)

df2 <- mutate(df2, date = lubridate::mdy_hm(CompletedDate, tz = "America/Detroit"))

df2 <- arrange(df2, date)

df2 <- select(df2, student_ID = opdata_username, contains("post"), date)
df2 <- distinct(df2)
df2 <- select(df2, -date)

pd3_f <- left_join(ps3_f, df2, by = "student_ID")
ps3_f <- mutate(ps3_f,
                student_ID = str_sub(student_ID, start = 2, end = -3))

3. Merging and processing merged data

ps12s <- dplyr::select(ps12_f, student_ID, course_ID, subject, semester, section, int, uv, percomp)
ps3s <- dplyr::select(ps3_f, course_ID, subject, semester, section, int, uv, percomp)

x <- bind_rows(ps12s, ps3s)
x <- as_tibble(x)

d <- bind_rows(ps12_f, ps3_f)

# treatment vs. control for sems 1 and 2
# https://docs.google.com/document/d/1g52pl-0JyEO26bFEJ9aE295dL7oZSOU1wrVXvVbd2lg/edit

d <- mutate(d,
            intervention_dummy = case_when(
                # Fall 15
                course_ID == "AnPhA-S116-01" ~ 1,
                course_ID == "AnPhA-S116-02" ~ 0,
                course_ID == "BioA-S116-01" ~ 1,
                course_ID == "BioA-T116-01" ~ 0,
                course_ID == "FrScA-S116-01" ~ 1,
                course_ID == "FrScA-S116-02" ~ 0,
                course_ID == "FrScA-S116-03" ~ 1,
                course_ID == "FrScA-S116-04" ~ 0,
                course_ID == "FrScA-T116-01" ~ 0,
                course_ID == "OcnA-S116-01" ~ 1,
                course_ID == "OcnA-S116-01" ~ 0,
                course_ID == "OcnA-S116-03" ~ 1,
                course_ID == "OcnA-T116-01" ~ 0,
                course_ID == "PhysA-S116-01" ~ 1,
                course_ID == "PhysA-T116-01" ~ 0,
                
                # Spring 16
                course_ID == "AnPhA-S216-01" ~ 0,
                course_ID == "AnPhA-S216-02" ~ 1,
                course_ID == "BioA-S216-01" ~ 0,
                course_ID == "FrScA-S216-01" ~ 0,
                course_ID == "FrScA-S216-02" ~ 1,
                course_ID == "FrScA-S216-03" ~ 0,
                course_ID == "FrScA-S216-04" ~ 1,
                course_ID == "OcnA-S216-01" ~ 0,
                course_ID == "OcnA-S216-02" ~ 1,
                course_ID == "PhysA-S216-01" ~ 0,
                
                # Spring 17
                course_ID == "AnPhA-S217-01" ~ 1,
                course_ID == "AnPhA-S217-01" ~ 0,
                course_ID == "Bio-S217-01" ~ 1,
                course_ID == "FrScA-S217-01" ~ 1,
                course_ID == "FrScA-S217-02" ~ 0,
                course_ID == "FrScA-S217-02." ~ 0,
                course_ID == "FrScA-S217-03" ~ 1,
                course_ID == "OcnA-S217-01" ~ 0,
                course_ID == "OcnA-S217-02" ~ 1,
                course_ID == "OcnA-S217-03" ~ 1,
                course_ID == "PhysA-S217-01" ~ 0,
                TRUE ~ 0
            ))

d <- rename(d, pre_int = int, pre_uv = uv, pre_percomp = percomp)

4. Processing all gradebook data

x <- read_csv("RR_S3.csv")
x <- select(x, course_ID = Course_ID, student_ID = CU_Pk1, Item_Position:last_access_date)
x <- rename(x, Grade_Category = Grade_Catagory)

RR_Course_Data <- select(RR_Course_Data, course_ID = CourseSectionOrigID, student_ID = Bb_UserPK, Gradebook_Item:last_access_date)

xx <- bind_rows(RR_Course_Data, x)
# write_csv(RR_Course_Data, "s12_gradebook_data.csv")

5. Merging self-report and gradebook data (not run yet)

d$student_ID <- as.character(d$student_ID)
xx$student_ID <- as.character(xx$student_ID)
df <- left_join(d, xx, by = "student_ID")

Processing trace data

library(readxl)
ts_12 <- read_csv("RR_Minutes.csv")

td_12 <- read_csv("RR_Course_Data.csv")
td_3 <- read_excel("Ranelluci Study Data Pull Request.xlsx")

td_12 <- td_12 %>% 
    select(student_ID = Bb_UserPK, course_ID = CourseSectionOrigID,
           gender = Gender, enrollment_reason = EnrollmentReason, 
           enrollment_status = EnrollmentStatus,
           final_grade = FinalGradeCEMS) %>% 
    distinct()

ts_12 <- ts_12 %>% 
    select(student_ID = Bb_UserPK,
           course_ID = CourseSectionOrigID,
           time_spent = TimeSpent)

td_12 <- left_join(td_12, ts_12)

td_3 <- td_3 %>% 
    select(student_ID = CEMS_Bb_UserPK, 
           course_ID = Section_ID,
           gender = Gender,
           enrollment_reason = EnrollmentReason,
           enrollment_status = EnrollmentStatus,
           final_grade = Final_Grade,
           time_spent = `Sum of time spent in course`) %>% 
    mutate(final_grade = as.numeric(final_grade))

trace_data <- bind_rows(td_12, td_3)

Merging trace data with other data

d$student_ID <- as.integer(d$student_ID)
d <- left_join(d, trace_data)

6. Pre-post analysis

Using multi-level models by course.

60. Looking first at n’s

d %>% 
    count(intervention_dummy)
## # A tibble: 2 x 2
##   intervention_dummy     n
##                <dbl> <int>
## 1                  0   380
## 2                  1   429
d[complete.cases(d), ] %>% 
    count(intervention_dummy)
## # A tibble: 2 x 2
##   intervention_dummy     n
##                <dbl> <int>
## 1                  0     8
## 2                  1   108

6A. Just looking at pre-post changes in interest and UV and grades

sjPlot::sjt.lmer(lme4::lmer(post_int ~ intervention_dummy + (1 | course_ID), data = d))
    post_int
    B CI p
Fixed Parts
(Intercept)   4.51 3.71 – 5.31 <.001
intervention_dummy   -0.85 -1.80 – 0.11 .096
Random Parts
σ2   0.705
τ00, course_ID   0.370
Ncourse_ID   12
ICCcourse_ID   0.344
Observations   121
R2 / Ω02   .262 / .252
sjPlot::sjt.lmer(lme4::lmer(post_uv ~ intervention_dummy + (1 | course_ID), data = d))
    post_uv
    B CI p
Fixed Parts
(Intercept)   3.86 3.03 – 4.70 <.001
intervention_dummy   -0.72 -1.70 – 0.27 .166
Random Parts
σ2   0.853
τ00, course_ID   0.354
Ncourse_ID   12
ICCcourse_ID   0.293
Observations   121
R2 / Ω02   .205 / .187
sjPlot::sjt.lmer(lme4::lmer(final_grade ~ intervention_dummy + (1 | course_ID), data = d))
    final_grade
    B CI p
Fixed Parts
(Intercept)   76.32 73.16 – 79.49 <.001
intervention_dummy   1.57 -2.78 – 5.91 .486
Random Parts
σ2   429.987
τ00, course_ID   15.339
Ncourse_ID   36
ICCcourse_ID   0.034
Observations   776
R2 / Ω02   .060 / .051

6B. With pre-values added (pre per-comp for final grades)

sjPlot::sjt.lmer(lme4::lmer(post_int ~ pre_int + intervention_dummy + (1 | course_ID), data = d))
    post_int
    B CI p
Fixed Parts
(Intercept)   1.24 0.13 – 2.35 .031
pre_int   0.73 0.52 – 0.94 <.001
intervention_dummy   -0.43 -1.06 – 0.21 .194
Random Parts
σ2   0.535
τ00, course_ID   0.078
Ncourse_ID   12
ICCcourse_ID   0.127
Observations   120
R2 / Ω02   .421 / .420
sjPlot::sjt.lmer(lme4::lmer(post_uv ~ pre_uv + intervention_dummy + (1 | course_ID), data = d))
    post_uv
    B CI p
Fixed Parts
(Intercept)   0.75 -0.20 – 1.71 .126
pre_uv   0.80 0.61 – 0.98 <.001
intervention_dummy   -0.22 -0.91 – 0.46 .525
Random Parts
σ2   0.556
τ00, course_ID   0.115
Ncourse_ID   12
ICCcourse_ID   0.172
Observations   118
R2 / Ω02   .457 / .456
sjPlot::sjt.lmer(lme4::lmer(final_grade ~ pre_percomp + intervention_dummy + (1 | course_ID), data = d))
    final_grade
    B CI p
Fixed Parts
(Intercept)   65.40 56.73 – 74.06 <.001
pre_percomp   2.99 0.83 – 5.16 .007
intervention_dummy   1.39 -3.05 – 5.82 .541
Random Parts
σ2   429.896
τ00, course_ID   16.048
Ncourse_ID   36
ICCcourse_ID   0.036
Observations   759
R2 / Ω02   .067 / .060

6C. With pre-values added + interactions with pre perceived competence

sjPlot::sjt.lmer(lme4::lmer(post_int ~ pre_int + intervention_dummy*pre_percomp + (1 | course_ID), data = d))
    post_int
    B CI p
Fixed Parts
(Intercept)   1.29 -2.32 – 4.91 .486
pre_int   0.69 0.44 – 0.95 <.001
intervention_dummy   -0.58 -4.31 – 3.15 .761
pre_percomp   0.03 -0.88 – 0.93 .955
intervention_dummy:pre_percomp   0.04 -0.86 – 0.95 .926
Random Parts
σ2   0.541
τ00, course_ID   0.088
Ncourse_ID   12
ICCcourse_ID   0.140
Observations   120
R2 / Ω02   .425 / .424
sjPlot::sjt.lmer(lme4::lmer(post_uv ~ pre_uv + intervention_dummy*pre_percomp + (1 | course_ID), data = d))
    post_uv
    B CI p
Fixed Parts
(Intercept)   0.72 -3.12 – 4.56 .715
pre_uv   0.77 0.56 – 0.99 <.001
intervention_dummy   -0.32 -4.23 – 3.59 .872
pre_percomp   0.03 -0.89 – 0.95 .948
intervention_dummy:pre_percomp   0.03 -0.92 – 0.98 .953
Random Parts
σ2   0.564
τ00, course_ID   0.125
Ncourse_ID   12
ICCcourse_ID   0.181
Observations   118
R2 / Ω02   .459 / .458
sjPlot::sjt.lmer(lme4::lmer(final_grade ~ pre_uv + intervention_dummy*pre_percomp + (1 | course_ID), data = d))
    final_grade
    B CI p
Fixed Parts
(Intercept)   64.19 51.48 – 76.89 <.001
pre_uv   -1.15 -3.76 – 1.45 .387
intervention_dummy   8.20 -8.42 – 24.83 .334
pre_percomp   4.52 1.07 – 7.97 .011
intervention_dummy:pre_percomp   -1.80 -6.14 – 2.54 .417
Random Parts
σ2   427.745
τ00, course_ID   16.074
Ncourse_ID   36
ICCcourse_ID   0.036
Observations   755
R2 / Ω02   .069 / .062

6D. With all variables added

sjPlot::sjt.lmer(lme4::lmer(post_uv ~ pre_uv + pre_int + pre_percomp + intervention_dummy + (1 | course_ID), data = d))
    post_uv
    B CI p
Fixed Parts
(Intercept)   0.54 -0.72 – 1.81 .400
pre_uv   0.76 0.51 – 1.00 <.001
pre_int   0.04 -0.26 – 0.34 .802
pre_percomp   0.05 -0.23 – 0.32 .750
intervention_dummy   -0.20 -0.90 – 0.50 .580
Random Parts
σ2   0.565
τ00, course_ID   0.118
Ncourse_ID   12
ICCcourse_ID   0.173
Observations   118
R2 / Ω02   .459 / .458
sjPlot::sjt.lmer(lme4::lmer(post_int ~ pre_uv + pre_int + pre_percomp + intervention_dummy + (1 | course_ID), data = d))
    post_int
    B CI p
Fixed Parts
(Intercept)   0.97 -0.24 – 2.19 .118
pre_uv   0.17 -0.07 – 0.41 .162
pre_int   0.61 0.32 – 0.90 <.001
pre_percomp   0.03 -0.24 – 0.30 .809
intervention_dummy   -0.43 -1.08 – 0.22 .199
Random Parts
σ2   0.532
τ00, course_ID   0.085
Ncourse_ID   12
ICCcourse_ID   0.137
Observations   118
R2 / Ω02   .444 / .443
sjPlot::sjt.lmer(lme4::lmer(final_grade ~ pre_uv + pre_int + pre_percomp + intervention_dummy + (1 | course_ID), data = d))
    final_grade
    B CI p
Fixed Parts
(Intercept)   55.28 43.45 – 67.11 <.001
pre_uv   -2.92 -5.70 – -0.14 .040
pre_int   5.78 2.48 – 9.08 <.001
pre_percomp   2.00 -0.83 – 4.84 .166
intervention_dummy   1.47 -2.95 – 5.88 .516
Random Parts
σ2   423.048
τ00, course_ID   15.755
Ncourse_ID   36
ICCcourse_ID   0.036
Observations   750
R2 / Ω02   .080 / .076

7. Other analyses

sjPlot::sjt.lmer(lme4::lmer(final_grade ~ pre_uv + pre_int + pre_percomp + (1 | course_ID), data = d))
    final_grade
    B CI p
Fixed Parts
(Intercept)   56.13 44.58 – 67.67 <.001
pre_uv   -2.98 -5.75 – -0.20 .036
pre_int   5.82 2.52 – 9.11 <.001
pre_percomp   2.00 -0.83 – 4.84 .166
Random Parts
σ2   422.661
τ00, course_ID   15.881
Ncourse_ID   36
ICCcourse_ID   0.036
Observations   750
R2 / Ω02   .081 / .076
sjPlot::sjt.lmer(lme4::lmer(final_grade ~ I(time_spent/60) + (1 | course_ID), data = d))
    final_grade
    B CI p
Fixed Parts
(Intercept)   64.66 61.38 – 67.93 <.001
I(time_spent/60)   0.38 0.32 – 0.44 <.001
Random Parts
σ2   359.037
τ00, course_ID   31.031
Ncourse_ID   36
ICCcourse_ID   0.080
Observations   776
R2 / Ω02   .216 / .214
sjPlot::sjt.lmer(lme4::lmer(final_grade ~ pre_uv + pre_int + pre_percomp + I(time_spent/60) + (1 | course_ID), data = d))
    final_grade
    B CI p
Fixed Parts
(Intercept)   47.11 36.15 – 58.07 <.001
pre_uv   -3.37 -5.98 – -0.76 .012
pre_int   5.31 2.21 – 8.40 <.001
pre_percomp   2.14 -0.47 – 4.74 .109
I(time_spent/60)   0.37 0.31 – 0.43 <.001
Random Parts
σ2   353.930
τ00, course_ID   30.568
Ncourse_ID   36
ICCcourse_ID   0.080
Observations   750
R2 / Ω02   .235 / .233

7A. With gender added

sjPlot::sjt.lmer(lme4::lmer(final_grade ~ pre_uv + pre_int + pre_percomp + gender + (1 | course_ID), data = d))
    final_grade
    B CI p
Fixed Parts
(Intercept)   60.35 48.59 – 72.11 <.001
pre_uv   -2.91 -5.68 – -0.14 .040
pre_int   4.96 1.64 – 8.29 .004
pre_percomp   2.27 -0.54 – 5.08 .114
gender (M)   -6.06 -9.38 – -2.74 <.001
Random Parts
σ2   414.508
τ00, course_ID   19.765
Ncourse_ID   36
ICCcourse_ID   0.046
Observations   750
R2 / Ω02   .101 / .097
sjPlot::sjt.lmer(lme4::lmer(final_grade ~ I(time_spent/60) + gender + (1 | course_ID), data = d))
    final_grade
    B CI p
Fixed Parts
(Intercept)   66.77 63.27 – 70.26 <.001
I(time_spent/60)   0.37 0.31 – 0.43 <.001
gender (M)   -6.09 -9.09 – -3.09 <.001
Random Parts
σ2   351.239
τ00, course_ID   34.669
Ncourse_ID   36
ICCcourse_ID   0.090
Observations   776
R2 / Ω02   .235 / .233
sjPlot::sjt.lmer(lme4::lmer(final_grade ~ pre_uv + pre_int + pre_percomp + gender + I(time_spent/60) + (1 | course_ID), data = d))
    final_grade
    B CI p
Fixed Parts
(Intercept)   50.54 39.38 – 61.69 <.001
pre_uv   -3.27 -5.87 – -0.67 .014
pre_int   4.64 1.52 – 7.75 .004
pre_percomp   2.34 -0.25 – 4.94 .077
gender (M)   -4.98 -8.06 – -1.91 .002
I(time_spent/60)   0.36 0.30 – 0.42 <.001
Random Parts
σ2   348.602
τ00, course_ID   34.424
Ncourse_ID   36
ICCcourse_ID   0.090
Observations   750
R2 / Ω02   .248 / .246

7A. Mediation analyses (not working quite right, I think)

library(mediation)

m1 <- lme4::lmer(time_spent ~ pre_uv + pre_int + pre_percomp + (1 | course_ID), data = d)
m2 <- lme4::lmer(final_grade ~ time_spent + pre_uv + pre_int + pre_percomp + (1 | course_ID), data = d)

med.outa <- mediate(m1, m2, treat = "pre_uv", mediator = "time_spent", dropobs = T, sims = 500)
med.outb <- mediate(m1, m2, treat = "pre_int", mediator = "time_spent", dropobs = T, sims = 500)

summary(med.outa)
summary(med.outb)

7B. SEM (but no accounting for nesting)

indirect effect of UV

library(lavaan)

d$ts_60 <- d$time_spent / 60
d$male_dummy <- ifelse(d$gender == "M", 1, 0)

m1 <- '
  # regressions
    ts_60 ~ pre_uv + pre_int + pre_percomp + male_dummy
    final_grade ~ ts_60 + pre_uv + pre_int + pre_percomp 
'

out1 <- sem(m1, data = d)
summary(out1)
## lavaan (0.5-23.1097) converged normally after  76 iterations
## 
##                                                   Used       Total
##   Number of observations                           750         809
## 
##   Estimator                                         ML
##   Minimum Function Test Statistic                4.889
##   Degrees of freedom                                 1
##   P-value (Chi-square)                           0.027
## 
## Parameter Estimates:
## 
##   Information                                 Expected
##   Standard Errors                             Standard
## 
## Regressions:
##                    Estimate  Std.Err  z-value  P(>|z|)
##   ts_60 ~                                             
##     pre_uv            3.617    1.444    2.505    0.012
##     pre_int           0.108    1.760    0.061    0.951
##     pre_percomp      -0.121    1.563   -0.077    0.939
##     male_dummy       -4.754    1.833   -2.593    0.010
##   final_grade ~                                       
##     ts_60             0.317    0.032   10.013    0.000
##     pre_uv           -4.052    1.264   -3.206    0.001
##     pre_int           5.335    1.509    3.535    0.000
##     pre_percomp       1.955    1.361    1.436    0.151
## 
## Variances:
##                    Estimate  Std.Err  z-value  P(>|z|)
##    .ts_60           506.077   26.134   19.365    0.000
##    .final_grade     384.902   19.876   19.365    0.000
m2 <- '
  # regressions
    ts_60 ~ a*pre_uv + pre_int + pre_percomp + male_dummy
    final_grade ~ b*ts_60 + c*pre_uv + pre_int + pre_percomp
    # indirect effect (a*b)
    ab := a*b
    # total effect
    total := c + (a*b)
'

out2 <- sem(m2, data = d)
summary(out2)
## lavaan (0.5-23.1097) converged normally after  76 iterations
## 
##                                                   Used       Total
##   Number of observations                           750         809
## 
##   Estimator                                         ML
##   Minimum Function Test Statistic                4.889
##   Degrees of freedom                                 1
##   P-value (Chi-square)                           0.027
## 
## Parameter Estimates:
## 
##   Information                                 Expected
##   Standard Errors                             Standard
## 
## Regressions:
##                    Estimate  Std.Err  z-value  P(>|z|)
##   ts_60 ~                                             
##     pre_uv     (a)    3.617    1.444    2.505    0.012
##     pre_int           0.108    1.760    0.061    0.951
##     pre_percmp       -0.121    1.563   -0.077    0.939
##     male_dummy       -4.754    1.833   -2.593    0.010
##   final_grade ~                                       
##     ts_60      (b)    0.317    0.032   10.013    0.000
##     pre_uv     (c)   -4.052    1.264   -3.206    0.001
##     pre_int           5.335    1.509    3.535    0.000
##     pre_percmp        1.955    1.361    1.436    0.151
## 
## Variances:
##                    Estimate  Std.Err  z-value  P(>|z|)
##    .ts_60           506.077   26.134   19.365    0.000
##    .final_grade     384.902   19.876   19.365    0.000
## 
## Defined Parameters:
##                    Estimate  Std.Err  z-value  P(>|z|)
##     ab                1.148    0.473    2.430    0.015
##     total            -2.904    1.340   -2.167    0.030

7C. Let’s run the same two models accounting for clustering

library(survey)
library(lavaan.survey)

group <- svydesign(ids= ~course_ID, data = d)
out1_c <- lavaan.survey(out1, group)
summary(out1_c)
## lavaan (0.5-23.1097) converged normally after  77 iterations
## 
##   Number of observations                           750
## 
##   Estimator                                         ML      Robust
##   Minimum Function Test Statistic                4.889       0.111
##   Degrees of freedom                                 1           1
##   P-value (Chi-square)                           0.027       0.739
##   Scaling correction factor                                 44.063
##     for the Satorra-Bentler correction
## 
## Parameter Estimates:
## 
##   Information                                 Expected
##   Standard Errors                           Robust.sem
## 
## Regressions:
##                    Estimate  Std.Err  z-value  P(>|z|)
##   ts_60 ~                                             
##     pre_uv            3.617    1.848    1.958    0.050
##     pre_int           0.108    2.033    0.053    0.958
##     pre_percomp      -0.121    2.282   -0.053    0.958
##     male_dummy       -4.754    2.375   -2.001    0.045
##   final_grade ~                                       
##     ts_60             0.317    0.029   10.890    0.000
##     pre_uv           -4.052    1.525   -2.657    0.008
##     pre_int           5.335    2.505    2.129    0.033
##     pre_percomp       1.955    1.817    1.076    0.282
## 
## Intercepts:
##                    Estimate  Std.Err  z-value  P(>|z|)
##    .ts_60            19.690    5.809    3.390    0.001
##    .final_grade      52.606    8.219    6.401    0.000
## 
## Variances:
##                    Estimate  Std.Err  z-value  P(>|z|)
##    .ts_60           506.028   72.959    6.936    0.000
##    .final_grade     384.864   28.598   13.458    0.000
out2_c <- lavaan.survey(out2, group)
summary(out2_c)
## lavaan (0.5-23.1097) converged normally after  77 iterations
## 
##   Number of observations                           750
## 
##   Estimator                                         ML      Robust
##   Minimum Function Test Statistic                4.889       0.111
##   Degrees of freedom                                 1           1
##   P-value (Chi-square)                           0.027       0.739
##   Scaling correction factor                                 44.063
##     for the Satorra-Bentler correction
## 
## Parameter Estimates:
## 
##   Information                                 Expected
##   Standard Errors                           Robust.sem
## 
## Regressions:
##                    Estimate  Std.Err  z-value  P(>|z|)
##   ts_60 ~                                             
##     pre_uv     (a)    3.617    1.848    1.958    0.050
##     pre_int           0.108    2.033    0.053    0.958
##     pre_percmp       -0.121    2.282   -0.053    0.958
##     male_dummy       -4.754    2.375   -2.001    0.045
##   final_grade ~                                       
##     ts_60      (b)    0.317    0.029   10.890    0.000
##     pre_uv     (c)   -4.052    1.525   -2.657    0.008
##     pre_int           5.335    2.505    2.129    0.033
##     pre_percmp        1.955    1.817    1.076    0.282
## 
## Intercepts:
##                    Estimate  Std.Err  z-value  P(>|z|)
##    .ts_60            19.690    5.809    3.390    0.001
##    .final_grade      52.606    8.219    6.401    0.000
## 
## Variances:
##                    Estimate  Std.Err  z-value  P(>|z|)
##    .ts_60           506.028   72.959    6.936    0.000
##    .final_grade     384.864   28.598   13.458    0.000
## 
## Defined Parameters:
##                    Estimate  Std.Err  z-value  P(>|z|)
##     ab                1.148    0.609    1.886    0.059
##     total            -2.904    1.409   -2.061    0.039