df <- read.csv("C:/Users/ASUS/Downloads/Data Final.csv", stringsAsFactors = FALSE)

cat(" INFO DATASET \n")
##  INFO DATASET
cat("Jumlah responden :", nrow(df), "\n")
## Jumlah responden : 355
cat("Jumlah kolom     :", ncol(df), "\n")
## Jumlah kolom     : 36
cat("Missing values   :", sum(is.na(df)), "\n\n")
## Missing values   : 0
item_cols <- c("MAD1","MAD2","MAD3",
               "MAU1","MAU2","MAU3",
               "MAE1","MAE2","MAE3",
               "BIF1","BIF2",
               "BIS1","BIS2","BIS3",
               "BIE1","BIE2","BIE3",
               "LPF1","LPF2","LPF3",
               "LPP1","LPP2","LPP3",
               "LPA1","LPA2","LPA3",
               "CLB1","CLB2","CLB3",
               "CLA1","CLA2","CLA3")

df_item <- df[, item_cols]
cat("STATISTIK DESKRIPTIF\n")
## STATISTIK DESKRIPTIF
desc <- describe(df_item)
print(round(desc[, c("n","mean","sd","median","skew","kurtosis")], 3))
##        n mean   sd median  skew kurtosis
## MAD1 355 4.39 0.60      4 -0.41    -0.69
## MAD2 355 4.37 0.60      4 -0.43    -0.23
## MAD3 355 4.38 0.60      4 -0.38    -0.70
## MAU1 355 4.44 0.62      5 -0.70    -0.13
## MAU2 355 4.41 0.65      4 -0.76     0.07
## MAU3 355 4.39 0.62      4 -0.48    -0.66
## MAE1 355 4.40 0.60      4 -0.52    -0.22
## MAE2 355 4.39 0.59      4 -0.37    -0.71
## MAE3 355 4.38 0.62      4 -0.52    -0.27
## BIF1 355 4.43 0.60      4 -0.59    -0.16
## BIF2 355 4.41 0.62      4 -0.71     0.20
## BIS1 355 4.39 0.62      4 -0.51    -0.65
## BIS2 355 4.43 0.62      4 -0.59    -0.60
## BIS3 355 4.37 0.63      4 -0.55    -0.32
## BIE1 355 4.36 0.63      4 -0.47    -0.68
## BIE2 355 4.35 0.63      4 -0.43    -0.69
## BIE3 355 4.40 0.62      4 -0.54    -0.64
## LPF1 355 4.39 0.62      4 -0.50    -0.66
## LPF2 355 4.49 0.62      5 -0.82    -0.35
## LPF3 355 4.47 0.63      5 -0.78    -0.42
## LPP1 355 4.40 0.60      4 -0.47    -0.67
## LPP2 355 4.48 0.61      5 -0.75    -0.43
## LPP3 355 4.46 0.61      5 -0.65    -0.54
## LPA1 355 4.45 0.62      5 -0.66    -0.54
## LPA2 355 4.41 0.62      4 -0.54    -0.63
## LPA3 355 4.41 0.62      4 -0.52    -0.64
## CLB1 355 4.35 0.62      4 -0.40    -0.68
## CLB2 355 4.36 0.61      4 -0.38    -0.68
## CLB3 355 4.32 0.63      4 -0.45    -0.35
## CLA1 355 4.39 0.60      4 -0.50    -0.23
## CLA2 355 4.38 0.61      4 -0.52    -0.24
## CLA3 355 4.34 0.63      4 -0.48    -0.32
cat("\n CRONBACH ALPHA PER KONSTRUK\n")
## 
##  CRONBACH ALPHA PER KONSTRUK
konstruk_items <- list(
  MAD = c("MAD1","MAD2","MAD3"),   # Mobile App Design
  MAU = c("MAU1","MAU2","MAU3"),   # Mobile App Usability
  MAE = c("MAE1","MAE2","MAE3"),   # Mobile App Engagement
  BIF = c("BIF1","BIF2"),          # Brand Image - Feature
  BIS = c("BIS1","BIS2","BIS3"),   # Brand Image - Social
  BIE = c("BIE1","BIE2","BIE3"),   # Brand Image - Emotional
  LPF = c("LPF1","LPF2","LPF3"),   # Loyalty Program - Financial
  LPP = c("LPP1","LPP2","LPP3"),   # Loyalty Program - Partnership
  LPA = c("LPA1","LPA2","LPA3"),   # Loyalty Program - Aspirational
  CLB = c("CLB1","CLB2","CLB3"),   # Customer Loyalty - Behavioral
  CLA = c("CLA1","CLA2","CLA3")    # Customer Loyalty - Attitudinal
)

