# LOAD LIBRARY
library(lavaan)
## Warning: package 'lavaan' was built under R version 4.5.3
## This is lavaan 0.6-21
## lavaan is FREE software! Please report any bugs.
library(psych)
## Warning: package 'psych' was built under R version 4.5.3
## 
## Attaching package: 'psych'
## The following object is masked from 'package:lavaan':
## 
##     cor2cov
library(corrplot)
## Warning: package 'corrplot' was built under R version 4.5.3
## corrplot 0.95 loaded
library(semPlot)
## Warning: package 'semPlot' was built under R version 4.5.3
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.5.3
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.5.3
## 
## Attaching package: 'ggplot2'
## The following objects are masked from 'package:psych':
## 
##     %+%, alpha
library(car)
## Warning: package 'car' was built under R version 4.5.3
## Loading required package: carData
## Warning: package 'carData' was built under R version 4.5.3
## Registered S3 method overwritten by 'car':
##   method           from
##   na.action.merMod lme4
## 
## Attaching package: 'car'
## The following object is masked from 'package:dplyr':
## 
##     recode
## The following object is masked from 'package:psych':
## 
##     logit
# LOAD DATA
data <- read.csv("C:\\Users\\zahir\\Downloads\\StressLevelDataset.csv")
str(data)
## 'data.frame':    1100 obs. of  21 variables:
##  $ anxiety_level               : int  14 15 12 16 16 20 4 17 13 6 ...
##  $ self_esteem                 : int  20 8 18 12 28 13 26 3 22 8 ...
##  $ mental_health_history       : int  0 1 1 1 0 1 0 1 1 0 ...
##  $ depression                  : int  11 15 14 15 7 21 6 22 12 27 ...
##  $ headache                    : int  2 5 2 4 2 3 1 4 3 4 ...
##  $ blood_pressure              : int  1 3 1 3 3 3 2 3 1 3 ...
##  $ sleep_quality               : int  2 1 2 1 5 1 4 1 2 1 ...
##  $ breathing_problem           : int  4 4 2 3 1 4 1 5 4 2 ...
##  $ noise_level                 : int  2 3 2 4 3 3 1 3 3 0 ...
##  $ living_conditions           : int  3 1 2 2 2 2 4 1 3 5 ...
##  $ safety                      : int  3 2 3 2 4 2 4 1 3 2 ...
##  $ basic_needs                 : int  2 2 2 2 3 1 4 1 3 2 ...
##  $ academic_performance        : int  3 1 2 2 4 2 5 1 3 2 ...
##  $ study_load                  : int  2 4 3 4 3 5 1 3 3 2 ...
##  $ teacher_student_relationship: int  3 1 3 1 1 2 4 2 2 1 ...
##  $ future_career_concerns      : int  3 5 2 4 2 5 1 4 3 5 ...
##  $ social_support              : int  2 1 2 1 1 1 3 1 3 1 ...
##  $ peer_pressure               : int  3 4 3 4 5 4 2 4 3 5 ...
##  $ extracurricular_activities  : int  3 5 2 4 0 4 2 4 2 3 ...
##  $ bullying                    : int  2 5 2 5 5 5 1 5 2 4 ...
##  $ stress_level                : int  1 2 1 2 1 2 0 2 1 1 ...
head(data)
##   anxiety_level self_esteem mental_health_history depression headache
## 1            14          20                     0         11        2
## 2            15           8                     1         15        5
## 3            12          18                     1         14        2
## 4            16          12                     1         15        4
## 5            16          28                     0          7        2
## 6            20          13                     1         21        3
##   blood_pressure sleep_quality breathing_problem noise_level living_conditions
## 1              1             2                 4           2                 3
## 2              3             1                 4           3                 1
## 3              1             2                 2           2                 2
## 4              3             1                 3           4                 2
## 5              3             5                 1           3                 2
## 6              3             1                 4           3                 2
##   safety basic_needs academic_performance study_load
## 1      3           2                    3          2
## 2      2           2                    1          4
## 3      3           2                    2          3
## 4      2           2                    2          4
## 5      4           3                    4          3
## 6      2           1                    2          5
##   teacher_student_relationship future_career_concerns social_support
## 1                            3                      3              2
## 2                            1                      5              1
## 3                            3                      2              2
## 4                            1                      4              1
## 5                            1                      2              1
## 6                            2                      5              1
##   peer_pressure extracurricular_activities bullying stress_level
## 1             3                          3        2            1
## 2             4                          5        5            2
## 3             3                          2        2            1
## 4             4                          4        5            2
## 5             5                          0        5            1
## 6             4                          4        5            2
# CEK KUALITAS DATA
cat("  CEK KUALITAS DATA\n")
##   CEK KUALITAS DATA
cat("Dimensi data   :", dim(data), "\n")
## Dimensi data   : 1100 21
cat("Missing values :", sum(is.na(data)), "\n")
## Missing values : 0
cat("Duplikat       :", sum(duplicated(data)), "\n")
## Duplikat       : 0
data <- na.omit(data)
cat("Dimensi setelah na.omit:", dim(data), "\n")
## Dimensi setelah na.omit: 1100 21
# SELEKSI & REVERSE CODING
# Reverse coding untuk indikator yang loading-nya negatif
sem_data <- data %>%
  select(
    anxiety_level, self_esteem, mental_health_history, depression,
    headache, sleep_quality, breathing_problem,
    noise_level, living_conditions, safety, basic_needs,
    academic_performance, study_load, teacher_student_relationship,
    future_career_concerns, social_support, peer_pressure,
    extracurricular_activities, bullying, stress_level
  ) %>%
  mutate(
    self_esteem = (30) - self_esteem,
    sleep_quality = (5) - sleep_quality,
    living_conditions = (5) - living_conditions,
    safety = (5) - safety,
    basic_needs = (5) - basic_needs,
    study_load = (5) - study_load,
    future_career_concerns = (5) - future_career_concerns,
    peer_pressure = (5) - peer_pressure,
    extracurricular_activities = (5) - extracurricular_activities,
    bullying = (5) - bullying
  )
