Memuat
Memuat
Covariance-Based SEM (lavaan) for Informatics and Information Systems
0 views
The goal is to test the fit of the perceived usefulness to user attitude to intention to use e-wallet path model with covariance-based SEM; all illustrations use synthetic data. Covariance-based SEM (CB-SEM) with lavaan estimates the measurement and structural models together and judges how well the model reproduces the data covariance matrix. It suits theses that test a theory (for example TAM or TPB) with Likert questionnaires and reasonably large samples.

The goal is to test the fit of the perceived usefulness to user attitude to intention to use e-wallet path model with covariance-based SEM; all illustrations use synthetic data.
| Role | Variable | Unit |
|---|---|---|
| Main | Intention to use e-wallet | Likert 1-5 |
| Supporting 1 | Perceived usefulness | Likert 1-5 |
| Supporting 2 | User attitude | Likert 1-5 |
The model fits the data well (CFI = 0.998, TLI = 0.997, RMSEA = 0.014, SRMR = 0.033). Perceived usefulness has a significant direct effect on Intention to use e-wallet (beta = 0.352, p < 0.001), and the indirect effect through User attitude is 0.345 (p < 0.001). The model explains 66.8% of the variance in Intention to use e-wallet.
Computed from illustrative synthetic data, not from a real study.
Covariance-based SEM (CB-SEM) with lavaan estimates the measurement and structural models together and judges how well the model reproduces the data covariance matrix. It suits theses that test a theory (for example TAM or TPB) with Likert questionnaires and reasonably large samples.
The model fits when CFI and TLI exceed 0.90 (preferably 0.95) and RMSEA and SRMR are below 0.08. Then report standardised loadings, standardised path coefficients with p-values, R2 of the endogenous constructs and the indirect effect a*b to conclude on the mediator.
A short starting script with this project's variable names. The delivered version is adapted to your data and fully commented.
# Contoh kode R: Covariance-Based SEM (lavaan)
suppressPackageStartupMessages({
library(ggplot2)
library(patchwork)
library(lavaan)
})
set.seed(42)
# ---- Gaya grafik ----
pal <- c("#1f6feb", "#e8590c", "#2f9e44", "#ae3ec9", "#f59f00")
warna <- list(bg = "#f4f6fa", panel = "#ffffff", teks = "#1f2933", redup = "#5f6b78", grid = "#e3e8ee", bar = "#1d3557")
tata <- 1
theme_set(theme_minimal(base_size = 11) + theme(legend.position = "bottom"))
# ---- Data sintetis: 12 butir Likert 1-5 dari tiga konstruk laten ----
n <- 200
a <- runif(1, 0.4, 0.7) # jalur X1 -> X2 (mediator)
b <- runif(1, 0.3, 0.55) # jalur X2 -> Y
cp <- runif(1, 0.1, 0.35) # jalur langsung X1 -> Y
e_x1 <- rnorm(n)
e_x2 <- a * e_x1 + rnorm(n, 0, sqrt(1 - a^2))
e_y <- as.numeric(scale(cp * e_x1 + b * e_x2 + rnorm(n, 0, runif(1, 0.55, 0.75))))
# butir Likert: muatan acak 0.65-0.9, ambang diacak agar rata-rata butir sekitar 3.4-3.8
likert <- function(eta, k) {
sapply(seq_len(k), function(j) {
l <- runif(1, 0.65, 0.9)
s <- l * eta + rnorm(length(eta), 0, sqrt(1 - l^2))
findInterval(s, sort(c(-2, -1.1, -0.2, 0.9) + runif(1, -0.3, 0.2))) + 1
})
}
# butir Y ke-4 sedikit ikut dipengaruhi X1 (muatan silang kecil) agar kecocokan model realistis, tidak sempurna
d <- data.frame(likert(e_x1, 4), likert(e_x2, 4), likert(e_y, 3),
likert(as.numeric(scale(e_y + runif(1, 0.25, 0.5) * e_x1)), 1))
names(d) <- c(paste0("perceived_usefulness", "_", 1:4), paste0("user_attitude", "_", 1:4), paste0("intention_to_use_e_wallet", "_", 1:4))
write.csv(d, "data_contoh.csv", row.names = FALSE)
# ---- Spesifikasi model: pengukuran (=~), struktural (~), efek tidak langsung (:=) ----
model <- paste0(
"perceived_usefulness =~ ", paste(names(d)[1:4], collapse = " + "), "\n",
"user_attitude =~ ", paste(names(d)[5:8], collapse = " + "), "\n",
"intention_to_use_e_wallet =~ ", paste(names(d)[9:12], collapse = " + "), "\n",
"user_attitude ~ a*perceived_usefulness\n",
"intention_to_use_e_wallet ~ b*user_attitude + c*perceived_usefulness\n",
"tidak_langsung := a*b\n",
"total := c + a*b\n")
cat(model)
fit <- sem(model, data = d, estimator = "MLR") # ML robust (data Likert diperlakukan kontinu)
print(summary(fit, fit.measures = TRUE, standardized = TRUE, rsquare = TRUE))
# ---- Indeks kecocokan model (versi robust, cadangan versi biasa) ----
fm <- fitMeasures(fit, c("cfi.robust", "tli.robust", "rmsea.robust", "srmr", "cfi", "tli", "rmsea"))
pilih <- function(r, s) if (is.finite(fm[[r]])) fm[[r]] else fm[[s]]
idx <- c(CFI = pilih("cfi.robust", "cfi"), TLI = pilih("tli.robust", "tli"),
RMSEA = pilih("rmsea.robust", "rmsea"), SRMR = fm[["srmr"]])
print(round(idx, 3))
# ---- Koefisien terstandar ----
ss <- standardizedSolution(fit)
jalur <- ss[ss$op == "~", ]
ambil <- function(lhs, rhs) jalur[jalur$lhs == lhs & jalur$rhs == rhs, ]
j_a <- ambil("user_attitude", "perceived_usefulness"); j_b <- ambil("intention_to_use_e_wallet", "user_attitude"); j_c <- ambil("intention_to_use_e_wallet", "perceived_usefulness")
tl <- ss[ss$op == ":=" & ss$lhs == "tidak_langsung", ]
muat <- ss[ss$op == "=~", ]
r2 <- lavInspect(fit, "rsquare")
print(jalur[, c("lhs", "rhs", "est.std", "se", "pvalue")]); print(tl)
# ---- Grafik ----
singkat <- function(s, w = 18) { # nama konstruk pendek untuk grafik
k <- strsplit(s, " ")[[1]]
if (nchar(s) > w) k <- k[!tolower(k) %in% c("of", "to", "the", "and", "for", "in", "on", "with")]
i <- length(k)
while (nchar(paste(k, collapse = " ")) > w && i >= 1) {
if (nchar(k[i]) > 5) k[i] <- paste0(substr(k[i], 1, 4), ".")
i <- i - 1
}
substr(paste(k, collapse = " "), 1, w)
}
nm_k <- make.unique(unname(sapply(c("perceived_usefulness", "user_attitude", "intention_to_use_e_wallet"), singkat)), sep = " ")
bintang <- function(p) ifelse(p < 0.001, "***", ifelse(p < 0.01, "**", ifelse(p < 0.05, "*", " ns")))
elips <- function(x0, y0, rx = 0.74, ry = 0.3, id = 1) {
t_ <- seq(0, 2 * pi, length.out = 60)
data.frame(x = x0 + rx * cos(t_), y = y0 + ry * sin(t_), id = id)
}
pos <- data.frame(x = c(0, 1.6, 3.2), y = c(0, 1.25, 0), lab = nm_k)
de <- do.call(rbind, lapply(1:3, function(i) elips(pos$x[i], pos$y[i], id = i)))
# kotak indikator: X1 di kiri bawah, X2 di atas, Y di kanan bawah
ind <- data.frame(x = c(-0.9, -0.3, 0.3, 0.9, 0.7, 1.3, 1.9, 2.5, 2.3, 2.9, 3.5, 4.1),
y = rep(c(-0.95, 2.35, -0.95), each = 4), grup = rep(1:3, each = 4),
lab = paste0(rep(c("X1.", "M.", "Y."), each = 4), rep(1:4, 3)))
ind$xl <- pos$x[ind$grup]; ind$yl <- pos$y[ind$grup] + ifelse(ind$grup == 2, 0.3, -0.3)
st <- data.frame(x = c(0.45, 2.15, 0.78), y = c(0.3, 0.95, 0), xend = c(1.05, 2.75, 2.42), yend = c(1.0, 0.3, 0),
lab = sprintf("%.2f%s", c(j_a$est.std, j_b$est.std, j_c$est.std), bintang(c(j_a$pvalue, j_b$pvalue, j_c$pvalue))),
lx = c(0.55, 2.65, 1.6), ly = c(0.78, 0.78, -0.14))
p1 <- ggplot() +
geom_segment(data = ind, aes(xl, yl, xend = x, yend = y + ifelse(grup == 2, -0.15, 0.15)), colour = warna$redup,
linewidth = 0.4, arrow = arrow(length = unit(0.07, "inches"), type = "closed")) +
geom_tile(data = ind, aes(x, y), width = 0.5, height = 0.3, fill = warna$panel, colour = warna$redup, linewidth = 0.4) +
geom_text(data = ind, aes(x, y, label = lab), colour = warna$teks, size = 2.6) +
geom_segment(data = st, aes(x, y, xend = xend, yend = yend), colour = warna$teks, linewidth = 0.9,
arrow = arrow(length = unit(0.13, "inches"), type = "closed")) +
geom_text(data = st, aes(lx, ly, label = lab), colour = warna$teks, fontface = "bold", size = 3.3) +
geom_polygon(data = de, aes(x, y, group = id, fill = factor(id)), show.legend = FALSE) +
scale_fill_manual(values = pal[1:3]) +
geom_text(data = pos, aes(x, y, label = lab), colour = warna$panel, fontface = "bold", size = 3) +
annotate("text", x = 1.6, y = -1.38, size = 3, colour = warna$teks,
label = sprintf("Std. indirect = %.3f%s R2 = %.2f", tl$est.std, bintang(tl$pvalue), r2[["intention_to_use_e_wallet"]])) +
coord_cartesian(xlim = c(-1.25, 4.45), ylim = c(-1.5, 2.6)) +
theme_void() + theme(plot.background = element_rect(fill = warna$panel, colour = NA),
plot.title = element_text(face = "bold", colour = warna$teks, margin = margin(4, 0, 4, 6))) +
labs(title = "Standardised structural model (MLR)")
df <- data.frame(indeks = factor(names(idx), levels = names(idx)), nilai = unname(idx),
ambang = c(0.9, 0.9, 0.08, 0.08), arah = c("Higher is better", "Higher is better", "Lower is better", "Lower is better"))
p2 <- ggplot(df, aes(indeks, nilai, fill = arah)) +
geom_col(width = 0.6) +
geom_errorbar(aes(ymin = ambang, ymax = ambang), width = 0.8, linetype = "dashed", colour = warna$teks, linewidth = 0.6) +
geom_text(aes(label = sprintf("%.3f", nilai)), vjust = -0.4, colour = warna$teks, size = 3) +
facet_wrap(~arah, scales = "free") +
scale_fill_manual(values = pal[4:5], guide = "none") +
scale_y_continuous(expand = expansion(mult = c(0, 0.15))) +
labs(title = "Fit indices vs cut-offs (dashed)", x = NULL, y = "Value")
muat$konstruk <- factor(nm_k[match(muat$lhs, c("perceived_usefulness", "user_attitude", "intention_to_use_e_wallet"))], levels = nm_k)
muat$butir <- factor(ind$lab, levels = rev(ind$lab))
p3 <- ggplot(muat, aes(est.std, butir, colour = konstruk)) +
geom_vline(xintercept = 0.7, linetype = "dashed", colour = warna$redup) +
geom_segment(aes(x = 0, xend = est.std, yend = butir), linewidth = 0.9) +
geom_point(size = 2.6) +
geom_text(aes(label = sprintf("%.2f", est.std)), hjust = -0.35, size = 2.6, colour = warna$teks) +
scale_colour_manual(values = pal[1:3], name = NULL) +
scale_x_continuous(limits = c(0, 1.1), breaks = seq(0, 1, 0.25)) +
labs(title = "Standardised loadings", x = "Loading", y = NULL)
p_hasil <- if (tata == 1) p1 / (p2 | p3) + plot_layout(heights = c(1.15, 1)) else p1 | (p2 / p3)
print(p_hasil)
The original project file is available. It is not just the picture above: you get the working R project. It can be downloaded after payment, and we send it by WhatsApp or email.
ZIP: analisis.R + data_contoh.csv + BACA-DULU.txt
Choose how much help you need. Each higher package includes everything in the lower ones. Prices exclude 11% VAT.
Package 1
US$34
excl. 11% VAT
Duration: 7 working days
Output: R files + result figures
Deliverables
Package 2 · most chosen
US$100
excl. 11% VAT
Duration: 13 working days
Output: Code + analysis + interpretation notes
Includes all of Package 1, plus
Package 3
US$219
excl. 11% VAT
Duration: 18-21 working days
Output: Code + analysis + guidance until ready to present
Includes all of Packages 1 & 2, plus
Yes. The original project file is a ZIP containing the complete analisis.R script, a data_contoh.csv sample dataset and a BACA-DULU.txt guide. It can be downloaded after payment, and we send it by WhatsApp or email. For your own data (Package 2 and 3) the script is adapted to your dataset.
Yes. Covariance-Based SEM (lavaan) is commonly used at this level in Informatics and Information Systems. We adapt the analysis to your research question, your own data and your supervisor's requirements.
No. The sheet is computed from illustrative synthetic data so you can see the kind of output R Studio gives. For your order we run the same method on your own data.
That is the point of the packages. Every script is commented, and Package 3 includes two coaching sessions plus practice questions so you can explain the method and the results at your seminar and defence.
Each project has three packages: Package 1 (code and explanation) US$34, Package 2 (your data analysis and interpretation) US$100 and Package 3 (full guidance) US$219, excluding 11% VAT. Larger datasets, extra methods or tight deadlines adjust the quote after a short consultation.
The result sheet uses illustrative synthetic data. R is a programming language of the R Foundation project; RStudio and Posit are trademarks of Posit PBC.
Back to R Studio portfolio