for (nm in names(konstruk_items)) {
  a <- alpha(df_item[, konstruk_items[[nm]]])$total$raw_alpha
  status <- ifelse(a >= 0.7, "✓ Reliabel", "✗ Perlu perhatian")
  cat(sprintf("  %-4s : α = %.3f  %s\n", nm, a, status))
}
## Warning in response.frequencies(x, max = max): response.frequency has been
## deprecated and replaced with responseFrequecy.  Please fix your call
##   MAD  : α = 0.825  ✓ Reliabel
## Warning in response.frequencies(x, max = max): response.frequency has been
## deprecated and replaced with responseFrequecy.  Please fix your call
##   MAU  : α = 0.738  ✓ Reliabel
## Warning in response.frequencies(x, max = max): response.frequency has been
## deprecated and replaced with responseFrequecy.  Please fix your call
##   MAE  : α = 0.809  ✓ Reliabel
## Warning in response.frequencies(x, max = max): response.frequency has been
## deprecated and replaced with responseFrequecy.  Please fix your call
##   BIF  : α = 0.704  ✓ Reliabel
## Warning in response.frequencies(x, max = max): response.frequency has been
## deprecated and replaced with responseFrequecy.  Please fix your call
##   BIS  : α = 0.763  ✓ Reliabel
## Warning in response.frequencies(x, max = max): response.frequency has been
## deprecated and replaced with responseFrequecy.  Please fix your call
##   BIE  : α = 0.771  ✓ Reliabel
## Warning in response.frequencies(x, max = max): response.frequency has been
## deprecated and replaced with responseFrequecy.  Please fix your call
##   LPF  : α = 0.796  ✓ Reliabel
## Warning in response.frequencies(x, max = max): response.frequency has been
## deprecated and replaced with responseFrequecy.  Please fix your call
##   LPP  : α = 0.746  ✓ Reliabel
## Warning in response.frequencies(x, max = max): response.frequency has been
## deprecated and replaced with responseFrequecy.  Please fix your call
##   LPA  : α = 0.724  ✓ Reliabel
## Warning in response.frequencies(x, max = max): response.frequency has been
## deprecated and replaced with responseFrequecy.  Please fix your call
##   CLB  : α = 0.764  ✓ Reliabel
## Warning in response.frequencies(x, max = max): response.frequency has been
## deprecated and replaced with responseFrequecy.  Please fix your call
##   CLA  : α = 0.782  ✓ Reliabel
cat("\n MATRIKS KORELASI (item numerik) \n")
## 
##  MATRIKS KORELASI (item numerik)
cor_matrix <- cor(df_item, use = "complete.obs")

# Visualisasi korelasi
corrplot(cor_matrix,
         method  = "color",
         type    = "upper",
         tl.cex  = 0.7,
         tl.col  = "black",
         addCoef.col = "black",
         number.cex  = 0.45,
         title   = "Matriks Korelasi Antar Item",
         mar     = c(0,0,1,0))

model_sem <- '
  MobileApp =~ MAD1 + MAD2 + MAD3 +
               MAU1 + MAU2 + MAU3 +
               MAE1 + MAE2 + MAE3
  BrandImage =~ BIF1 + BIF2 +
                BIS1 + BIS2 + BIS3 +
                BIE1 + BIE2 + BIE3
  LoyaltyPrg =~ LPF1 + LPF2 + LPF3 +
                LPP1 + LPP2 + LPP3 +
                LPA1 + LPA2 + LPA3
  CustLoyalty =~ CLB1 + CLB2 + CLB3 +
                 CLA1 + CLA2 + CLA3

  # H1: Mobile App berpengaruh terhadap Brand Image
  BrandImage  ~ MobileApp

  # H2: Loyalty Program berpengaruh terhadap Brand Image
  BrandImage  ~ LoyaltyPrg

  # H3: Mobile App berpengaruh langsung terhadap Customer Loyalty
  CustLoyalty ~ MobileApp

  # H4: Loyalty Program berpengaruh terhadap Customer Loyalty
  CustLoyalty ~ LoyaltyPrg

  # H5: Brand Image berpengaruh terhadap Customer Loyalty (mediasi)
  CustLoyalty ~ BrandImage