cat("\nVariabel yang digunakan:", ncol(sem_data), "\n")
## 
## Variabel yang digunakan: 20
cat("Jumlah observasi      :", nrow(sem_data), "\n")
## Jumlah observasi      : 1100
# STATISTIK DESKRIPTIF
cat("  STATISTIK DESKRIPTIF\n")
##   STATISTIK DESKRIPTIF
summary(sem_data)
##  anxiety_level    self_esteem    mental_health_history   depression   
##  Min.   : 0.00   Min.   : 0.00   Min.   :0.0000        Min.   : 0.00  
##  1st Qu.: 6.00   1st Qu.: 4.00   1st Qu.:0.0000        1st Qu.: 6.00  
##  Median :11.00   Median :11.00   Median :0.0000        Median :12.00  
##  Mean   :11.06   Mean   :12.22   Mean   :0.4927        Mean   :12.56  
##  3rd Qu.:16.00   3rd Qu.:19.00   3rd Qu.:1.0000        3rd Qu.:19.00  
##  Max.   :21.00   Max.   :30.00   Max.   :1.0000        Max.   :27.00  
##     headache     sleep_quality  breathing_problem  noise_level   
##  Min.   :0.000   Min.   :0.00   Min.   :0.000     Min.   :0.000  
##  1st Qu.:1.000   1st Qu.:1.00   1st Qu.:2.000     1st Qu.:2.000  
##  Median :3.000   Median :2.50   Median :3.000     Median :3.000  
##  Mean   :2.508   Mean   :2.34   Mean   :2.754     Mean   :2.649  
##  3rd Qu.:3.000   3rd Qu.:4.00   3rd Qu.:4.000     3rd Qu.:3.000  
##  Max.   :5.000   Max.   :5.00   Max.   :5.000     Max.   :5.000  
##  living_conditions     safety       basic_needs    academic_performance
##  Min.   :0.000     Min.   :0.000   Min.   :0.000   Min.   :0.000       
##  1st Qu.:2.000     1st Qu.:1.000   1st Qu.:1.000   1st Qu.:2.000       
##  Median :3.000     Median :3.000   Median :2.000   Median :2.000       
##  Mean   :2.482     Mean   :2.263   Mean   :2.227   Mean   :2.773       
##  3rd Qu.:3.000     3rd Qu.:3.000   3rd Qu.:3.000   3rd Qu.:4.000       
##  Max.   :5.000     Max.   :5.000   Max.   :5.000   Max.   :5.000       
##    study_load    teacher_student_relationship future_career_concerns
##  Min.   :0.000   Min.   :0.000                Min.   :0.000         
##  1st Qu.:2.000   1st Qu.:2.000                1st Qu.:1.000         
##  Median :3.000   Median :2.000                Median :3.000         
##  Mean   :2.378   Mean   :2.648                Mean   :2.351         
##  3rd Qu.:3.000   3rd Qu.:4.000                3rd Qu.:4.000         
##  Max.   :5.000   Max.   :5.000                Max.   :5.000         
##  social_support  peer_pressure   extracurricular_activities    bullying    
##  Min.   :0.000   Min.   :0.000   Min.   :0.000              Min.   :0.000  
##  1st Qu.:1.000   1st Qu.:1.000   1st Qu.:1.000              1st Qu.:1.000  
##  Median :2.000   Median :3.000   Median :2.500              Median :2.000  
##  Mean   :1.882   Mean   :2.265   Mean   :2.233              Mean   :2.383  
##  3rd Qu.:3.000   3rd Qu.:3.000   3rd Qu.:3.000              3rd Qu.:4.000  
##  Max.   :3.000   Max.   :5.000   Max.   :5.000              Max.   :5.000  
##   stress_level   
##  Min.   :0.0000  
##  1st Qu.:0.0000  
##  Median :1.0000  
##  Mean   :0.9964  
##  3rd Qu.:2.0000  
##  Max.   :2.0000
# VISUALISASI DISTRIBUSI
par(mfrow = c(4, 6), mar = c(3, 3, 2, 1))
for (col in names(sem_data)) {
  hist(sem_data[[col]], main = col, col = "steelblue",
       border = "white", xlab = "", cex.main = 0.75)
}
par(mfrow = c(1, 1))

