File này không chỉ in lại output từ SEMinR. Mục tiêu là giúp đọc kết quả theo đúng trình tự của một phân tích PLS-SEM.
Trình tự được dùng trong báo cáo:
Nguyên tắc quan trọng: chưa nên diễn giải các structural paths nếu measurement model chưa được chứng minh là đạt yêu cầu.
Mô hình gồm 7 constructs phản xạ:
| Construct | Nội dung | Indicators |
|---|---|---|
| SQ | AI System Quality | SQ1–SQ5 |
| PP | Perceived Personalization | PP1–PP5 |
| TR | AI Transparency | TR1–TR3 |
| PU | Perceived Usefulness | PU1–PU4 |
| PEOU | Perceived Ease of Use | PEOU1–PEOU4 |
| BT | Brand Trust | BT1–BT4 |
| PI | Purchase Intention | PI1–PI3 |
Phân tích structural model gồm:
Trước khi chạy PLS-SEM cần xác nhận:
Điều này bảo đảm rằng phần descriptive và phần PLS-SEM không vô tình sử dụng hai bộ dữ liệu khác nhau.
| Metric | Value |
|---|---|
| Rows | 534 |
| Columns | 29 |
| Duplicate IDs | 0 |
| Missing cells in scale items | 0 |
| Cases with >=1 missing scale item | 0 |
| Out-of-range Likert responses | 0 |
| Metric | Value |
|---|---|
| SPSS unique IDs | 534 |
| PLS unique IDs | 534 |
| Common IDs | 534 |
| PLS IDs missing from SPSS | 0 |
| SPSS IDs missing from PLS | 0 |
| Scale-item mismatches | 0 |
Có thể tiếp tục sang measurement model nếu:
Với reflective measurement model, outer loading cho biết một indicator phản ánh construct của nó mạnh đến mức nào.
Ngưỡng tham khảo thường dùng:
Bình phương loading chính là indicator reliability.
Ví dụ:
\[ 0.708^2 \approx 0.50 \]
nghĩa là construct giải thích khoảng 50% phương sai của indicator đó.
loading_report <- outer_loadings
if ("Loading" %in% names(loading_report)) {
loading_report <- loading_report |>
mutate(
Loading_Decision = interpret_loading(abs(Loading))
)
}
show_table(
loading_report,
caption = "Outer loadings và indicator reliability"
)| Indicator | Construct | Loading | Indicator_Reliability | Loading_Assessment | Indicator_Reliability_Assessment | Loading_Decision |
|---|---|---|---|---|---|---|
| SQ1 | SQ | 0.826 | 0.682 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| SQ2 | SQ | 0.768 | 0.590 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| SQ3 | SQ | 0.771 | 0.595 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| SQ4 | SQ | 0.832 | 0.693 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| SQ5 | SQ | 0.807 | 0.651 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| PP1 | PP | 0.820 | 0.672 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| PP2 | PP | 0.815 | 0.664 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| PP3 | PP | 0.803 | 0.645 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| PP4 | PP | 0.753 | 0.567 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| PP5 | PP | 0.802 | 0.643 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| TR1 | TR | 0.854 | 0.730 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| TR2 | TR | 0.861 | 0.742 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| TR3 | TR | 0.804 | 0.646 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| PEOU1 | PEOU | 0.844 | 0.713 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| PEOU2 | PEOU | 0.807 | 0.652 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| PEOU3 | PEOU | 0.860 | 0.740 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| PEOU4 | PEOU | 0.795 | 0.632 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| PU1 | PU | 0.844 | 0.713 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| PU2 | PU | 0.816 | 0.666 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| PU3 | PU | 0.862 | 0.743 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| PU4 | PU | 0.858 | 0.737 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| BT1 | BT | 0.833 | 0.694 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| BT2 | BT | 0.852 | 0.726 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| BT3 | BT | 0.839 | 0.705 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| BT4 | BT | 0.847 | 0.717 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| PI1 | PI | 0.849 | 0.721 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| PI2 | PI | 0.866 | 0.751 | Recommended (>= 0.708) | >= 0.50 | Đạt |
| PI3 | PI | 0.836 | 0.698 | Recommended (>= 0.708) | >= 0.50 | Đạt |
if (all(c("Indicator", "Construct", "Loading") %in% names(outer_loadings))) {
ggplot(
outer_loadings,
aes(
x = reorder(Indicator, Loading),
y = Loading
)
) +
geom_col() +
geom_hline(
yintercept = 0.708,
linetype = "dashed"
) +
facet_wrap(
~ Construct,
scales = "free_x"
) +
coord_flip() +
labs(
title = "Outer Loadings theo từng Construct",
subtitle = "Đường đứt = ngưỡng tham khảo 0.708",
x = NULL,
y = "Outer loading"
) +
theme_minimal(base_size = 11)
}if ("Loading" %in% names(outer_loadings) && nrow(outer_loadings) > 0) {
min_loading <- min(abs(outer_loadings$Loading), na.rm = TRUE)
max_loading <- max(abs(outer_loadings$Loading), na.rm = TRUE)
n_ge_708 <- sum(abs(outer_loadings$Loading) >= 0.708, na.rm = TRUE)
n_indicators <- sum(!is.na(outer_loadings$Loading))
cat(
sprintf(
"Mô hình có **%d indicators**. Outer loadings nằm trong khoảng **%.3f–%.3f**. ",
n_indicators,
min_loading,
max_loading
)
)
cat(
sprintf(
"Có **%d/%d indicators đạt loading ≥ 0.708**. ",
n_ge_708,
n_indicators
)
)
if (n_ge_708 == n_indicators) {
cat(
"Do đó, indicator reliability đạt yêu cầu và không có lý do thống kê để loại item chỉ dựa trên outer loading.\n"
)
} else {
cat(
"Những item dưới 0.708 phải được đánh giá cùng CR, AVE và nội dung thang đo trước khi quyết định giữ hay loại.\n"
)
}
}Mô hình có 28 indicators. Outer loadings nằm trong khoảng 0.753–0.866. Có 28/28 indicators đạt loading ≥ 0.708. Do đó, indicator reliability đạt yêu cầu và không có lý do thống kê để loại item chỉ dựa trên outer loading.
Ba chỉ số được dùng:
Ngưỡng tham khảo:
Average Variance Extracted (AVE) đo convergent validity.
| Construct | alpha | rhoA | rhoC | AVE | Alpha_OK | rhoA_OK | rhoC_OK | AVE_OK | Overall_Assessment |
|---|---|---|---|---|---|---|---|---|---|
| SQ | 0.860 | 0.865 | 0.900 | 0.642 | TRUE | TRUE | TRUE | TRUE | Pass |
| PP | 0.858 | 0.863 | 0.898 | 0.638 | TRUE | TRUE | TRUE | TRUE | Pass |
| TR | 0.793 | 0.806 | 0.878 | 0.706 | TRUE | TRUE | TRUE | TRUE | Pass |
| PEOU | 0.846 | 0.849 | 0.896 | 0.684 | TRUE | TRUE | TRUE | TRUE | Pass |
| PU | 0.867 | 0.868 | 0.909 | 0.715 | TRUE | TRUE | TRUE | TRUE | Pass |
| BT | 0.864 | 0.865 | 0.908 | 0.711 | TRUE | TRUE | TRUE | TRUE | Pass |
| PI | 0.809 | 0.814 | 0.887 | 0.724 | TRUE | TRUE | TRUE | TRUE | Pass |
if (nrow(reliability_ave) > 0) {
if ("alpha" %in% names(reliability_ave)) {
cat(
sprintf(
"- Cronbach's alpha: **%.3f–%.3f**.\n",
min(reliability_ave$alpha, na.rm = TRUE),
max(reliability_ave$alpha, na.rm = TRUE)
)
)
}
if ("rhoA" %in% names(reliability_ave)) {
cat(
sprintf(
"- rho_A: **%.3f–%.3f**.\n",
min(reliability_ave$rhoA, na.rm = TRUE),
max(reliability_ave$rhoA, na.rm = TRUE)
)
)
}
if ("rhoC" %in% names(reliability_ave)) {
cat(
sprintf(
"- Composite Reliability: **%.3f–%.3f**.\n",
min(reliability_ave$rhoC, na.rm = TRUE),
max(reliability_ave$rhoC, na.rm = TRUE)
)
)
}
if ("AVE" %in% names(reliability_ave)) {
cat(
sprintf(
"- AVE: **%.3f–%.3f**.\n",
min(reliability_ave$AVE, na.rm = TRUE),
max(reliability_ave$AVE, na.rm = TRUE)
)
)
}
if (all(c("alpha", "rhoA", "rhoC", "AVE") %in% names(reliability_ave))) {
all_pass <- all(
reliability_ave$alpha >= 0.70 &
reliability_ave$rhoA >= 0.70 &
reliability_ave$rhoC >= 0.70 &
reliability_ave$rhoC <= 0.95 &
reliability_ave$AVE >= 0.50,
na.rm = TRUE
)
if (all_pass) {
cat(
"\n**Kết luận:** toàn bộ constructs đạt internal consistency reliability và convergent validity theo các tiêu chuẩn được sử dụng.\n"
)
} else {
cat(
"\n**Kết luận:** có ít nhất một construct cần kiểm tra kỹ hơn trước khi chuyển sang structural model.\n"
)
}
}
}Kết luận: toàn bộ constructs đạt internal consistency reliability và convergent validity theo các tiêu chuẩn được sử dụng.
Discriminant validity trả lời câu hỏi:
Các construct có thực sự khác nhau về mặt thực nghiệm hay chúng đang đo gần như cùng một khái niệm?
Trong báo cáo này, HTMT được ưu tiên. Fornell–Larcker và cross-loadings được dùng bổ sung.
Ngưỡng tham khảo:
| Construct_1 | Construct_2 | HTMT | Pair_Key | HTMT_085 | HTMT_090 |
|---|---|---|---|---|---|
| PP | SQ | 0.327 | PP | SQ | Pass | Pass |
| TR | SQ | 0.222 | SQ | TR | Pass | Pass |
| PEOU | SQ | 0.390 | PEOU | SQ | Pass | Pass |
| PU | SQ | 0.441 | PU | SQ | Pass | Pass |
| BT | SQ | 0.479 | BT | SQ | Pass | Pass |
| PI | SQ | 0.318 | PI | SQ | Pass | Pass |
| TR | PP | 0.245 | PP | TR | Pass | Pass |
| PEOU | PP | 0.374 | PEOU | PP | Pass | Pass |
| PU | PP | 0.414 | PP | PU | Pass | Pass |
| BT | PP | 0.429 | BT | PP | Pass | Pass |
| PI | PP | 0.233 | PI | PP | Pass | Pass |
| PEOU | TR | 0.378 | PEOU | TR | Pass | Pass |
| PU | TR | 0.383 | PU | TR | Pass | Pass |
| BT | TR | 0.383 | BT | TR | Pass | Pass |
| PI | TR | 0.267 | PI | TR | Pass | Pass |
| PU | PEOU | 0.559 | PEOU | PU | Pass | Pass |
| BT | PEOU | 0.494 | BT | PEOU | Pass | Pass |
| PI | PEOU | 0.473 | PEOU | PI | Pass | Pass |
| BT | PU | 0.525 | BT | PU | Pass | Pass |
| PI | PU | 0.464 | PI | PU | Pass | Pass |
| PI | BT | 0.575 | BT | PI | Pass | Pass |
if ("HTMT" %in% names(htmt_long) && nrow(htmt_long) > 0) {
max_htmt <- max(htmt_long$HTMT, na.rm = TRUE)
max_pair <- htmt_long |>
filter(HTMT == max(HTMT, na.rm = TRUE)) |>
slice(1)
cat(
sprintf(
"HTMT lớn nhất = **%.3f**",
max_htmt
)
)
if (all(c("Construct_1", "Construct_2") %in% names(max_pair))) {
cat(
sprintf(
", giữa **%s và %s**",
max_pair$Construct_1,
max_pair$Construct_2
)
)
}
cat(". ")
if (max_htmt < 0.85) {
cat(
"Giá trị này thấp hơn 0.85, vì vậy discriminant validity được hỗ trợ rõ ràng.\n"
)
} else if (max_htmt < 0.90) {
cat(
"Giá trị nằm giữa 0.85 và 0.90; cần diễn giải cùng mức độ tương đồng lý thuyết của hai constructs.\n"
)
} else {
cat(
"Giá trị này cần được xem xét kỹ vì có thể tồn tại vấn đề discriminant validity.\n"
)
}
}HTMT lớn nhất = 0.575, giữa PI và BT. Giá trị này thấp hơn 0.85, vì vậy discriminant validity được hỗ trợ rõ ràng.
if (all(c("Construct_1", "Construct_2", "HTMT") %in% names(htmt_long))) {
ggplot(
htmt_long,
aes(
x = Construct_1,
y = Construct_2,
fill = HTMT
)
) +
geom_tile() +
geom_text(
aes(label = sprintf("%.3f", HTMT)),
size = 3
) +
labs(
title = "HTMT Heatmap",
x = NULL,
y = NULL,
fill = "HTMT"
) +
theme_minimal(base_size = 11) +
theme(
axis.text.x = element_text(angle = 45, hjust = 1)
)
}| Construct_Pair | Original_Est | Bootstrap_Mean | Bootstrap_SD | T_Stat | CI_Lower | CI_Upper | Bootstrap_P | HTMT_CI_below_0_85 | HTMT_CI_below_0_90 |
|---|---|---|---|---|---|---|---|---|---|
| SQ -> PP | 0.327 | 0.326 | 0.044 | 15.150 | 0.251 | 0.398 | 0 | TRUE | TRUE |
| SQ -> TR | 0.222 | 0.222 | 0.051 | 15.152 | 0.137 | 0.307 | 0 | TRUE | TRUE |
| SQ -> PEOU | 0.390 | 0.390 | 0.046 | 13.283 | 0.313 | 0.465 | 0 | TRUE | TRUE |
| SQ -> PU | 0.441 | 0.440 | 0.043 | 12.937 | 0.366 | 0.509 | 0 | TRUE | TRUE |
| SQ -> BT | 0.479 | 0.478 | 0.041 | 12.719 | 0.411 | 0.546 | 0 | TRUE | TRUE |
| SQ -> PI | 0.318 | 0.318 | 0.046 | 14.825 | 0.242 | 0.393 | 0 | TRUE | TRUE |
| PP -> TR | 0.245 | 0.247 | 0.049 | 15.520 | 0.169 | 0.328 | 0 | TRUE | TRUE |
| PP -> PEOU | 0.374 | 0.374 | 0.045 | 14.030 | 0.298 | 0.445 | 0 | TRUE | TRUE |
| PP -> PU | 0.414 | 0.414 | 0.041 | 14.282 | 0.346 | 0.480 | 0 | TRUE | TRUE |
| PP -> BT | 0.429 | 0.429 | 0.040 | 14.295 | 0.363 | 0.494 | 0 | TRUE | TRUE |
| PP -> PI | 0.233 | 0.234 | 0.047 | 16.208 | 0.156 | 0.312 | 0 | TRUE | TRUE |
| TR -> PEOU | 0.378 | 0.378 | 0.045 | 13.972 | 0.303 | 0.450 | 0 | TRUE | TRUE |
| TR -> PU | 0.383 | 0.383 | 0.048 | 12.842 | 0.301 | 0.460 | 0 | TRUE | TRUE |
| TR -> BT | 0.383 | 0.382 | 0.047 | 13.165 | 0.304 | 0.458 | 0 | TRUE | TRUE |
| TR -> PI | 0.267 | 0.267 | 0.051 | 14.332 | 0.183 | 0.352 | 0 | TRUE | TRUE |
| PEOU -> PU | 0.559 | 0.558 | 0.037 | 11.892 | 0.496 | 0.617 | 0 | TRUE | TRUE |
| PEOU -> BT | 0.494 | 0.494 | 0.041 | 12.277 | 0.425 | 0.560 | 0 | TRUE | TRUE |
| PEOU -> PI | 0.473 | 0.473 | 0.044 | 12.028 | 0.400 | 0.545 | 0 | TRUE | TRUE |
| PU -> BT | 0.525 | 0.524 | 0.041 | 11.438 | 0.454 | 0.591 | 0 | TRUE | TRUE |
| PU -> PI | 0.464 | 0.463 | 0.043 | 12.574 | 0.393 | 0.533 | 0 | TRUE | TRUE |
| BT -> PI | 0.575 | 0.575 | 0.038 | 11.274 | 0.510 | 0.635 | 0 | TRUE | TRUE |
Điểm cần nhớ:
Không nên nhầm hai loại tiêu chuẩn này.
| Row | SQ | PP | TR | PEOU | PU | BT | PI |
|---|---|---|---|---|---|---|---|
| SQ | 0.801 | NA | NA | NA | NA | NA | NA |
| PP | 0.281 | 0.799 | NA | NA | NA | NA | NA |
| TR | 0.185 | 0.211 | 0.840 | NA | NA | NA | NA |
| PEOU | 0.336 | 0.321 | 0.311 | 0.827 | NA | NA | NA |
| PU | 0.382 | 0.359 | 0.323 | 0.478 | 0.845 | NA | NA |
| BT | 0.415 | 0.374 | 0.320 | 0.426 | 0.455 | 0.843 | NA |
| PI | 0.267 | 0.201 | 0.217 | 0.393 | 0.391 | 0.482 | 0.851 |
Logic:
Đây là diagnostic bổ sung. Khi HTMT đã được báo cáo, không nên chỉ dựa vào Fornell–Larcker để kết luận discriminant validity.
| Row | SQ | PP | TR | PEOU | PU | BT | PI |
|---|---|---|---|---|---|---|---|
| SQ1 | 0.826 | 0.229 | 0.174 | 0.312 | 0.341 | 0.359 | 0.218 |
| SQ2 | 0.768 | 0.210 | 0.132 | 0.230 | 0.273 | 0.304 | 0.201 |
| SQ3 | 0.771 | 0.244 | 0.158 | 0.220 | 0.304 | 0.324 | 0.235 |
| SQ4 | 0.832 | 0.252 | 0.130 | 0.283 | 0.324 | 0.326 | 0.198 |
| SQ5 | 0.807 | 0.190 | 0.146 | 0.293 | 0.284 | 0.346 | 0.217 |
| PP1 | 0.254 | 0.820 | 0.127 | 0.278 | 0.302 | 0.296 | 0.167 |
| PP2 | 0.216 | 0.815 | 0.181 | 0.253 | 0.303 | 0.316 | 0.184 |
| PP3 | 0.208 | 0.803 | 0.203 | 0.271 | 0.299 | 0.309 | 0.215 |
| PP4 | 0.213 | 0.753 | 0.113 | 0.219 | 0.240 | 0.226 | 0.080 |
| PP5 | 0.229 | 0.802 | 0.209 | 0.255 | 0.284 | 0.335 | 0.140 |
| TR1 | 0.148 | 0.185 | 0.854 | 0.291 | 0.272 | 0.291 | 0.184 |
| TR2 | 0.181 | 0.227 | 0.861 | 0.250 | 0.329 | 0.283 | 0.212 |
| TR3 | 0.135 | 0.105 | 0.804 | 0.241 | 0.199 | 0.227 | 0.145 |
| PU1 | 0.322 | 0.332 | 0.284 | 0.420 | 0.844 | 0.357 | 0.290 |
| PU2 | 0.307 | 0.272 | 0.258 | 0.383 | 0.816 | 0.382 | 0.309 |
| PU3 | 0.303 | 0.331 | 0.282 | 0.419 | 0.862 | 0.385 | 0.367 |
| PU4 | 0.359 | 0.281 | 0.270 | 0.396 | 0.858 | 0.414 | 0.354 |
| PEOU1 | 0.305 | 0.217 | 0.219 | 0.844 | 0.402 | 0.338 | 0.316 |
| PEOU2 | 0.278 | 0.274 | 0.250 | 0.807 | 0.385 | 0.346 | 0.318 |
| PEOU3 | 0.303 | 0.295 | 0.277 | 0.860 | 0.395 | 0.430 | 0.349 |
| PEOU4 | 0.224 | 0.271 | 0.282 | 0.795 | 0.402 | 0.285 | 0.317 |
| BT1 | 0.292 | 0.294 | 0.254 | 0.358 | 0.367 | 0.833 | 0.405 |
| BT2 | 0.393 | 0.355 | 0.270 | 0.367 | 0.386 | 0.852 | 0.428 |
| BT3 | 0.380 | 0.294 | 0.278 | 0.351 | 0.395 | 0.839 | 0.394 |
| BT4 | 0.329 | 0.315 | 0.277 | 0.359 | 0.386 | 0.847 | 0.398 |
| PI1 | 0.195 | 0.162 | 0.214 | 0.310 | 0.349 | 0.403 | 0.849 |
| PI2 | 0.264 | 0.214 | 0.181 | 0.368 | 0.361 | 0.438 | 0.866 |
| PI3 | 0.218 | 0.130 | 0.159 | 0.324 | 0.285 | 0.386 | 0.836 |
Một indicator nên có loading lớn nhất trên chính construct mà nó được thiết kế để đo.
Trước khi đọc path coefficients, cần xác nhận rằng các predictor constructs không bị collinearity quá cao.
Ngưỡng tham khảo:
| Outcome | Predictor | VIF | VIF_Assessment |
|---|---|---|---|
| PU | SQ | 1.177 | < 3 (conservative criterion met) |
| PU | PP | 1.172 | < 3 (conservative criterion met) |
| PU | TR | 1.130 | < 3 (conservative criterion met) |
| PU | PEOU | 1.275 | < 3 (conservative criterion met) |
| PEOU | SQ | 1.105 | < 3 (conservative criterion met) |
| PEOU | PP | 1.117 | < 3 (conservative criterion met) |
| PEOU | TR | 1.066 | < 3 (conservative criterion met) |
| BT | SQ | 1.239 | < 3 (conservative criterion met) |
| BT | PP | 1.216 | < 3 (conservative criterion met) |
| BT | TR | 1.165 | < 3 (conservative criterion met) |
| BT | PU | 1.505 | < 3 (conservative criterion met) |
| BT | PEOU | 1.417 | < 3 (conservative criterion met) |
| PI | PU | 1.441 | < 3 (conservative criterion met) |
| PI | PEOU | 1.395 | < 3 (conservative criterion met) |
| PI | BT | 1.358 | < 3 (conservative criterion met) |
if ("VIF" %in% names(structural_vif) && nrow(structural_vif) > 0) {
min_vif <- min(structural_vif$VIF, na.rm = TRUE)
max_vif <- max(structural_vif$VIF, na.rm = TRUE)
cat(
sprintf(
"Structural VIF nằm trong khoảng **%.3f–%.3f**. ",
min_vif,
max_vif
)
)
if (max_vif < 3) {
cat(
"Toàn bộ VIF < 3, do đó không có dấu hiệu structural collinearity đáng kể.\n"
)
} else if (max_vif < 5) {
cat(
"Có VIF lớn hơn 3 nhưng vẫn dưới 5; cần kiểm tra predictor set tương ứng.\n"
)
} else {
cat(
"Có VIF ≥ 5, vì vậy cần xem xét collinearity trước khi diễn giải paths.\n"
)
}
}Structural VIF nằm trong khoảng 1.066–1.505. Toàn bộ VIF < 3, do đó không có dấu hiệu structural collinearity đáng kể.
R² cho biết tỷ lệ variance của một endogenous construct được giải thích bởi các predictors trong model.
Ví dụ:
\[ R^2 = 0.30 \]
nghĩa là model giải thích khoảng 30% variance của endogenous construct đó.
Các mức 0.25 / 0.50 / 0.75 đôi khi được dùng làm heuristic, nhưng không phải ngưỡng pass/fail phổ quát.
| Construct | R^2 | AdjR^2 | R2_Heuristic |
|---|---|---|---|
| PU | 0.336 | 0.331 | Weak |
| PEOU | 0.216 | 0.211 | Very weak / context dependent |
| BT | 0.351 | 0.345 | Weak |
| PI | 0.292 | 0.288 | Weak |
if (all(c("Construct", "R^2") %in% names(r2_table))) {
ggplot(
r2_table,
aes(
x = reorder(Construct, `R^2`),
y = `R^2`
)
) +
geom_col() +
coord_flip() +
scale_y_continuous(
limits = c(0, 1),
labels = percent_format(accuracy = 1)
) +
labs(
title = "Explained Variance",
x = NULL,
y = expression(R^2)
) +
theme_minimal(base_size = 11)
}if (all(c("Construct", "R^2") %in% names(r2_table))) {
for (i in seq_len(nrow(r2_table))) {
cat(
sprintf(
"- **%s:** R² = %.3f → model giải thích khoảng **%.1f%%** variance.\n",
r2_table$Construct[i],
r2_table$`R^2`[i],
100 * r2_table$`R^2`[i]
)
)
}
cat(
"\nKhi viết luận văn, nên diễn giải các giá trị này theo bối cảnh nghiên cứu hành vi người tiêu dùng, không gắn nhãn 'tốt/xấu' một cách cơ học.\n"
)
}Khi viết luận văn, nên diễn giải các giá trị này theo bối cảnh nghiên cứu hành vi người tiêu dùng, không gắn nhãn ‘tốt/xấu’ một cách cơ học.
Một path có thể:
p < .001 nhưng f² vẫn nhỏ.
Ngưỡng heuristic:
f2_report <- f2_table
if ("f2" %in% names(f2_report)) {
f2_report <- f2_report |>
mutate(
Effect_Size_Recomputed = interpret_f2(f2)
)
}
show_table(
f2_report,
caption = "f² effect sizes"
)| From | To | f2 | Effect_Size | Effect_Size_Recomputed |
|---|---|---|---|---|
| SQ | PEOU | 0.064 | Small | Small |
| PP | PEOU | 0.049 | Small | Small |
| TR | PEOU | 0.060 | Small | Small |
| SQ | PU | 0.052 | Small | Small |
| PP | PU | 0.038 | Small | Small |
| TR | PU | 0.032 | Small | Small |
| PEOU | PU | 0.111 | Small | Small |
| SQ | BT | 0.058 | Small | Small |
| PP | BT | 0.034 | Small | Small |
| TR | BT | 0.023 | Small | Small |
| PEOU | BT | 0.031 | Small | Small |
| PU | BT | 0.037 | Small | Small |
| PEOU | PI | 0.031 | Small | Small |
| PU | PI | 0.023 | Small | Small |
| BT | PI | 0.118 | Small | Small |
if ("f2" %in% names(f2_table) && nrow(f2_table) > 0) {
cat(
sprintf(
"f² nằm trong khoảng **%.3f–%.3f**.\n\n",
min(f2_table$f2, na.rm = TRUE),
max(f2_table$f2, na.rm = TRUE)
)
)
f2_counts <- tibble(
Muc = c("Negligible", "Small", "Medium", "Large"),
So_path = c(
sum(f2_table$f2 < 0.02, na.rm = TRUE),
sum(f2_table$f2 >= 0.02 & f2_table$f2 < 0.15, na.rm = TRUE),
sum(f2_table$f2 >= 0.15 & f2_table$f2 < 0.35, na.rm = TRUE),
sum(f2_table$f2 >= 0.35, na.rm = TRUE)
)
)
print(
knitr::kable(
f2_counts,
caption = "Phân loại f²"
)
)
}f² nằm trong khoảng 0.023–0.118.
| Muc | So_path |
|---|---|
| Negligible | 0 |
| Small | 15 |
| Medium | 0 |
| Large | 0 |
Với một positive hypothesis, cần xem:
Nếu CI không chứa 0 và p < 0.05, relationship có bằng chứng statistical significance ở mức 5%.
direct_report <- direct_results |>
mutate(
P_Reported = if ("Bootstrap_P" %in% names(direct_results)) {
format_p(Bootstrap_P)
} else NA_character_
)
show_table(
direct_report |>
select(
any_of(c(
"Hypothesis",
"From",
"To",
"Original_Est",
"T_Stat",
"P_Reported",
"CI_Lower",
"CI_Upper",
"Decision"
))
),
caption = "Kết quả H1–H15"
)| Hypothesis | From | To | Original_Est | T_Stat | P_Reported | CI_Lower | CI_Upper | Decision |
|---|---|---|---|---|---|---|---|---|
| H1 | SQ | PU | 0.202 | 5.170 | < .001 | 0.124 | 0.277 | Supported |
| H2 | SQ | PEOU | 0.237 | 5.861 | < .001 | 0.158 | 0.316 | Supported |
| H3 | SQ | BT | 0.215 | 5.543 | < .001 | 0.140 | 0.292 | Supported |
| H4 | PP | PU | 0.172 | 4.532 | < .001 | 0.098 | 0.247 | Supported |
| H5 | PP | PEOU | 0.207 | 5.303 | < .001 | 0.132 | 0.283 | Supported |
| H6 | PP | BT | 0.163 | 4.411 | < .001 | 0.092 | 0.236 | Supported |
| H7 | TR | PU | 0.154 | 4.094 | < .001 | 0.080 | 0.228 | Supported |
| H8 | TR | PEOU | 0.223 | 5.820 | < .001 | 0.147 | 0.298 | Supported |
| H9 | TR | BT | 0.132 | 3.548 | < .001 | 0.059 | 0.204 | Supported |
| H10 | PEOU | PU | 0.307 | 8.084 | < .001 | 0.231 | 0.380 | Supported |
| H11 | PU | BT | 0.191 | 4.141 | < .001 | 0.098 | 0.279 | Supported |
| H12 | PEOU | BT | 0.169 | 4.023 | < .001 | 0.086 | 0.251 | Supported |
| H13 | PU | PI | 0.154 | 3.562 | < .001 | 0.068 | 0.238 | Supported |
| H14 | PEOU | PI | 0.177 | 4.133 | < .001 | 0.092 | 0.260 | Supported |
| H15 | BT | PI | 0.337 | 8.367 | < .001 | 0.257 | 0.416 | Supported |
if (all(
c(
"Hypothesis",
"Original_Est",
"CI_Lower",
"CI_Upper"
) %in% names(direct_results)
)) {
plot_direct <- direct_results |>
mutate(
Label = if (
all(c("From", "To") %in% names(direct_results))
) {
paste0(Hypothesis, ": ", From, " → ", To)
} else {
Hypothesis
}
)
ggplot(
plot_direct,
aes(
x = reorder(Label, Original_Est),
y = Original_Est
)
) +
geom_point(size = 2.5) +
geom_errorbar(
aes(
ymin = CI_Lower,
ymax = CI_Upper
),
width = 0.15
) +
geom_hline(
yintercept = 0,
linetype = "dashed"
) +
coord_flip() +
labs(
title = "Direct Structural Effects",
subtitle = "β và 95% bootstrap CI",
x = NULL,
y = expression(beta)
) +
theme_minimal(base_size = 11)
}if (!is.na(n_direct_supported)) {
cat(
sprintf(
"**Có %d/%d direct hypotheses được hỗ trợ.**\n\n",
n_direct_supported,
n_direct_total
)
)
}Có 15/15 direct hypotheses được hỗ trợ.
if (
all(c("Original_Est", "From", "To") %in% names(direct_results)) &&
nrow(direct_results) > 0
) {
strongest_direct <- direct_results |>
arrange(desc(abs(Original_Est))) |>
slice(1)
cat(
sprintf(
"Path có |β| lớn nhất là **%s → %s (β = %.3f)**. ",
strongest_direct$From,
strongest_direct$To,
strongest_direct$Original_Est
)
)
cat(
"Đây là direct standardized relationship lớn nhất trong model, nhưng vẫn cần đọc cùng f² và lý thuyết.\n"
)
}Path có |β| lớn nhất là BT → PI (β = 0.337). Đây là direct standardized relationship lớn nhất trong model, nhưng vẫn cần đọc cùng f² và lý thuyết.
Nếu output hiển thị:
Bootstrap_P = 0
thì trong luận văn viết:
p < .001
không viết:
p = .000
Mediation xem xét liệu X có ảnh hưởng đến Purchase Intention thông qua Brand Trust hay không:
\[ X \rightarrow BT \rightarrow PI \]
Specific indirect effect được xem là statistically significant nếu bootstrap confidence interval không chứa 0.
Các giả thuyết:
mediation_report <- mediation_results |>
mutate(
P_Reported = if ("Bootstrap_P" %in% names(mediation_results)) {
format_p(Bootstrap_P)
} else NA_character_
)
show_table(
mediation_report |>
select(
any_of(c(
"Hypothesis",
"From",
"Through",
"To",
"Original_Est",
"T_Stat",
"P_Reported",
"CI_Lower",
"CI_Upper",
"Decision",
"Mediation_Interpretation"
))
),
caption = "Specific indirect effects qua Brand Trust"
)| Hypothesis | From | Through | To | Original_Est | T_Stat | P_Reported | CI_Lower | CI_Upper | Decision | Mediation_Interpretation |
|---|---|---|---|---|---|---|---|---|---|---|
| H16 | SQ | BT | PI | 0.073 | 4.530 | < .001 | 0.044 | 0.106 | Supported | Significant specific indirect effect; direct X->PI path not specified in canonical model |
| H17 | PP | BT | PI | 0.055 | 3.963 | < .001 | 0.030 | 0.084 | Supported | Significant specific indirect effect; direct X->PI path not specified in canonical model |
| H18 | TR | BT | PI | 0.044 | 3.158 | < .001 | 0.019 | 0.073 | Supported | Significant specific indirect effect; direct X->PI path not specified in canonical model |
| H19 | PU | BT | PI | 0.064 | 3.558 | < .001 | 0.031 | 0.102 | Supported | Complementary mediation |
| H20 | PEOU | BT | PI | 0.057 | 3.687 | < .001 | 0.028 | 0.089 | Supported | Complementary mediation |
if (all(
c(
"Hypothesis",
"Original_Est",
"CI_Lower",
"CI_Upper"
) %in% names(mediation_results)
)) {
plot_med <- mediation_results |>
mutate(
Label = if (
all(c("From", "Through", "To") %in% names(mediation_results))
) {
paste0(
Hypothesis,
": ",
From,
" → ",
Through,
" → ",
To
)
} else {
Hypothesis
}
)
ggplot(
plot_med,
aes(
x = reorder(Label, Original_Est),
y = Original_Est
)
) +
geom_point(size = 2.5) +
geom_errorbar(
aes(
ymin = CI_Lower,
ymax = CI_Upper
),
width = 0.15
) +
geom_hline(
yintercept = 0,
linetype = "dashed"
) +
coord_flip() +
labs(
title = "Specific Indirect Effects qua Brand Trust",
subtitle = "Indirect effect và 95% bootstrap CI",
x = NULL,
y = "Specific indirect effect"
) +
theme_minimal(base_size = 11)
}if (!is.na(n_med_supported)) {
cat(
sprintf(
"**Có %d/%d mediation hypotheses được hỗ trợ.**\n\n",
n_med_supported,
n_med_total
)
)
}Có 5/5 mediation hypotheses được hỗ trợ.
if (
all(c("From", "Mediation_Interpretation") %in% names(mediation_results)) &&
nrow(mediation_results) > 0
) {
print(
knitr::kable(
mediation_results |>
select(
any_of(c(
"Hypothesis",
"From",
"Through",
"To",
"Mediation_Interpretation"
))
),
caption = "Phân loại mediation"
)
)
}| Hypothesis | From | Through | To | Mediation_Interpretation |
|---|---|---|---|---|
| H16 | SQ | BT | PI | Significant specific indirect effect; direct X->PI path not specified in canonical model |
| H17 | PP | BT | PI | Significant specific indirect effect; direct X->PI path not specified in canonical model |
| H18 | TR | BT | PI | Significant specific indirect effect; direct X->PI path not specified in canonical model |
| H19 | PU | BT | PI | Complementary mediation |
| H20 | PEOU | BT | PI | Complementary mediation |
Nếu canonical model không estimate:
thì không nên tự động gọi H16–H18 là:
Kết luận chính xác hơn là:
Specific indirect effect through Brand Trust is significant.
Với H19 và H20, vì model có direct paths PU → PI và PEOU → PI, có thể phân loại mediation dựa trên direct và indirect effects.
Ngoài 5 mediation hypotheses chính, model còn tạo ra các chuỗi gián tiếp dài hơn, ví dụ:
\[ SQ \rightarrow PEOU \rightarrow PU \rightarrow BT \rightarrow PI \]
| From | Through | To | Effect | Original_Est | Bootstrap_Mean | Bootstrap_SD | T_Stat | CI_Lower | CI_Upper | Bootstrap_P | Significant |
|---|---|---|---|---|---|---|---|---|---|---|---|
| SQ | PU | PI | SQ->PU->PI | 0.031 | 0.031 | 0.011 | 2.938 | 0.012 | 0.054 | 0.001 | TRUE |
| SQ | PEOU | PI | SQ->PEOU->PI | 0.042 | 0.042 | 0.013 | 3.317 | 0.020 | 0.069 | 0.000 | TRUE |
| SQ | PU -> BT | PI | SQ->PU->BT->PI | 0.013 | 0.013 | 0.005 | 2.889 | 0.005 | 0.023 | 0.000 | TRUE |
| SQ | PEOU -> BT | PI | SQ->PEOU->BT->PI | 0.013 | 0.014 | 0.004 | 3.018 | 0.006 | 0.024 | 0.000 | TRUE |
| SQ | PEOU -> PU | PI | SQ->PEOU->PU->PI | 0.011 | 0.011 | 0.004 | 2.782 | 0.004 | 0.020 | 0.001 | TRUE |
| SQ | PEOU -> PU -> BT | PI | SQ->PEOU->PU->BT->PI | 0.005 | 0.005 | 0.002 | 2.849 | 0.002 | 0.008 | 0.000 | TRUE |
| PP | PU | PI | PP->PU->PI | 0.026 | 0.026 | 0.009 | 2.879 | 0.010 | 0.046 | 0.001 | TRUE |
| PP | PEOU | PI | PP->PEOU->PI | 0.037 | 0.037 | 0.011 | 3.361 | 0.017 | 0.060 | 0.000 | TRUE |
| PP | PU -> BT | PI | PP->PU->BT->PI | 0.011 | 0.011 | 0.004 | 2.712 | 0.004 | 0.020 | 0.000 | TRUE |
| PP | PEOU -> BT | PI | PP->PEOU->BT->PI | 0.012 | 0.012 | 0.004 | 3.016 | 0.005 | 0.020 | 0.000 | TRUE |
| PP | PEOU -> PU | PI | PP->PEOU->PU->PI | 0.010 | 0.010 | 0.004 | 2.600 | 0.004 | 0.018 | 0.001 | TRUE |
| PP | PEOU -> PU -> BT | PI | PP->PEOU->PU->BT->PI | 0.004 | 0.004 | 0.002 | 2.728 | 0.002 | 0.007 | 0.000 | TRUE |
| TR | PU | PI | TR->PU->PI | 0.024 | 0.024 | 0.009 | 2.632 | 0.008 | 0.043 | 0.001 | TRUE |
| TR | PEOU | PI | TR->PEOU->PI | 0.039 | 0.040 | 0.012 | 3.228 | 0.018 | 0.066 | 0.000 | TRUE |
| TR | PU -> BT | PI | TR->PU->BT->PI | 0.010 | 0.010 | 0.004 | 2.570 | 0.004 | 0.019 | 0.000 | TRUE |
| TR | PEOU -> BT | PI | TR->PEOU->BT->PI | 0.013 | 0.013 | 0.004 | 3.074 | 0.006 | 0.022 | 0.000 | TRUE |
| TR | PEOU -> PU | PI | TR->PEOU->PU->PI | 0.011 | 0.011 | 0.004 | 2.811 | 0.004 | 0.019 | 0.001 | TRUE |
| TR | PEOU -> PU -> BT | PI | TR->PEOU->PU->BT->PI | 0.004 | 0.004 | 0.002 | 2.862 | 0.002 | 0.008 | 0.000 | TRUE |
| PEOU | PU | PI | PEOU->PU->PI | 0.047 | 0.047 | 0.015 | 3.197 | 0.020 | 0.078 | 0.001 | TRUE |
| PEOU | PU -> BT | PI | PEOU->PU->BT->PI | 0.020 | 0.020 | 0.006 | 3.332 | 0.009 | 0.033 | 0.000 | TRUE |
Các paths này nên được xem là:
trừ khi chúng đã được đặt giả thuyết từ trước.
Không nên nhìn thấy significant rồi mới biến chúng thành hypotheses chính.
R² là in-sample explanatory power.
PLSpredict hỏi một câu khác:
Model dự báo các observations chưa được dùng để estimate training fold tốt đến đâu?
Vì vậy không được kết luận model có predictive power chỉ vì:
| Row | PU1 | PU2 | PU3 | PU4 | PEOU1 | PEOU2 | PEOU3 | PEOU4 | BT1 | BT2 | BT3 | BT4 | PI1 | PI2 | PI3 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| RMSE | 1.058 | 1.108 | 1.088 | 1.072 | 1.165 | 1.181 | 1.152 | 1.164 | 1.114 | 1.069 | 1.048 | 1.096 | 1.152 | 1.097 | 1.169 |
| MAE | 0.883 | 0.934 | 0.894 | 0.881 | 0.982 | 0.993 | 0.951 | 0.962 | 0.926 | 0.866 | 0.866 | 0.899 | 0.945 | 0.916 | 0.984 |
| Row | PU1 | PU2 | PU3 | PU4 | PEOU1 | PEOU2 | PEOU3 | PEOU4 | BT1 | BT2 | BT3 | BT4 | PI1 | PI2 | PI3 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| RMSE | 1.081 | 1.123 | 1.106 | 1.091 | 1.167 | 1.200 | 1.165 | 1.172 | 1.120 | 1.069 | 1.056 | 1.101 | 1.167 | 1.112 | 1.183 |
| MAE | 0.895 | 0.944 | 0.902 | 0.895 | 0.988 | 0.997 | 0.963 | 0.969 | 0.936 | 0.863 | 0.867 | 0.902 | 0.957 | 0.923 | 0.998 |
| Row | PU | PEOU | BT | PI |
|---|---|---|---|---|
| IS_MSE | 0.662 | 0.782 | 0.646 | 0.706 |
| IS_MAE | 0.672 | 0.731 | 0.650 | 0.696 |
| OOS_MSE | 0.671 | 0.796 | 0.661 | 0.714 |
| OOS_MAE | 0.677 | 0.737 | 0.658 | 0.700 |
| overfit | 0.014 | 0.018 | 0.023 | 0.011 |
Với cùng một error metric:
Nếu PLS có RMSE/MAE thấp hơn benchmark ở phần lớn indicators quan trọng, điều đó hỗ trợ predictive performance.
PLSpredict cho phép so sánh prediction error.
CVPAT đi thêm một bước: kiểm định xem chênh lệch predictive loss giữa PLS và benchmark có đủ lớn về mặt thống kê hay không.
| Row | PLS Loss | LM Loss | Diff | Boot T value | Boot P Value |
|---|---|---|---|---|---|
| PU | 1.170 | 1.211 | -0.041 | 3.095 | 0.001 |
| PEOU | 1.358 | 1.383 | -0.025 | 2.099 | 0.018 |
| BT | 1.171 | 1.181 | -0.010 | 0.620 | 0.268 |
| PI | 1.299 | 1.333 | -0.034 | 3.132 | 0.001 |
| Overall | 1.250 | 1.277 | -0.027 | 4.170 | 0.000 |
| Row | PLS Loss | IA Loss | Diff | Boot T value | Boot P Value |
|---|---|---|---|---|---|
| PU | 1.170 | 1.520 | -0.350 | 7.587 | 0 |
| PEOU | 1.358 | 1.570 | -0.212 | 5.474 | 0 |
| BT | 1.171 | 1.532 | -0.361 | 7.648 | 0 |
| PI | 1.299 | 1.626 | -0.327 | 6.947 | 0 |
| Overall | 1.250 | 1.562 | -0.313 | 9.984 | 0 |
Trong output của pipeline hiện tại:
Cần đọc riêng:
Model có thể outperform benchmark ở overall level nhưng một construct riêng lẻ vẫn không significant.
summary_table <- tibble(
Buoc = c(
"1. Data quality",
"2. Indicator reliability",
"3. Internal consistency",
"4. Convergent validity",
"5. Discriminant validity",
"6. Structural collinearity",
"7. Explanatory power",
"8. Effect size",
"9. Direct hypotheses",
"10. Mediation",
"11. Prediction"
),
Chi_so_chinh = c(
"Missing, duplicate, range, SPSS–PLS tie-out",
"Outer loadings",
"Cronbach's alpha, rho_A, rho_C",
"AVE",
"HTMT + bootstrapped HTMT",
"Structural VIF",
"R², Adjusted R²",
"f²",
"β, t, p, bootstrap CI",
"Specific indirect effect, bootstrap CI",
"PLSpredict + CVPAT"
),
Cau_hoi = c(
"Data có sạch và nhất quán không?",
"Indicators có phản ánh construct tốt không?",
"Construct có reliability tốt không?",
"Construct có convergent validity không?",
"Các constructs có phân biệt nhau không?",
"Predictors có bị collinearity không?",
"Model giải thích được bao nhiêu variance?",
"Từng predictor đóng góp lớn tới đâu?",
"H1–H15 có được hỗ trợ không?",
"Brand Trust có vai trò trung gian không?",
"Model dự báo out-of-sample tốt không?"
)
)
show_table(
summary_table,
caption = "Trình tự đánh giá PLS-SEM"
)| Buoc | Chi_so_chinh | Cau_hoi |
|---|---|---|
| 1. Data quality | Missing, duplicate, range, SPSS–PLS tie-out | Data có sạch và nhất quán không? |
| 2. Indicator reliability | Outer loadings | Indicators có phản ánh construct tốt không? |
| 3. Internal consistency | Cronbach’s alpha, rho_A, rho_C | Construct có reliability tốt không? |
| 4. Convergent validity | AVE | Construct có convergent validity không? |
| 5. Discriminant validity | HTMT + bootstrapped HTMT | Các constructs có phân biệt nhau không? |
| 6. Structural collinearity | Structural VIF | Predictors có bị collinearity không? |
| 7. Explanatory power | R², Adjusted R² | Model giải thích được bao nhiêu variance? |
| 8. Effect size | f² | Từng predictor đóng góp lớn tới đâu? |
| 9. Direct hypotheses | β, t, p, bootstrap CI | H1–H15 có được hỗ trợ không? |
| 10. Mediation | Specific indirect effect, bootstrap CI | Brand Trust có vai trò trung gian không? |
| 11. Prediction | PLSpredict + CVPAT | Model dự báo out-of-sample tốt không? |
Thứ tự nên viết:
Không cần đọc lại toàn bộ số trong bảng bằng prose.
Ví dụ, thay vì viết 28 loading một lần nữa, chỉ cần:
Outer loadings ranged from X to Y, and all indicators exceeded the recommended reference value of 0.708.
Sau đó bảng sẽ chứa chi tiết.
Thứ tự:
Không nên viết:
“Path này rất mạnh vì p < .001.”
p-value không cho biết magnitude của effect.
Mỗi hypothesis nên báo cáo:
Cấu trúc câu:
Brand Trust significantly mediated the relationship between X and Purchase Intention (indirect effect = …, t = …, p < …, 95% CI […, …]). Therefore, Hxx was supported.
Prediction nên nằm sau structural model và mediation:
Không được dùng R² thay thế cho predictive assessment.
## Workbook kết quả: D:\Research\ai_home_appliance\data_analysis\ai_appliance_rpubs\R_results\02_pls_sem_results.xlsx
## R version: R version 4.6.1 (2026-06-24 ucrt)
## Thời điểm tạo report: 2026-08-26 14:06:35
## R version 4.6.1 (2026-06-24 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 11 x64 (build 26200)
##
## Matrix products: default
## LAPACK version 3.12.1
##
## locale:
## [1] LC_COLLATE=English_United Kingdom.utf8
## [2] LC_CTYPE=English_United Kingdom.utf8
## [3] LC_MONETARY=English_United Kingdom.utf8
## [4] LC_NUMERIC=C
## [5] LC_TIME=English_United Kingdom.utf8
##
## time zone: Asia/Bangkok
## tzcode source: internal
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] tibble_3.3.1 scales_1.4.0 stringr_1.6.0 knitr_1.51 ggplot2_4.0.3
## [6] tidyr_1.3.2 dplyr_1.2.1 readxl_1.5.0
##
## loaded via a namespace (and not attached):
## [1] gtable_0.3.6 jsonlite_2.0.0 compiler_4.6.1 tidyselect_1.2.1
## [5] jquerylib_0.1.4 yaml_2.3.12 fastmap_1.2.0 R6_2.6.1
## [9] labeling_0.4.3 generics_0.1.4 bslib_0.11.0 pillar_1.11.1
## [13] RColorBrewer_1.1-3 rlang_1.2.0 stringi_1.8.7 cachem_1.1.0
## [17] xfun_0.59 sass_0.4.10 S7_0.2.2 otel_0.2.0
## [21] cli_3.6.6 withr_3.0.3 magrittr_2.0.5 digest_0.6.39
## [25] grid_4.6.1 rstudioapi_0.19.0 lifecycle_1.0.5 vctrs_0.7.3
## [29] evaluate_1.0.5 glue_1.8.1 farver_2.1.2 cellranger_1.1.0
## [33] rmarkdown_2.31 purrr_1.2.2 tools_4.6.1 pkgconfig_2.0.3
## [37] htmltools_0.5.9