'
cat("\n ESTIMASI MODEL SEM \n")
## 
##  ESTIMASI MODEL SEM
fit <- sem(model_sem,
           data      = df_item,
           estimator = "MLR",   
           se        = "robust")

cat("Status estimasi:", lavInspect(fit, "converged"), "\n\n")
## Status estimasi: TRUE
cat(" GOODNESS OF FIT INDICES \n")
##  GOODNESS OF FIT INDICES
fit_indices <- fitMeasures(fit, c(
  "chisq", "df", "pvalue",
  "cfi", "tli", "rmsea", "rmsea.ci.lower", "rmsea.ci.upper",
  "srmr", "aic", "bic"
))

cat(sprintf("\n  Chi-square (χ²) : %.3f (df = %d, p = %.4f)\n",
            fit_indices["chisq"], fit_indices["df"], fit_indices["pvalue"]))
## 
##   Chi-square (χ²) : 1768.406 (df = 458, p = 0.0000)
cat(sprintf("  CFI             : %.3f   (≥ 0.90 = acceptable, ≥ 0.95 = good)\n",
            fit_indices["cfi"]))
##   CFI             : 0.811   (≥ 0.90 = acceptable, ≥ 0.95 = good)
cat(sprintf("  TLI             : %.3f   (≥ 0.90 = acceptable)\n",
            fit_indices["tli"]))
##   TLI             : 0.795   (≥ 0.90 = acceptable)
cat(sprintf("  RMSEA           : %.3f   (≤ 0.08 = acceptable, ≤ 0.06 = good)\n",
            fit_indices["rmsea"]))
##   RMSEA           : 0.090   (≤ 0.08 = acceptable, ≤ 0.06 = good)
cat(sprintf("  RMSEA 90%% CI    : [%.3f, %.3f]\n",
            fit_indices["rmsea.ci.lower"], fit_indices["rmsea.ci.upper"]))
##   RMSEA 90% CI    : [0.085, 0.094]
cat(sprintf("  SRMR            : %.3f   (≤ 0.08 = acceptable)\n",
            fit_indices["srmr"]))
##   SRMR            : 0.058   (≤ 0.08 = acceptable)
cat(sprintf("  AIC             : %.1f\n", fit_indices["aic"]))
##   AIC             : 15689.9
cat(sprintf("  BIC             : %.1f\n", fit_indices["bic"]))
##   BIC             : 15961.0
cat("\n Interpretasi \n")
## 
##  Interpretasi
cfi_ok   <- fit_indices["cfi"]   >= 0.90
tli_ok   <- fit_indices["tli"]   >= 0.90
rmsea_ok <- fit_indices["rmsea"] <= 0.08
srmr_ok  <- fit_indices["srmr"]  <= 0.08

cat(sprintf("  CFI   : %s\n", ifelse(cfi_ok,   "✓ Acceptable", "✗ Kurang baik")))
##   CFI   : ✗ Kurang baik
cat(sprintf("  TLI   : %s\n", ifelse(tli_ok,   "✓ Acceptable", "✗ Kurang baik")))
##   TLI   : ✗ Kurang baik
cat(sprintf("  RMSEA : %s\n", ifelse(rmsea_ok, "✓ Acceptable", "✗ Kurang baik")))
##   RMSEA : ✗ Kurang baik
cat(sprintf("  SRMR  : %s\n", ifelse(srmr_ok,  "✓ Acceptable", "✗ Kurang baik")))
##   SRMR  : ✓ Acceptable
cat("\n RINGKASAN MODEL LENGKAP \n")
## 
##  RINGKASAN MODEL LENGKAP
summary(fit,
        fit.measures  = TRUE,
        standardized  = TRUE,
        rsquare       = TRUE)