par(mfrow = c(4, 6), mar = c(3, 3, 2, 1))
for (col in names(sem_data)) {
  boxplot(sem_data[[col]], main = col, col = "#AED6F1",
          border = "navy", cex.main = 0.75)
}
par(mfrow = c(1, 1))

# MATRIKS KORELASI
cor_matrix <- cor(sem_data, use = "complete.obs")
corrplot(
  cor_matrix,
  method = "color",
  type = "upper",
  tl.col = "black",
  tl.cex = 0.4,
  tl.srt = 45,
  addCoef.col = "black",
  number.cex = 0.25,
  cl.cex = 0.8,
  col = colorRampPalette(c("blue", "white", "red"))(200),
  title = "Matriks Korelasi – Student Stress Factors",
  mar = c(0, 0, 2, 0)
)

# DEFINISI sem_core
sem_core <- sem_data %>% select(-stress_level)

# UJI NORMALITAS MULTIVARIAT (MARDIA)
cat("  UJI NORMALITAS MULTIVARIAT (MARDIA)\n")
##   UJI NORMALITAS MULTIVARIAT (MARDIA)
mardia_result <- mardia(sem_core)

print(mardia_result)
## Call: mardia(x = sem_core)
## 
## Mardia tests of multivariate skew and kurtosis
## Use describe(x) the to get univariate tests
## n.obs = 1100   num.vars =  19 
## b1p =  107.46   skew =  19700.84  with probability  <=  0
##  small sample skew =  19759.95  with probability <=  0
## b2p =  856.36   kurtosis =  268.49  with probability <=  0
skew_p <- mardia_result$skew.p
kurt_p <- mardia_result$kurtosis.p
if (isTRUE(!is.na(skew_p) && !is.na(kurt_p) && skew_p > 0.05 && kurt_p > 0.05)) {
  cat("Kesimpulan: Data NORMAL Multivariat\n")
} else {
  cat("Kesimpulan: Data TIDAK Normal Multivariat\n")
  cat("-> Gunakan estimator MLR di lavaan\n")
}
## Kesimpulan: Data TIDAK Normal Multivariat
## -> Gunakan estimator MLR di lavaan
# Uji normalitas univariat
cat("\n── Normalitas Univariat per Variabel ──\n")
## 
## ── Normalitas Univariat per Variabel ──
n_obs <- nrow(sem_core)
hasil_uji <- data.frame(
  Variabel  = names(sem_core),
  Statistic = NA_real_,
  P_value   = NA_real_,
  Status    = NA_character_,
  stringsAsFactors = FALSE
)
if (n_obs <= 5000) {
  cat("(Shapiro-Wilk, n =", n_obs, ")\n\n")
  for (i in seq_along(names(sem_core))) {
    test <- shapiro.test(sem_core[[i]])
    hasil_uji$Statistic[i] <- round(test$statistic, 4)
    hasil_uji$P_value[i]   <- round(test$p.value,   4)
    hasil_uji$Status[i]    <- ifelse(
      test$p.value > 0.05, "Normal", "Tidak Normal")
  }
} else {
  cat("(Kolmogorov-Smirnov, n =", n_obs, ")\n\n")
  for (i in seq_along(names(sem_core))) {
    x    <- scale(sem_core[[i]])
    test <- ks.test(x, "pnorm")
    hasil_uji$Statistic[i] <- round(test$statistic, 4)
    hasil_uji$P_value[i]   <- round(test$p.value,   4)
    hasil_uji$Status[i]    <- ifelse(
      test$p.value > 0.05, "Normal", "Tidak Normal")
  }
}
## (Shapiro-Wilk, n = 1100 )
print(hasil_uji)
##                        Variabel Statistic P_value       Status
## 1                 anxiety_level    0.9580       0 Tidak Normal
## 2                   self_esteem    0.9325       0 Tidak Normal
## 3         mental_health_history    0.6365       0 Tidak Normal
## 4                    depression    0.9589       0 Tidak Normal
## 5                      headache    0.9023       0 Tidak Normal
## 6                 sleep_quality    0.8854       0 Tidak Normal
## 7             breathing_problem    0.9149       0 Tidak Normal
## 8                   noise_level    0.9257       0 Tidak Normal
## 9             living_conditions    0.9279       0 Tidak Normal
## 10                       safety    0.9116       0 Tidak Normal
## 11                  basic_needs    0.9134       0 Tidak Normal
## 12         academic_performance    0.9064       0 Tidak Normal
## 13                   study_load    0.9259       0 Tidak Normal
## 14 teacher_student_relationship    0.9188       0 Tidak Normal
## 15       future_career_concerns    0.8859       0 Tidak Normal
## 16               social_support    0.7972       0 Tidak Normal
## 17                peer_pressure    0.9089       0 Tidak Normal
## 18   extracurricular_activities    0.9134       0 Tidak Normal
## 19                     bullying    0.8914       0 Tidak Normal
cat("\nCatatan: Estimator MLR robust terhadap non-normalitas.\n")
## 
## Catatan: Estimator MLR robust terhadap non-normalitas.
# UJI KMO
cat("UJI KMO\n")
## UJI KMO
cor_core   <- cor(sem_core, use = "complete.obs")
kmo_result <- KMO(cor_core)
print(kmo_result)
## Kaiser-Meyer-Olkin factor adequacy
## Call: KMO(r = cor_core)
## Overall MSA =  0.98
## MSA for each item = 
##                anxiety_level                  self_esteem 
##                         0.99                         0.98 
##        mental_health_history                   depression 
##                         0.99                         0.99 
##                     headache                sleep_quality 
##                         0.98                         0.98 
##            breathing_problem                  noise_level 
##                         0.98                         0.99 
##            living_conditions                       safety 
##                         0.99                         0.98 
##                  basic_needs         academic_performance 
##                         0.98                         0.98 
##                   study_load teacher_student_relationship 
##                         0.99                         0.98 
##       future_career_concerns               social_support 
##                         0.98                         0.96 
##                peer_pressure   extracurricular_activities 
##                         0.98                         0.98 
##                     bullying 
##                         0.98
msa <- kmo_result$MSA
if (msa >= 0.90) {
  cat("MSA =", round(msa, 3), "-> Marvelous (Sangat Layak)\n")
} else if (msa >= 0.80) {
  cat("MSA =", round(msa, 3), "-> Meritorious (Layak)\n")
} else if (msa >= 0.70) {
  cat("MSA =", round(msa, 3), "-> Middling (Cukup Layak)\n")
} else if (msa >= 0.60) {
  cat("MSA =", round(msa, 3), "-> Mediocre (Pas-pasan)\n")
} else if (msa >= 0.50) {
  cat("MSA =", round(msa, 3), "-> Miserable (Hampir Tidak Layak)\n")
} else {
  cat("MSA =", round(msa, 3), "-> Tidak Layak untuk SEM\n")
}
## MSA = 0.983 -> Marvelous (Sangat Layak)
# UJI BARTLETT
cat("  UJI BARTLETT\n")
##   UJI BARTLETT
bartlett_result <- cortest.bartlett(cor_core, n = nrow(sem_core))
bartlett_result
## $chisq
## [1] 16086.67
## 
## $p.value
## [1] 0
## 
## $df
## [1] 171
if (bartlett_result$p.value < 0.05) {
  cat("Kesimpulan: p < 0.05 -> Data LAYAK untuk analisis SEM\n")
} else {
  cat("Kesimpulan: p >= 0.05 -> Data tidak layak untuk SEM\n")
}
## Kesimpulan: p < 0.05 -> Data LAYAK untuk analisis SEM
# Uji Multikulinearitas
model_vif <- lm(
  anxiety_level ~ self_esteem + depression +
    headache + sleep_quality + breathing_problem +
    study_load + academic_performance + future_career_concerns +
    peer_pressure + bullying + extracurricular_activities,
  data = sem_core
)
vif(model_vif)
##                self_esteem                 depression 
##                   2.736896                   2.947854 
##                   headache              sleep_quality 
##                   2.390172                   2.865135 
##          breathing_problem                 study_load 
##                   1.678886                   1.864410 
##       academic_performance     future_career_concerns 
##                   2.404494                   3.231987 
##              peer_pressure                   bullying 
##                   2.382107                   2.995177 
## extracurricular_activities 
##                   2.357690
max_vif <- max(vif(model_vif))
if (max_vif < 5) {
  cat("Kesimpulan: nilai VIF maksimum =", round(max_vif, 3),
      "-> Tidak terdapat masalah multikolinearitas (layak untuk SEM)\n")
} else {
  cat("Kesimpulan: nilai VIF maksimum =", round(max_vif, 3),
      "-> Terdapat multikolinearitas (perlu perbaikan model)\n")
}
## Kesimpulan: nilai VIF maksimum = 3.232 -> Tidak terdapat masalah multikolinearitas (layak untuk SEM)
# STANDARDISASI DATA
cat("\n── Standardisasi Data ──\n")
## 
## ── Standardisasi Data ──
sem_core_scaled <- as.data.frame(scale(sem_core))
sem_data_scaled <- as.data.frame(scale(sem_data))
cat("Mean tiap variabel (harus ~0):\n")
## Mean tiap variabel (harus ~0):
print(round(colMeans(sem_core_scaled), 3))
##                anxiety_level                  self_esteem 
##                            0                            0 
##        mental_health_history                   depression 
##                            0                            0 
##                     headache                sleep_quality 
##                            0                            0 
##            breathing_problem                  noise_level 
##                            0                            0 
##            living_conditions                       safety 
##                            0                            0 
##                  basic_needs         academic_performance 
##                            0                            0 
##                   study_load teacher_student_relationship 
##                            0                            0 
##       future_career_concerns               social_support 
##                            0                            0 
##                peer_pressure   extracurricular_activities 
##                            0                            0 
##                     bullying 
##                            0
cat("\nSD tiap variabel (harus ~1):\n")
## 
## SD tiap variabel (harus ~1):
print(round(apply(sem_core_scaled, 2, sd), 3))
##                anxiety_level                  self_esteem 
##                            1                            1 
##        mental_health_history                   depression 
##                            1                            1 
##                     headache                sleep_quality 
##                            1                            1 
##            breathing_problem                  noise_level 
##                            1                            1 
##            living_conditions                       safety 
##                            1                            1 
##                  basic_needs         academic_performance 
##                            1                            1 
##                   study_load teacher_student_relationship 
##                            1                            1 
##       future_career_concerns               social_support 
##                            1                            1 
##                peer_pressure   extracurricular_activities 
##                            1                            1 
##                     bullying 
##                            1
# MODEL CFA
cat("CONFIRMATORY FACTOR ANALYSIS (CFA)\n")
## CONFIRMATORY FACTOR ANALYSIS (CFA)
cfa_model <- '
  Stress =~ anxiety_level + depression + self_esteem +
            sleep_quality + peer_pressure + bullying +
            academic_performance + study_load
