Pada tahap awal ini, kita akan mempersiapkan lingkungan kerja R
dengan memuat pustaka (libraries) yang esensial untuk analisis
Structural Equation Modeling (SEM). Pustaka utama yang
digunakan adalah lavaan untuk komputasi model,
semPlot untuk visualisasi diagram jalur (path
diagram), psych untuk uji asumsi statistik, dan
dplyr untuk manipulasi data.
Selanjutnya, kita akan memuat dataset
retail_wlb_dataset.csv ke dalam memori (disimpan dalam
variabel df) dan menampilkan dimensi data untuk memastikan
proses import berjalan dengan benar. Ekspektasi dari dataset
ini adalah 150 baris observasi dan 20 kolom.
# Mengaktifkan pustaka yang dibutuhkan
# Hapus tanda pagar pada baris install.packages jika pustaka belum terinstal di environment Anda
# install.packages(c("lavaan", "semPlot", "psych", "dplyr"))
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(semPlot)
## Warning: package 'semPlot' was built under R version 4.5.3
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(dplyr)
##
## 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
# Memuat dataset
df <- read.csv("retail_wlb_dataset.csv")
# Memeriksa dimensi dataset (baris, kolom) dan struktur awal
dim(df)
## [1] 150 20
glimpse(df) # Fungsi dari dplyr untuk melihat ringkasan tipe data per kolom
## Rows: 150
## Columns: 20
## $ Age <int> 56, 46, 32, 25, 38, 56, 36, 40, 28, 28, 41, 53,…
## $ Gender <chr> "Female", "Female", "Female", "Female", "Female…
## $ Experience_Years <dbl> 18.0, 18.1, 12.8, 7.1, 7.3, 14.7, 18.0, 17.8, 1…
## $ Job_Role <chr> "Supervisor", "Customer Service", "Cashier", "S…
## $ Working_Hours_Per_Week <int> 32, 41, 54, 49, 50, 33, 50, 52, 45, 54, 36, 42,…
## $ WLB1 <dbl> 4, 3, 2, 5, 3, 4, 2, 3, 3, 4, 3, 3, 2, 3, 3, 4,…
## $ WLB2 <dbl> 4, 3, 3, 4, 3, 4, 3, 3, 3, 3, 3, 4, 3, 3, 4, 3,…
## $ WLB3 <dbl> 4, 3, 2, 4, 4, 4, 2, 2, 3, 3, 3, 4, 2, 4, 4, 3,…
## $ WLB4 <dbl> 4, 3, 2, 4, 3, 4, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4,…
## $ WLB5 <dbl> 4, 3, 2, 4, 4, 4, 2, 3, 3, 4, 3, 3, 3, 3, 4, 4,…
## $ JS1 <dbl> 1, 1, 2, 3, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2,…
## $ JS2 <dbl> 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 3, 2,…
## $ JS3 <dbl> 1, 1, 2, 3, 2, 2, 2, 2, 3, 2, 2, 2, 1, 1, 2, 2,…
## $ JS4 <dbl> 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2,…
## $ JS5 <dbl> 1, 1, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2,…
## $ EP1 <dbl> 2, 2, 2, 2, 3, 2, 2, 3, 2, 1, 2, 3, 1, 3, 1, 3,…
## $ EP2 <dbl> 2, 2, 2, 2, 3, 3, 2, 3, 2, 2, 1, 2, 2, 3, 1, 3,…
## $ EP3 <dbl> 2, 1, 2, 2, 3, 3, 1, 3, 2, 2, 1, 3, 1, 3, 2, 3,…
## $ EP4 <dbl> 2, 1, 2, 2, 3, 3, 1, 3, 2, 1, 1, 2, 1, 3, 2, 3,…
## $ EP5 <dbl> 2, 1, 2, 1, 3, 2, 2, 3, 2, 2, 1, 3, 1, 3, 2, 3,…
Analisis SEM menggunakan metode estimasi yang berfokus pada matriks
kovarians antar indikator. Oleh karena itu, kita perlu memisahkan data
metrik/indikator dari data demografi. Dataset asli memiliki kolom
demografi seperti Age, Gender,
Experience_Years, Job_Role, dan
Working_Hours_Per_Week yang tidak termasuk dalam persamaan
struktural kita.
Pada sel ini, kita akan: 1. Melakukan subsetting untuk hanya
mengambil 15 kolom indikator skala Likert (WLB1-WLB5, JS1-JS5, dan
EP1-EP5). 2. Memeriksa keberadaan nilai kosong (missing
values). Jika terdapat missing values, kita akan
menghapusnya (listwise deletion) agar tidak menyebabkan
kegagalan iterasi pada algoritma estimasi lavaan. 3.
Menampilkan sampel baris data bersih yang siap untuk dianalisis.
# 1. Subsetting data indikator
# Mengambil kolom berawalan WLB, JS, dan EP menggunakan fungsi select dari dplyr
df_sem <- df %>%
select(WLB1:WLB5, JS1:JS5, EP1:EP5)
# 2. Pemeriksaan missing values
cat("Jumlah missing values pada dataset indikator:", sum(is.na(df_sem)), "\n")
## Jumlah missing values pada dataset indikator: 0
# Menghapus baris yang memiliki missing values (jika ada)
df_clean <- na.omit(df_sem)
# Memastikan kembali dimensi setelah pembersihan
cat("Dimensi data setelah pembersihan:", dim(df_clean)[1], "baris,", dim(df_clean)[2], "kolom\n\n")
## Dimensi data setelah pembersihan: 150 baris, 15 kolom
# 3. Menampilkan 6 baris pertama dari data yang sudah bersih
head(df_clean)
Pendekatan Covariance-Based SEM (CB-SEM) yang menggunakan estimator Maximum Likelihood (ML) mensyaratkan agar data berdistribusi normal secara multivariat. Pada sel ini, kita akan melakukan uji asumsi tersebut.
Kita akan menggunakan uji Mardia’s Skewness and
Kurtosis dari pustaka psych untuk memeriksa
tingkat kemencengan (skewness) dan keruncingan
(kurtosis) dari gabungan 15 variabel kita. Jika nilai
p-value kurang dari 0.05, ini mengindikasikan pelanggaran
asumsi normalitas, yang nantinya harus kita pertimbangkan saat melakukan
fitting model.
# Menjalankan uji Mardia untuk mengevaluasi skewness dan kurtosis multivariat
hasil_mardia <- mardia(df_clean, plot = FALSE)
hasil_mardia
## Call: mardia(x = df_clean, plot = FALSE)
##
## Mardia tests of multivariate skew and kurtosis
## Use describe(x) the to get univariate tests
## n.obs = 150 num.vars = 15
## b1p = 26.6 skew = 664.91 with probability <= 0.65
## small sample skew = 679.9 with probability <= 0.49
## b2p = 252.41 kurtosis = -0.7 with probability <= 0.48
Artinya, 15 indikator kuesioner kita lolos uji asumsi normalitas multivariat.
Tahap ini adalah inti dari pemodelan menggunakan pustaka
lavaan. Kita akan merakit arsitektur model berdasarkan
kerangka konseptual yang telah disepakati. Seluruh struktur ini
dituliskan ke dalam satu objek teks (string) yang nantinya akan dibaca
oleh algoritma estimasi.
Penting untuk memahami tiga operator utama dalam sintaks
lavaan: 1. =~ (Diukur oleh):
Digunakan untuk membangun Outer Model. Operator ini mengikat
indikator-indikator kuesioner ke dalam satu variabel laten/konstruk. 2.
~ (Diregresi pada / Dipengaruhi oleh):
Digunakan untuk membangun Inner Model. Operator ini
mendefinisikan jalur kausalitas antar variabel laten. 3.
:= (Didefinisikan sebagai): Digunakan
untuk kalkulasi parameter kustom. Kita menggunakan ini untuk menghitung
kekuatan efek mediasi secara matematis.
Untuk mempermudah pelacakan jalur dalam uji mediasi, kita akan
memberikan label koefisien: * Label a: Pengaruh Work-Life
Balance (WLB) terhadap Job Satisfaction (JS). * Label b:
Pengaruh Job Satisfaction (JS) terhadap Employee Performance (EP). *
Label c: Pengaruh langsung Work-Life Balance (WLB) terhadap
Employee Performance (EP).
# Mendefinisikan blueprint model ke dalam variabel string
model_retail <- '
# ----------------------------------------------------
# 1. OUTER MODEL (Measurement Model)
# ----------------------------------------------------
WLB =~ WLB1 + WLB2 + WLB3 + WLB4 + WLB5
JS =~ JS1 + JS2 + JS3 + JS4 + JS5
EP =~ EP1 + EP2 + EP3 + EP4 + EP5
# ----------------------------------------------------
# 2. INNER MODEL (Structural Model)
# ----------------------------------------------------
# H1: WLB mempengaruhi Job Satisfaction
JS ~ a * WLB
# H2 & H3: EP dipengaruhi oleh Job Satisfaction dan secara langsung oleh WLB
EP ~ b * JS + c * WLB
# ----------------------------------------------------
# 3. KALKULASI EFEK MEDIASI
# ----------------------------------------------------
# Indirect Effect (Efek Mediasi) adalah perkalian jalur a dan b
indirect_effect := a * b
# Total Effect adalah gabungan pengaruh langsung (c) dan tidak langsung (a*b)
total_effect := c + (a * b)
'
cat("Arsitektur model 'model_retail' berhasil didefinisikan.\n")
## Arsitektur model 'model_retail' berhasil didefinisikan.
Setelah blueprint model selesai dirancang, kita akan
melakukan fitting model menggunakan data riil
(df_clean). Berdasarkan hasil uji asumsi di Tahap 3 (uji
Mardia) yang menyatakan bahwa data kita berdistribusi normal secara
multivariat, kita sangat direkomendasikan untuk menggunakan metode
estimasi standar, yaitu Maximum Likelihood
(estimator = "ML").
Fungsi summary() akan dipanggil untuk menampilkan
ringkasan hasil secara komprehensif, dengan menambahkan argumen: *
fit.measures = TRUE: Untuk menampilkan metrik evaluasi
kelayakan model (seperti RMSEA, CFI, TLI). *
standardized = TRUE: Untuk menampilkan koefisien
terstandardisasi agar skala nilainya seragam dan mudah dibandingkan. *
rsquare = TRUE: Untuk melihat nilai R-squared (\(R^2\)) dari variabel dependen.
# Mengeksekusi model SEM
fit_retail <- sem(model_retail, data = df_clean, estimator = "ML")
# Menampilkan ringkasan hasil analisis
summary(fit_retail, fit.measures = TRUE, standardized = TRUE, rsquare = TRUE)
## lavaan 0.6-21 ended normally after 50 iterations
##
## Estimator ML
## Optimization method NLMINB
## Number of model parameters 33
##
## Number of observations 150
##
## Model Test User Model:
##
## Test statistic 100.650
## Degrees of freedom 87
## P-value (Chi-square) 0.150
##
## Model Test Baseline Model:
##
## Test statistic 1783.505
## Degrees of freedom 105
## P-value 0.000
##
## User Model versus Baseline Model:
##
## Comparative Fit Index (CFI) 0.992
## Tucker-Lewis Index (TLI) 0.990
##
## Loglikelihood and Information Criteria:
##
## Loglikelihood user model (H0) -1606.878
## Loglikelihood unrestricted model (H1) -1556.553
##
## Akaike (AIC) 3279.756
## Bayesian (BIC) 3379.107
## Sample-size adjusted Bayesian (SABIC) 3274.668
##
## Root Mean Square Error of Approximation:
##
## RMSEA 0.032
## 90 Percent confidence interval - lower 0.000
## 90 Percent confidence interval - upper 0.057
## P-value H_0: RMSEA <= 0.050 0.864
## P-value H_0: RMSEA >= 0.080 0.000
##
## Standardized Root Mean Square Residual:
##
## SRMR 0.036
##
## Parameter Estimates:
##
## Standard errors Standard
## Information Expected
## Information saturated (h1) model Structured
##
## Latent Variables:
## Estimate Std.Err z-value P(>|z|) Std.lv Std.all
## WLB =~
## WLB1 1.000 0.641 0.866
## WLB2 0.890 0.072 12.431 0.000 0.570 0.812
## WLB3 0.950 0.078 12.216 0.000 0.609 0.803
## WLB4 0.907 0.072 12.623 0.000 0.581 0.819
## WLB5 0.979 0.075 13.101 0.000 0.627 0.838
## JS =~
## JS1 1.000 0.570 0.837
## JS2 1.044 0.080 13.008 0.000 0.595 0.857
## JS3 1.023 0.082 12.408 0.000 0.583 0.831
## JS4 0.973 0.077 12.619 0.000 0.555 0.840
## JS5 0.974 0.076 12.749 0.000 0.555 0.846
## EP =~
## EP1 1.000 0.604 0.811
## EP2 1.051 0.089 11.767 0.000 0.634 0.833
## EP3 1.076 0.090 11.940 0.000 0.649 0.842
## EP4 1.025 0.089 11.487 0.000 0.618 0.819
## EP5 0.968 0.083 11.644 0.000 0.584 0.827
##
## Regressions:
## Estimate Std.Err z-value P(>|z|) Std.lv Std.all
## JS ~
## WLB (a) 0.482 0.076 6.362 0.000 0.542 0.542
## EP ~
## JS (b) 0.549 0.091 6.032 0.000 0.518 0.518
## WLB (c) 0.332 0.076 4.372 0.000 0.353 0.353
##
## Variances:
## Estimate Std.Err z-value P(>|z|) Std.lv Std.all
## .WLB1 0.136 0.021 6.393 0.000 0.136 0.249
## .WLB2 0.168 0.023 7.212 0.000 0.168 0.341
## .WLB3 0.203 0.028 7.299 0.000 0.203 0.355
## .WLB4 0.165 0.023 7.128 0.000 0.165 0.329
## .WLB5 0.167 0.024 6.892 0.000 0.167 0.298
## .JS1 0.139 0.020 7.090 0.000 0.139 0.299
## .JS2 0.129 0.019 6.810 0.000 0.129 0.266
## .JS3 0.152 0.021 7.162 0.000 0.152 0.309
## .JS4 0.128 0.018 7.050 0.000 0.128 0.294
## .JS5 0.123 0.018 6.975 0.000 0.123 0.285
## .EP1 0.190 0.026 7.265 0.000 0.190 0.343
## .EP2 0.177 0.025 7.001 0.000 0.177 0.306
## .EP3 0.173 0.025 6.880 0.000 0.173 0.291
## .EP4 0.188 0.026 7.174 0.000 0.188 0.329
## .EP5 0.157 0.022 7.080 0.000 0.157 0.316
## WLB 0.410 0.063 6.534 0.000 1.000 1.000
## .JS 0.230 0.038 5.972 0.000 0.706 0.706
## .EP 0.149 0.028 5.287 0.000 0.409 0.409
##
## R-Square:
## Estimate
## WLB1 0.751
## WLB2 0.659
## WLB3 0.645
## WLB4 0.671
## WLB5 0.702
## JS1 0.701
## JS2 0.734
## JS3 0.691
## JS4 0.706
## JS5 0.715
## EP1 0.657
## EP2 0.694
## EP3 0.709
## EP4 0.671
## EP5 0.684
## JS 0.294
## EP 0.591
##
## Defined Parameters:
## Estimate Std.Err z-value P(>|z|) Std.lv Std.all
## indirect_effct 0.265 0.056 4.695 0.000 0.281 0.281
## total_effect 0.597 0.081 7.379 0.000 0.633 0.633
Meskipun model struktural kita sudah terbukti fit pada tahap sebelumnya, kita wajib mendokumentasikan bukti statistik bahwa alat ukur (kuesioner) yang kita gunakan memang valid dan reliabel. Ini adalah inti dari analisis Outer Model.
Kita akan mengevaluasi tiga aspek utama: 1. Validitas Konvergen (Convergent Validity): Mengukur seberapa baik indikator-indikator berkumpul untuk mewakili satu konsep. Metrik yang digunakan adalah Standardized Factor Loading (target > 0.70) dan Average Variance Extracted / AVE (target > 0.50). 2. Reliabilitas Konstruk (Construct Reliability): Mengukur konsistensi kuesioner. Jika tes diulang, apakah hasilnya akan sama? Metrik yang digunakan adalah Composite Reliability / CR atau Omega (target > 0.70). 3. Validitas Diskriminan (Discriminant Validity): Memastikan bahwa konstruk WLB, JS, dan EP benar-benar konsep yang berbeda dan tidak saling tumpang tindih. Kita akan menggunakan kriteria HTMT (Heterotrait-Monotrait Ratio), di mana nilainya harus < 0.90.
Kita akan menggunakan pustaka semTools untuk mengekstrak
metrik-metrik tersebut secara otomatis dari model yang sudah kita
eksekusi (fit_retail).
# Hapus tanda pagar di bawah ini jika pustaka semTools belum terinstal
# install.packages("semTools")
library(semTools)
## Warning: package 'semTools' was built under R version 4.5.3
##
## ###############################################################################
## This is semTools 0.5-8
## All users of R (or SEM) are invited to submit functions or ideas for functions.
## ###############################################################################
##
## Attaching package: 'semTools'
## The following objects are masked from 'package:psych':
##
## reliability, skew
cat("=== 1. VALIDITAS KONVERGEN (Standardized Loadings) ===\n")
## === 1. VALIDITAS KONVERGEN (Standardized Loadings) ===
# Mengekstrak matriks koefisien terstandardisasi khusus untuk indikator (=~)
loadings <- standardizedSolution(fit_retail)
loadings_filtered <- subset(loadings, op == "=~")
print(loadings_filtered[, c("lhs", "op", "rhs", "est.std", "pvalue")])
## lhs op rhs est.std pvalue
## 1 WLB =~ WLB1 0.866 0
## 2 WLB =~ WLB2 0.812 0
## 3 WLB =~ WLB3 0.803 0
## 4 WLB =~ WLB4 0.819 0
## 5 WLB =~ WLB5 0.838 0
## 6 JS =~ JS1 0.837 0
## 7 JS =~ JS2 0.857 0
## 8 JS =~ JS3 0.831 0
## 9 JS =~ JS4 0.840 0
## 10 JS =~ JS5 0.846 0
## 11 EP =~ EP1 0.811 0
## 12 EP =~ EP2 0.833 0
## 13 EP =~ EP3 0.842 0
## 14 EP =~ EP4 0.819 0
## 15 EP =~ EP5 0.827 0
cat("\n")
cat("=== 2. RELIABILITAS & AVE (Average Variance Extracted) ===\n")
## === 2. RELIABILITAS & AVE (Average Variance Extracted) ===
# Fungsi reliability() dari semTools akan otomatis menghitung Cronbach Alpha, CR (omega), dan AVE
reliabilitas_metrik <- reliability(fit_retail)
## Warning in reliability(fit_retail):
## The reliability() function was deprecated in 2022 and will cease to be included in future versions of semTools. See help('semTools-deprecated) for details.
##
## It is replaced by the compRelSEM() function, which can estimate alpha and model-based reliability in an even wider variety of models and data types, with greater control in specifying the desired type of reliability coefficient (i.e., more explicitly choosing assumptions).
##
## The average variance extracted should never have been included because it is not a reliability coefficient. It is now available from the AVE() function.
print(reliabilitas_metrik)
## WLB JS EP
## alpha 0.9154543 0.9239800 0.9149659
## omega 0.9160333 0.9242579 0.9151292
## omega2 0.9160333 0.9242579 0.9151292
## omega3 0.9164129 0.9245412 0.9147246
## avevar 0.6861359 0.7095065 0.6834902
cat("\n")
cat("=== 3. VALIDITAS DISKRIMINAN (Metode HTMT) ===\n")
## === 3. VALIDITAS DISKRIMINAN (Metode HTMT) ===
# Menghitung rasio HTMT untuk memastikan tidak ada tumpang tindih antar konsep
htmt_matrix <- htmt(model_retail, data = df_clean)
print(htmt_matrix)
## WLB JS EP
## WLB 1.000
## JS 0.543 1.000
## EP 0.631 0.706 1.000
Membaca matriks angka yang panjang bisa sangat melelahkan dan sulit dipahami oleh pemangku kepentingan (stakeholders). Oleh karena itu, kita akan menerjemahkan seluruh model struktural dan pengukuran kita ke dalam bentuk visual.
Kita menggunakan pustaka semPlot untuk menghasilkan
grafis Path Diagram. Beberapa parameter visualisasi yang kita
atur: * whatLabels = "std": Memastikan angka yang muncul di
atas panah adalah koefisien terstandardisasi (agar skalanya seragam). *
layout = "tree": Mengatur susunan tata letak diagram agar
rapi. * rotation = 2: Memutar diagram agar alurnya bergerak
masuk akal dari kiri ke kanan (WLB -> JS -> EP). *
style = "lisrel": Menggunakan standar visual akademik
klasik untuk SEM (Latent = Lingkaran, Indikator = Kotak).
# Memastikan pustaka semPlot sudah aktif
library(semPlot)
cat("Membangun visualisasi Path Diagram...\n")
## Membangun visualisasi Path Diagram...
# Menggambar grafis SEM
semPaths(fit_retail,
whatLabels = "std", # Menampilkan Standardized Loadings & Path Coefficients
layout = "tree", # Layout pohon agar rapi
rotation = 2, # Alur model dari kiri ke kanan
style = "lisrel", # Gaya klasik SEM
nCharNodes = 0, # Menampilkan nama variabel secara utuh (tidak disingkat)
sizeMan = 7, # Ukuran kotak indikator
sizeLat = 10, # Ukuran lingkaran variabel laten
edge.label.cex = 0.9, # Ukuran font angka di atas garis panah
fade = FALSE, # Warna garis tetap solid (tidak pudar)
posCol = "darkgreen", # Warna untuk korelasi/pengaruh positif
negCol = "red") # Warna untuk korelasi/pengaruh negatif
# Catatan: Gambar akan muncul di panel "Plots" pada RStudio Anda.