## lavaan 0.6-21 ended normally after 85 iterations
## 
##   Estimator                                         ML
##   Optimization method                           NLMINB
##   Number of model parameters                        70
## 
##   Number of observations                           355
## 
## Model Test User Model:
##                                               Standard      Scaled
##   Test Statistic                              1768.406    1665.819
##   Degrees of freedom                               458         458
##   P-value (Chi-square)                           0.000       0.000
##   Scaling correction factor                                  1.062
##     Yuan-Bentler correction (Mplus variant)                       
## 
## Model Test Baseline Model:
## 
##   Test statistic                              7431.474    7095.772
##   Degrees of freedom                               496         496
##   P-value                                        0.000       0.000
##   Scaling correction factor                                  1.047
## 
## User Model versus Baseline Model:
## 
##   Comparative Fit Index (CFI)                    0.811       0.817
##   Tucker-Lewis Index (TLI)                       0.795       0.802
##                                                                   
##   Robust Comparative Fit Index (CFI)                         0.814
##   Robust Tucker-Lewis Index (TLI)                            0.799
## 
## Loglikelihood and Information Criteria:
## 
##   Loglikelihood user model (H0)              -7774.954   -7774.954
##   Scaling correction factor                                  0.832
##       for the MLR correction                                      
##   Loglikelihood unrestricted model (H1)      -6890.751   -6890.751
##   Scaling correction factor                                  1.031
##       for the MLR correction                                      
##                                                                   
##   Akaike (AIC)                               15689.909   15689.909
##   Bayesian (BIC)                             15960.957   15960.957
##   Sample-size adjusted Bayesian (SABIC)      15738.886   15738.886
## 
## Root Mean Square Error of Approximation:
## 
##   RMSEA                                          0.090       0.086
##   90 Percent confidence interval - lower         0.085       0.082
##   90 Percent confidence interval - upper         0.094       0.091
##   P-value H_0: RMSEA <= 0.050                    0.000       0.000
##   P-value H_0: RMSEA >= 0.080                    1.000       0.991
##                                                                   
##   Robust RMSEA                                               0.089
##   90 Percent confidence interval - lower                     0.084
##   90 Percent confidence interval - upper                     0.093
##   P-value H_0: Robust RMSEA <= 0.050                         0.000
##   P-value H_0: Robust RMSEA >= 0.080                         0.999
## 
## Standardized Root Mean Square Residual:
## 
##   SRMR                                           0.058       0.058
## 
## Parameter Estimates:
## 
##   Standard errors                           Robust.sem
##   Information                                 Expected
##   Information saturated (h1) model          Structured
## 
## Latent Variables:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##   MobileApp =~                                                          
##     MAD1              1.000                               0.374    0.622
##     MAD2              1.092    0.074   14.666    0.000    0.408    0.684
##     MAD3              1.039    0.099   10.467    0.000    0.388    0.652
##     MAU1              1.051    0.101   10.413    0.000    0.392    0.635
##     MAU2              1.123    0.107   10.456    0.000    0.419    0.646
##     MAU3              1.177    0.106   11.076    0.000    0.440    0.710
##     MAE1              1.129    0.100   11.289    0.000    0.422    0.700
##     MAE2              1.102    0.108   10.187    0.000    0.412    0.696
##     MAE3              1.134    0.101   11.242    0.000    0.424    0.686
##   BrandImage =~                                                         
##     BIF1              1.000                               0.381    0.638
##     BIF2              1.079    0.072   14.922    0.000    0.412    0.660
##     BIS1              1.179    0.102   11.563    0.000    0.450    0.724
##     BIS2              1.044    0.085   12.238    0.000    0.398    0.646
##     BIS3              1.198    0.088   13.552    0.000    0.457    0.721
##     BIE1              1.248    0.120   10.391    0.000    0.476    0.753
##     BIE2              1.128    0.105   10.707    0.000    0.430    0.688
##     BIE3              1.170    0.096   12.181    0.000    0.446    0.717
##   LoyaltyPrg =~                                                         
##     LPF1              1.000                               0.424    0.680
##     LPF2              1.100    0.075   14.661    0.000    0.467    0.752
##     LPF3              1.257    0.086   14.572    0.000    0.533    0.848
##     LPP1              1.004    0.074   13.515    0.000    0.426    0.705
##     LPP2              1.142    0.082   13.853    0.000    0.484    0.792
##     LPP3              0.981    0.089   11.085    0.000    0.416    0.682
##     LPA1              1.064    0.082   12.928    0.000    0.451    0.729
##     LPA2              0.964    0.070   13.817    0.000    0.409    0.665
##     LPA3              0.909    0.079   11.452    0.000    0.385    0.628
##   CustLoyalty =~                                                        
##     CLB1              1.000                               0.466    0.756
##     CLB2              0.912    0.066   13.897    0.000    0.425    0.702
##     CLB3              0.987    0.070   14.152    0.000    0.460    0.728
##     CLA1              0.919    0.067   13.774    0.000    0.428    0.712
##     CLA2              0.958    0.061   15.741    0.000    0.446    0.733
##     CLA3              1.067    0.069   15.409    0.000    0.497    0.792
## 
## Regressions:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##   BrandImage ~                                                          
##     MobileApp         0.303    0.066    4.574    0.000    0.297    0.297
##     LoyaltyPrg        0.625    0.070    8.880    0.000    0.695    0.695
##   CustLoyalty ~                                                         
##     MobileApp         0.539    0.130    4.140    0.000    0.432    0.432
##     LoyaltyPrg        0.534    0.197    2.715    0.007    0.485    0.485
##     BrandImage       -0.142    0.258   -0.550    0.582   -0.116   -0.116
## 
## Covariances:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##   MobileApp ~~                                                          
##     LoyaltyPrg        0.117    0.019    6.280    0.000    0.739    0.739
## 
## Variances:
##                    Estimate  Std.Err  z-value  P(>|z|)   Std.lv  Std.all
##    .MAD1              0.221    0.011   20.447    0.000    0.221    0.613
##    .MAD2              0.190    0.010   18.514    0.000    0.190    0.533
##    .MAD3              0.204    0.011   19.404    0.000    0.204    0.575
##    .MAU1              0.227    0.015   14.727    0.000    0.227    0.596
##    .MAU2              0.246    0.015   16.015    0.000    0.246    0.583
##    .MAU3              0.190    0.011   16.805    0.000    0.190    0.496
##    .MAE1              0.185    0.011   16.630    0.000    0.185    0.510
##    .MAE2              0.180    0.011   16.944    0.000    0.180    0.516
##    .MAE3              0.201    0.013   16.025    0.000    0.201    0.529
##    .BIF1              0.212    0.011   19.823    0.000    0.212    0.593
##    .BIF2              0.220    0.012   18.219    0.000    0.220    0.565
##    .BIS1              0.183    0.013   13.641    0.000    0.183    0.475
##    .BIS2              0.222    0.011   19.497    0.000    0.222    0.583
##    .BIS3              0.192    0.012   16.698    0.000    0.192    0.480
##    .BIE1              0.173    0.016   11.121    0.000    0.173    0.433
##    .BIE2              0.206    0.012   17.320    0.000    0.206    0.527
##    .BIE3              0.188    0.011   16.412    0.000    0.188    0.486
##    .LPF1              0.209    0.012   16.884    0.000    0.209    0.538
##    .LPF2              0.167    0.013   12.872    0.000    0.167    0.435
##    .LPF3              0.111    0.011   10.259    0.000    0.111    0.282
##    .LPP1              0.183    0.012   15.535    0.000    0.183    0.503
##    .LPP2              0.139    0.011   12.496    0.000    0.139    0.373
##    .LPP3              0.199    0.015   13.024    0.000    0.199    0.535
##    .LPA1              0.179    0.014   12.425    0.000    0.179    0.468
##    .LPA2              0.211    0.012   17.100    0.000    0.211    0.557
##    .LPA3              0.228    0.014   15.777    0.000    0.228    0.606
##    .CLB1              0.163    0.013   12.257    0.000    0.163    0.429
##    .CLB2              0.186    0.013   14.404    0.000    0.186    0.507
##    .CLB3              0.187    0.017   11.229    0.000    0.187    0.470
##    .CLA1              0.178    0.013   14.167    0.000    0.178    0.492
##    .CLA2              0.172    0.013   13.296    0.000    0.172    0.463
##    .CLA3              0.147    0.014   10.310    0.000    0.147    0.373
##     MobileApp         0.140    0.024    5.843    0.000    1.000    1.000
##    .BrandImage        0.018    0.004    4.772    0.000    0.125    0.125
##     LoyaltyPrg        0.180    0.027    6.679    0.000    1.000    1.000
##    .CustLoyalty       0.095    0.014    6.934    0.000    0.439    0.439
## 
## R-Square:
##                    Estimate
##     MAD1              0.387
##     MAD2              0.467
##     MAD3              0.425
##     MAU1              0.404
##     MAU2              0.417
##     MAU3              0.504
##     MAE1              0.490
##     MAE2              0.484
##     MAE3              0.471
##     BIF1              0.407
##     BIF2              0.435
##     BIS1              0.525
##     BIS2              0.417
##     BIS3              0.520
##     BIE1              0.567
##     BIE2              0.473
##     BIE3              0.514
##     LPF1              0.462
##     LPF2              0.565
##     LPF3              0.718
##     LPP1              0.497
##     LPP2              0.627
##     LPP3              0.465
##     LPA1              0.532
##     LPA2              0.443
##     LPA3              0.394
##     CLB1              0.571
##     CLB2              0.493
##     CLB3              0.530
##     CLA1              0.508
##     CLA2              0.537
##     CLA3              0.627
##     BrandImage        0.875
##     CustLoyalty       0.561
cat("\n VALIDITAS KONVERGEN (AVE & CR) \n")
## 
##  VALIDITAS KONVERGEN (AVE & CR)
# Ambil standardized loadings
params <- parameterEstimates(fit, standardized = TRUE)
loadings <- params[params$op == "=~", c("lhs","rhs","std.all")]