'
fit_cfa <- cfa(
  cfa_model,
  data = sem_core_scaled,
  estimator = "MLR"
)
cat("\nKonvergen CFA?", lavInspect(fit_cfa, "converged"), "\n")
## 
## Konvergen CFA? TRUE
summary(fit_cfa, fit.measures = TRUE, standardized = TRUE)
## lavaan 0.6-21 ended normally after 23 iterations
## 
##   Estimator                                         ML
##   Optimization method                           NLMINB
##   Number of model parameters                        16
## 
##   Number of observations                          1100
## 
## Model Test User Model:
##                                               Standard      Scaled
##   Test Statistic                                67.196      25.091
##   Degrees of freedom                                20          20
##   P-value (Chi-square)                           0.000       0.198
##   Scaling correction factor                                  2.678
##     Yuan-Bentler correction (Mplus variant)                       
## 
## Model Test Baseline Model:
## 
##   Test statistic                              6156.303    2416.179
##   Degrees of freedom                                28          28
##   P-value                                        0.000       0.000
##   Scaling correction factor                                  2.548
## 
## User Model versus Baseline Model:
## 
##   Comparative Fit Index (CFI)                    0.992       0.998
##   Tucker-Lewis Index (TLI)                       0.989       0.997
##                                                                   
##   Robust Comparative Fit Index (CFI)                         0.998
##   Robust Tucker-Lewis Index (TLI)                            0.997
## 
## Loglikelihood and Information Criteria:
## 
##   Loglikelihood user model (H0)              -9438.104   -9438.104
##   Scaling correction factor                                  1.346
##       for the MLR correction                                      
##   Loglikelihood unrestricted model (H1)      -9404.506   -9404.506
##   Scaling correction factor                                  2.086
##       for the MLR correction                                      
##                                                                   
##   Akaike (AIC)                               18908.207   18908.207
##   Bayesian (BIC)                             18988.256   18988.256
##   Sample-size adjusted Bayesian (SABIC)      18937.436   18937.436
## 
## Root Mean Square Error of Approximation:
## 
##   RMSEA                                          0.046       0.015
##   90 Percent confidence interval - lower         0.034       0.000
##   90 Percent confidence interval - upper         0.059       0.026
##   P-value H_0: RMSEA <= 0.050                    0.669       1.000
##   P-value H_0: RMSEA >= 0.080                    0.000       0.000
##                                                                   
##   Robust RMSEA                                               0.025
##   90 Percent confidence interval - lower                     0.000
##   90 Percent confidence interval - upper                     0.052
##   P-value H_0: Robust RMSEA <= 0.050                         0.935
##   P-value H_0: Robust RMSEA >= 0.080                         0.000
## 
## Standardized Root Mean Square Residual:
## 
##   SRMR                                           0.015       0.015
## 
## Parameter Estimates:
## 
##   Standard errors                             Sandwich
##   Information bread                           Observed
##   Observed information based on                Hessian
## 
## Latent Variables:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##   Stress =~                                                             
##     anxiety_level     1.000                               0.842    0.842
##     depression        0.985    0.025   39.855    0.000    0.829    0.830
##     self_esteem       0.954    0.024   39.786    0.000    0.803    0.804
##     sleep_quality     0.995    0.021   46.297    0.000    0.837    0.838
##     peer_pressure    -0.910    0.024  -37.503    0.000   -0.766   -0.767
##     bullying         -0.987    0.021  -46.609    0.000   -0.831   -0.832
##     acadmc_prfrmnc   -0.923    0.024  -38.853    0.000   -0.777   -0.778
##     study_load       -0.827    0.026  -32.293    0.000   -0.697   -0.697
## 
## Variances:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##    .anxiety_level     0.290    0.021   14.101    0.000    0.290    0.291
##    .depression        0.312    0.022   14.029    0.000    0.312    0.312
##    .self_esteem       0.354    0.025   14.174    0.000    0.354    0.354
##    .sleep_quality     0.298    0.023   12.703    0.000    0.298    0.298
##    .peer_pressure     0.412    0.029   14.184    0.000    0.412    0.412
##    .bullying          0.308    0.025   12.541    0.000    0.308    0.308
##    .acadmc_prfrmnc    0.395    0.026   15.165    0.000    0.395    0.395
##    .study_load        0.514    0.030   16.998    0.000    0.514    0.514
##     Stress            0.709    0.030   23.440    0.000    1.000    1.000
cat("\n── Indeks Fit CFA ──\n")
## 
## ── Indeks Fit CFA ──
round(fitMeasures(fit_cfa, c(
  "chisq", "cfi", "tli", "rmsea", "srmr"
)), 3)
##  chisq    cfi    tli  rmsea   srmr 
## 67.196  0.992  0.989  0.046  0.015
# EVALUASI OUTER MODEL
cat("  EVALUASI OUTER MODEL\n")
##   EVALUASI OUTER MODEL
# Loading Factor
std_sol <- standardizedSolution(fit_cfa) %>%
  filter(op == "=~") %>%
  select(lhs, rhs, est.std, pvalue) %>%
  rename(
    Konstruk  = lhs,
    Indikator = rhs,
    Loading   = est.std,
    P_value   = pvalue
  ) %>%
  mutate(
    Status = ifelse(abs(Loading) >= 0.70, "✓ Valid", "✗ Perlu ditinjau")
  )