konstruk_laten <- c("MobileApp","BrandImage","LoyaltyPrg","CustLoyalty")

for (k in konstruk_laten) {
  lam <- loadings[loadings$lhs == k, "std.all"]
  n_item <- length(lam)

  # AVE (Average Variance Extracted)
  ave <- mean(lam^2)

  # CR (Composite Reliability)
  cr <- (sum(lam))^2 / ((sum(lam))^2 + sum(1 - lam^2))

  ave_ok <- ifelse(ave >= 0.50, "✓", "✗")
  cr_ok  <- ifelse(cr  >= 0.70, "✓", "✗")

  cat(sprintf("  %-12s | AVE = %.3f %s (≥0.50) | CR = %.3f %s (≥0.70) | n_item = %d\n",
              k, ave, ave_ok, cr, cr_ok, n_item))
}
##   MobileApp    | AVE = 0.450 ✗ (≥0.50) | CR = 0.880 ✓ (≥0.70) | n_item = 9
##   BrandImage   | AVE = 0.482 ✗ (≥0.50) | CR = 0.881 ✓ (≥0.70) | n_item = 8
##   LoyaltyPrg   | AVE = 0.523 ✓ (≥0.50) | CR = 0.907 ✓ (≥0.70) | n_item = 9
##   CustLoyalty  | AVE = 0.544 ✓ (≥0.50) | CR = 0.877 ✓ (≥0.70) | n_item = 6
cat("\n UJI HIPOTESIS (PATH COEFFICIENTS) \n")
## 
##  UJI HIPOTESIS (PATH COEFFICIENTS)
cat(sprintf("%-35s %8s %8s %8s %8s %s\n",
            "Jalur", "β std", "SE", "z", "p-value", "Ket"))
## Jalur                                 β std       SE        z  p-value Ket
cat(strrep("-", 80), "\n")
## --------------------------------------------------------------------------------
paths <- params[params$op == "~",]
for (i in 1:nrow(paths)) {
  p   <- paths[i,]
  sig <- ifelse(p$pvalue < 0.001, "***",
         ifelse(p$pvalue < 0.01,  "**",
         ifelse(p$pvalue < 0.05,  "*", "ns")))
  ket <- ifelse(p$pvalue < 0.05, "✓ Signifikan", "✗ Tidak Signifikan")
  cat(sprintf("%-15s → %-15s %8.3f %8.3f %8.3f %8.4f %s %s\n",
              p$rhs, p$lhs,
              p$std.all, p$se, p$z, p$pvalue,
              sig, ket))
}
## MobileApp       → BrandImage         0.297    0.066    4.574   0.0000 *** ✓ Signifikan
## LoyaltyPrg      → BrandImage         0.695    0.070    8.880   0.0000 *** ✓ Signifikan
## MobileApp       → CustLoyalty        0.432    0.130    4.140   0.0000 *** ✓ Signifikan
## LoyaltyPrg      → CustLoyalty        0.485    0.197    2.715   0.0066 ** ✓ Signifikan
## BrandImage      → CustLoyalty       -0.116    0.258   -0.550   0.5822 ns ✗ Tidak Signifikan
cat("\n UJI HIPOTESIS (PATH COEFFICIENTS) \n")
## 
##  UJI HIPOTESIS (PATH COEFFICIENTS)
cat(sprintf("%-35s %8s %8s %8s %8s %s\n",
            "Jalur", "β std", "SE", "z", "p-value", "Ket"))