cat("\n── Loading Factor (ideal >= 0.70) ──\n")
## 
## ── Loading Factor (ideal >= 0.70) ──
print(std_sol)
##   Konstruk            Indikator Loading P_value           Status
## 1   Stress        anxiety_level   0.842       0          ✓ Valid
## 2   Stress           depression   0.830       0          ✓ Valid
## 3   Stress          self_esteem   0.804       0          ✓ Valid
## 4   Stress        sleep_quality   0.838       0          ✓ Valid
## 5   Stress        peer_pressure  -0.767       0          ✓ Valid
## 6   Stress             bullying  -0.832       0          ✓ Valid
## 7   Stress academic_performance  -0.778       0          ✓ Valid
## 8   Stress           study_load  -0.697       0 ✗ Perlu ditinjau
# AVE – menggunakan nilai absolut loading
ave_df <- std_sol %>%
  group_by(Konstruk) %>%
  summarise(
    AVE = mean(Loading^2, na.rm = TRUE),
    Status = ifelse(mean(Loading^2, na.rm = TRUE) >= 0.50,
                    "✓ Valid", "✗ < 0.50"),
    .groups = "drop"
  )
cat("\n── AVE (ideal >= 0.50) ──\n")
## 
## ── AVE (ideal >= 0.50) ──
print(ave_df)
## # A tibble: 1 × 3
##   Konstruk   AVE Status 
##   <chr>    <dbl> <chr>  
## 1 Stress   0.639 ✓ Valid
# Composite Reliability – formula yang benar menggunakan abs(loading)
cr_df <- std_sol %>%
  group_by(Konstruk) %>%
  summarise(
    sum_lam = sum(abs(Loading), na.rm = TRUE),
    sum_lam2 = sum(Loading^2, na.rm = TRUE),
    n_item = n(),
    CR = sum_lam^2 / (sum_lam^2 + (n_item - sum_lam2)),
    Status = ifelse(CR >= 0.70, "✓ Reliabel", "✗ < 0.70"),
    .groups = "drop"
  )