## Jalur                                 β std       SE        z  p-value Ket
cat(strrep("-", 80), "\n")
## --------------------------------------------------------------------------------
paths <- params[params$op == "~",]
for (i in 1:nrow(paths)) {
  p   <- paths[i,]
  sig <- ifelse(p$pvalue < 0.001, "***",
         ifelse(p$pvalue < 0.01,  "**",
         ifelse(p$pvalue < 0.05,  "*", "ns")))
  ket <- ifelse(p$pvalue < 0.05, "✓ Signifikan", "✗ Tidak Signifikan")
  cat(sprintf("%-15s → %-15s %8.3f %8.3f %8.3f %8.4f %s %s\n",
              p$rhs, p$lhs,
              p$std.all, p$se, p$z, p$pvalue,
              sig, ket))
}
## MobileApp       → BrandImage         0.297    0.066    4.574   0.0000 *** ✓ Signifikan
## LoyaltyPrg      → BrandImage         0.695    0.070    8.880   0.0000 *** ✓ Signifikan
## MobileApp       → CustLoyalty        0.432    0.130    4.140   0.0000 *** ✓ Signifikan
## LoyaltyPrg      → CustLoyalty        0.485    0.197    2.715   0.0066 ** ✓ Signifikan
## BrandImage      → CustLoyalty       -0.116    0.258   -0.550   0.5822 ns ✗ Tidak Signifikan
cat("\n R-SQUARED (Variance Explained) \n")
## 
##  R-SQUARED (Variance Explained)
r2 <- lavInspect(fit, "r2")
for (nm in names(r2)) {
  cat(sprintf("  %-15s : R² = %.3f (%.1f%% varians dijelaskan)\n",
              nm, r2[nm], r2[nm]*100))
}
##   MAD1            : R² = 0.387 (38.7% varians dijelaskan)
##   MAD2            : R² = 0.467 (46.7% varians dijelaskan)
##   MAD3            : R² = 0.425 (42.5% varians dijelaskan)
##   MAU1            : R² = 0.404 (40.4% varians dijelaskan)
##   MAU2            : R² = 0.417 (41.7% varians dijelaskan)
##   MAU3            : R² = 0.504 (50.4% varians dijelaskan)
##   MAE1            : R² = 0.490 (49.0% varians dijelaskan)
##   MAE2            : R² = 0.484 (48.4% varians dijelaskan)
##   MAE3            : R² = 0.471 (47.1% varians dijelaskan)
##   BIF1            : R² = 0.407 (40.7% varians dijelaskan)
##   BIF2            : R² = 0.435 (43.5% varians dijelaskan)
##   BIS1            : R² = 0.525 (52.5% varians dijelaskan)
##   BIS2            : R² = 0.417 (41.7% varians dijelaskan)
##   BIS3            : R² = 0.520 (52.0% varians dijelaskan)
##   BIE1            : R² = 0.567 (56.7% varians dijelaskan)
##   BIE2            : R² = 0.473 (47.3% varians dijelaskan)
##   BIE3            : R² = 0.514 (51.4% varians dijelaskan)
##   LPF1            : R² = 0.462 (46.2% varians dijelaskan)
##   LPF2            : R² = 0.565 (56.5% varians dijelaskan)
##   LPF3            : R² = 0.718 (71.8% varians dijelaskan)
##   LPP1            : R² = 0.497 (49.7% varians dijelaskan)
##   LPP2            : R² = 0.627 (62.7% varians dijelaskan)
##   LPP3            : R² = 0.465 (46.5% varians dijelaskan)
##   LPA1            : R² = 0.532 (53.2% varians dijelaskan)
##   LPA2            : R² = 0.443 (44.3% varians dijelaskan)
##   LPA3            : R² = 0.394 (39.4% varians dijelaskan)
##   CLB1            : R² = 0.571 (57.1% varians dijelaskan)
##   CLB2            : R² = 0.493 (49.3% varians dijelaskan)
##   CLB3            : R² = 0.530 (53.0% varians dijelaskan)
##   CLA1            : R² = 0.508 (50.8% varians dijelaskan)
##   CLA2            : R² = 0.537 (53.7% varians dijelaskan)
##   CLA3            : R² = 0.627 (62.7% varians dijelaskan)
##   BrandImage      : R² = 0.875 (87.5% varians dijelaskan)
##   CustLoyalty     : R² = 0.561 (56.1% varians dijelaskan)
cat("\n TOP 10 MODIFICATION INDICES \n")
## 
##  TOP 10 MODIFICATION INDICES
mi <- modindices(fit, sort. = TRUE, maximum.number = 10)
print(mi[, c("lhs","op","rhs","mi","epc")])
##            lhs op  rhs      mi    epc
## 171       MAD1 ~~ MAD2 135.373  0.140
## 316       MAU3 ~~ MAE1 119.590  0.125
## 138 LoyaltyPrg =~ BIE3  93.044  2.095
## 514       BIE1 ~~ BIE2  84.484  0.103
## 646       LPA3 ~~ CLB1  60.208  0.088
## 639       LPA2 ~~ LPA3  41.066  0.079
## 232       MAD3 ~~ MAU1  38.994  0.078
## 496       BIS3 ~~ BIE1  38.987  0.069
## 477       BIS2 ~~ BIS3  38.968 -0.075
## 622       LPP3 ~~ LPA1  36.660  0.066
cat("\n MEMBUAT PATH DIAGRAM \n")
## 
##  MEMBUAT PATH DIAGRAM
# Path diagram standar
semPaths(fit,
         what         = "std",        # tampilkan koefisien terstandarisasi
         whatLabels   = "std",
         style        = "ram",
         layout       = "tree2",
         rotation     = 2,
         edge.label.cex = 0.7,
         node.label.cex = 0.8,
         color        = list(lat = "#4A90D9", man = "#7ED321"),
         title        = TRUE,
         thresholds   = FALSE,
         residuals    = FALSE,
         nCharNodes   = 0,
         mar          = c(3,3,3,3))
## Warning in qgraph::qgraph(Edgelist, labels = nLab, bidirectional = Bidir, : The
## following arguments are not documented and likely not arguments of qgraph and
## thus ignored: node.label.cex
title("Path Diagram SEM: Mobile App & Loyalty Program → Customer Loyalty",
      cex.main = 0.9)

cat("\n UJI MEDIASI (INDIRECT EFFECTS via BrandImage) \n")
## 
##  UJI MEDIASI (INDIRECT EFFECTS via BrandImage)
model_mediasi <- '
  MobileApp   =~ MAD1 + MAD2 + MAD3 + MAU1 + MAU2 + MAU3 + MAE1 + MAE2 + MAE3
  BrandImage  =~ BIF1 + BIF2 + BIS1 + BIS2 + BIS3 + BIE1 + BIE2 + BIE3
  LoyaltyPrg  =~ LPF1 + LPF2 + LPF3 + LPP1 + LPP2 + LPP3 + LPA1 + LPA2 + LPA3
  CustLoyalty =~ CLB1 + CLB2 + CLB3 + CLA1 + CLA2 + CLA3
 
  BrandImage  ~ a1 * MobileApp + a2 * LoyaltyPrg
  CustLoyalty ~ b  * BrandImage
  CustLoyalty ~ c1 * MobileApp + c2 * LoyaltyPrg
 
  ind_MA := a1 * b   # Indirect: MobileApp → BrandImage → CustLoyalty
  ind_LP := a2 * b   # Indirect: LoyaltyPrg → BrandImage → CustLoyalty
 
  tot_MA := c1 + (a1 * b)
  tot_LP := c2 + (a2 * b)
'
 
fit_med <- sem(model_mediasi,
               data      = df_item,
               estimator = "ML",    
               se        = "bootstrap",
               bootstrap = 1000)    
 
cat("\nHasil Indirect Effects (Bootstrap 1000x):\n")
## 
## Hasil Indirect Effects (Bootstrap 1000x):
indirect <- parameterEstimates(fit_med, boot.ci.type = "perc", level = 0.95)
med_rows <- indirect[indirect$label %in% c("ind_MA","ind_LP","tot_MA","tot_LP"), ]
print(med_rows[, c("label","est","se","z","pvalue","ci.lower","ci.upper")])
##     label    est    se      z pvalue ci.lower ci.upper
## 75 ind_MA -0.043 0.090 -0.478  0.633   -0.229    0.132
## 76 ind_LP -0.089 0.186 -0.475  0.635   -0.472    0.252
## 77 tot_MA  0.496 0.112  4.413  0.000    0.280    0.717
## 78 tot_LP  0.445 0.094  4.734  0.000    0.276    0.642
cat("\n  ind_MA = Indirect effect MobileApp → BrandImage → CustLoyalty\n")
## 
##   ind_MA = Indirect effect MobileApp → BrandImage → CustLoyalty
cat("  ind_LP = Indirect effect LoyaltyPrg → BrandImage → CustLoyalty\n")
##   ind_LP = Indirect effect LoyaltyPrg → BrandImage → CustLoyalty
cat("  tot_MA = Total effect MobileApp → CustLoyalty\n")
##   tot_MA = Total effect MobileApp → CustLoyalty
cat("  tot_LP = Total effect LoyaltyPrg → CustLoyalty\n")
##   tot_LP = Total effect LoyaltyPrg → CustLoyalty
cat("\n  Mediasi terjadi jika: CI tidak melewati 0 (p < 0.05)\n")
## 
##   Mediasi terjadi jika: CI tidak melewati 0 (p < 0.05)