cat("\n── Composite Reliability (ideal >= 0.70) ──\n")
## 
## ── Composite Reliability (ideal >= 0.70) ──
print(cr_df)
## # A tibble: 1 × 6
##   Konstruk sum_lam sum_lam2 n_item    CR Status    
##   <chr>      <dbl>    <dbl>  <int> <dbl> <chr>     
## 1 Stress      6.39     5.12      8 0.934 ✓ Reliabel
# CRONBACH'S ALPHA
alpha_stress <- psych::alpha(
  sem_core %>%
    select(anxiety_level, depression, self_esteem,
           sleep_quality, peer_pressure, bullying,
           academic_performance, study_load),
  check.keys = TRUE
)
## Warning in psych::alpha(sem_core %>% select(anxiety_level, depression, self_esteem, : Some items were negatively correlated with the first principal component and were automatically reversed.
##  This is indicated by a negative sign for the variable name.
alpha_summary <- data.frame(
  Konstruk = "Stress",
  Alpha = round(alpha_stress$total$raw_alpha, 3),
  Status = ifelse(alpha_stress$total$raw_alpha >= 0.70,
                  "✓ Reliabel", "✗ < 0.70")
)
print(alpha_summary)
##   Konstruk Alpha     Status
## 1   Stress 0.819 ✓ Reliabel
cat("\n── Cronbach's Alpha (CONSISTENT WITH CFA) ──\n")
## 
## ── Cronbach's Alpha (CONSISTENT WITH CFA) ──
print(alpha_summary)
##   Konstruk Alpha     Status
## 1   Stress 0.819 ✓ Reliabel
# korelasi latent (lebih aman pakai standardized solution)
cat("\n── VARIANCE LATENT (Stress) ──\n")
## 
## ── VARIANCE LATENT (Stress) ──
lavInspect(fit_cfa, "cov.lv")
##        Stress
## Stress  0.709
# Visualisasi CFA
semPaths(
  fit_cfa,
  what           = "std",
  layout         = "tree",
  edge.label.cex = 0.8,
  label.cex      = 1.2,   
  sizeMan        = 6,     
  sizeLat        = 10,    
  nCharNodes     = 0,
  style          = "lisrel",
  color          = list(lat = "#AED6F1", man = "#FDEBD0")
)
title("Path Diagram – CFA", line = 3)

cat("\n── FIT MODEL SUMMARY ──\n")
## 
## ── FIT MODEL SUMMARY ──
fitMeasures(fit_cfa, c("cfi","tli","rmsea","srmr"))
##   cfi   tli rmsea  srmr 
## 0.992 0.989 0.046 0.015
# MODEL SEM FULL
cat("\n=== SEM MODEL ===\n")
## 
## === SEM MODEL ===
sem_model <- '
  Stress =~ anxiety_level + depression + self_esteem +
            sleep_quality + headache + breathing_problem +
            academic_performance + study_load +
            peer_pressure + bullying

  stress_level ~ Stress
'
fit_sem <- sem(sem_model, data = sem_data_scaled, estimator = "MLR")
summary(fit_sem, fit.measures = TRUE, standardized = TRUE, rsquare = TRUE)
## lavaan 0.6-21 ended normally after 31 iterations
## 
##   Estimator                                         ML
##   Optimization method                           NLMINB
##   Number of model parameters                        22
## 
##   Number of observations                          1100
## 
## Model Test User Model:
##                                               Standard      Scaled
##   Test Statistic                               142.396      51.305
##   Degrees of freedom                                44          44
##   P-value (Chi-square)                           0.000       0.209
##   Scaling correction factor                                  2.775
##     Yuan-Bentler correction (Mplus variant)                       
## 
## Model Test Baseline Model:
## 
##   Test statistic                              9305.440    3508.510
##   Degrees of freedom                                55          55
##   P-value                                        0.000       0.000
##   Scaling correction factor                                  2.652
## 
## User Model versus Baseline Model:
## 
##   Comparative Fit Index (CFI)                    0.989       0.998
##   Tucker-Lewis Index (TLI)                       0.987       0.997
##                                                                   
##   Robust Comparative Fit Index (CFI)                         0.998
##   Robust Tucker-Lewis Index (TLI)                            0.997
## 
## Loglikelihood and Information Criteria:
## 
##   Loglikelihood user model (H0)             -12582.131  -12582.131
##   Scaling correction factor                                  1.306
##       for the MLR correction                                      
##   Loglikelihood unrestricted model (H1)     -12510.934  -12510.934
##   Scaling correction factor                                  2.286
##       for the MLR correction                                      
##                                                                   
##   Akaike (AIC)                               25208.263   25208.263
##   Bayesian (BIC)                             25318.330   25318.330
##   Sample-size adjusted Bayesian (SABIC)      25248.453   25248.453
## 
## Root Mean Square Error of Approximation:
## 
##   RMSEA                                          0.045       0.012
##   90 Percent confidence interval - lower         0.037       0.000
##   90 Percent confidence interval - upper         0.053       0.020
##   P-value H_0: RMSEA <= 0.050                    0.827       1.000
##   P-value H_0: RMSEA >= 0.080                    0.000       0.000
##                                                                   
##   Robust RMSEA                                               0.020
##   90 Percent confidence interval - lower                     0.000
##   90 Percent confidence interval - upper                     0.041
##   P-value H_0: Robust RMSEA <= 0.050                         0.995
##   P-value H_0: Robust RMSEA >= 0.080                         0.000
## 
## Standardized Root Mean Square Residual:
## 
##   SRMR                                           0.016       0.016
## 
## Parameter Estimates:
## 
##   Standard errors                             Sandwich
##   Information bread                           Observed
##   Observed information based on                Hessian
## 
## Latent Variables:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##   Stress =~                                                             
##     anxiety_level     1.000                               0.834    0.834
##     depression        0.991    0.023   42.261    0.000    0.826    0.827
##     self_esteem       0.974    0.023   43.040    0.000    0.812    0.812
##     sleep_quality     1.000    0.020   50.062    0.000    0.834    0.835
##     headache          0.928    0.023   40.613    0.000    0.774    0.775
##     breathng_prblm    0.772    0.023   33.386    0.000    0.643    0.644
##     acadmc_prfrmnc   -0.941    0.023  -40.862    0.000   -0.785   -0.785
##     study_load       -0.836    0.025  -33.930    0.000   -0.697   -0.697
##     peer_pressure    -0.922    0.023  -39.771    0.000   -0.769   -0.769
##     bullying         -0.995    0.020  -49.241    0.000   -0.830   -0.830
## 
## Regressions:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##   stress_level ~                                                        
##     Stress            1.083    0.019   56.076    0.000    0.903    0.904
## 
## Variances:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##    .anxiety_level     0.304    0.021   14.675    0.000    0.304    0.304
##    .depression        0.317    0.022   14.579    0.000    0.317    0.317
##    .self_esteem       0.340    0.022   15.472    0.000    0.340    0.340
##    .sleep_quality     0.303    0.022   13.607    0.000    0.303    0.304
##    .headache          0.400    0.026   15.658    0.000    0.400    0.400
##    .breathng_prblm    0.585    0.026   22.282    0.000    0.585    0.586
##    .acadmc_prfrmnc    0.383    0.025   15.434    0.000    0.383    0.383
##    .study_load        0.513    0.029   17.689    0.000    0.513    0.514
##    .peer_pressure     0.408    0.026   15.481    0.000    0.408    0.409
##    .bullying          0.310    0.024   13.188    0.000    0.310    0.311
##    .stress_level      0.183    0.018   10.290    0.000    0.183    0.183
##     Stress            0.695    0.030   23.520    0.000    1.000    1.000
## 
## R-Square:
##                    Estimate
##     anxiety_level     0.696
##     depression        0.683
##     self_esteem       0.660
##     sleep_quality     0.696
##     headache          0.600
##     breathng_prblm    0.414
##     acadmc_prfrmnc    0.617
##     study_load        0.486
##     peer_pressure     0.591
##     bullying          0.689
##     stress_level      0.817
# EVALUASI INNER MODEL
cat("  EVALUASI INNER MODEL\n")
##   EVALUASI INNER MODEL
fit_idx <- fitMeasures(fit_sem, c("cfi","tli","rmsea","srmr"))
print(round(fit_idx, 3))
##   cfi   tli rmsea  srmr 
## 0.989 0.987 0.045 0.016
cat("\n── Panduan Interpretasi Fit ──\n")
## 
## ── Panduan Interpretasi Fit ──
cat("CFI / TLI  >= 0.90  -> Fit Baik\n")
## CFI / TLI  >= 0.90  -> Fit Baik
cat("RMSEA      <  0.08  -> Fit Baik (≤0.05 sangat baik)\n")
## RMSEA      <  0.08  -> Fit Baik (≤0.05 sangat baik)
cat("SRMR       <  0.08  -> Fit Baik\n")
## SRMR       <  0.08  -> Fit Baik
cat("p-value    >  0.05  -> Fit sempurna (jarang terjadi di SEM)\n")
## p-value    >  0.05  -> Fit sempurna (jarang terjadi di SEM)
# Path Coefficient
cat("\n── Path Coefficients (Inner Model) ──\n")
## 
## ── Path Coefficients (Inner Model) ──
param_est <- parameterEstimates(fit_sem, standardized = TRUE) %>%
  filter(op == "~") %>%
  select(lhs, rhs, est, se, z, pvalue, std.all) %>%
  mutate(Signif = ifelse(pvalue <= 0.05, "Signifikan", "Tidak"))
print(param_est)
##            lhs    rhs   est    se      z pvalue std.all     Signif
## 1 stress_level Stress 1.083 0.019 56.076      0   0.904 Signifikan
# R-Square
r2 <- lavInspect(fit_sem, "r2")
cat("R2 stress_level =", r2, "\n")
## R2 stress_level = 0.6959758 0.6831484 0.6597558 0.6964134 0.5999818 0.4143845 0.6165643 0.4863267 0.5912141 0.6893363 0.8166506
if (!is.null(r2) && "stress_level" %in% names(r2)) {
  cat("R² stress_level =", round(r2["stress_level"], 3), "\n")
  r2_val <- r2["stress_level"]
  cat("Interpretasi: ")
  if (r2_val < 0.25) {
    cat("Rendah (lemah)\n")
  } else if (r2_val < 0.50) {
    cat("Sedang\n")
  } else if (r2_val < 0.75) {
    cat("Tinggi\n")
  } else {
    cat("Sangat tinggi\n")
  }
  cat("→ Menunjukkan proporsi variansi stress_level yang dijelaskan oleh variabel eksogen.\n")
} else {
  cat("R² tidak ditemukan atau nama variabel tidak sesuai.\n")
}
## R² stress_level = 0.817 
## Interpretasi: Sangat tinggi
## → Menunjukkan proporsi variansi stress_level yang dijelaskan oleh variabel eksogen.
# VISUALISASI PATH DIAGRAM SEM
semPaths(
  fit_sem,
  what = "std",
  layout = "tree",
  edge.label.cex = 0.8,
  label.cex = 1.2,
  sizeMan = 6,
  sizeLat = 10,
  nCharNodes = 0,
  residuals = FALSE,
  style = "lisrel",
  color = list(
    lat = "#AED6F1",
    man = "#FDEBD0"
  )
)
title("Path Diagram – Full SEM", line = 3)