Cách dùng file này: 1. Mở trong RStudio — chạy từng chunk bằng nút ▶ bên phải mỗi khối code. 2. Đọc phần giải thích trước khi chạy, đọc phần Đọc kết quả sau khi chạy. 3. Điền số thật vào các ô
___trong phần Ghi nhận kết quả. 4. Bấm Knit → Knit to HTML để xuất toàn bộ báo cáo.
Gói (package) trong R giống như ứng dụng trên điện
thoại — R chỉ có tính năng cơ bản sẵn, mọi phân tích nâng cao
đều cần cài thêm. Bạn chỉ cài một lần (install.packages),
nhưng phải nạp mỗi phiên (library).
# --- Cài gói (chỉ làm 1 lần, xong thì để dấu # trước mỗi dòng) --------------
# install.packages(c("tidyverse","readxl","psych","GPArotation",
# "lavaan","semTools","car","corrplot","modelsummary"))
# --- Nạp gói (làm MỖI LẦN mở RStudio) ---------------------------------------
library(tidyverse) # xử lý dữ liệu + ggplot2
library(readxl) # đọc file Excel
library(psych) # mô tả, Cronbach's alpha, EFA
library(GPArotation) # thuật toán xoay nhân tố cho EFA
library(lavaan) # CFA + SEM
library(semTools) # CR, AVE, bổ trợ lavaan
library(car) # VIF, kiểm định hồi quy
library(corrplot) # vẽ ma trận tương quan
library(modelsummary) # xuất bảng hồi quyKiểm tra: Sau khi chạy chunk trên, bạn thấy dòng chữ trong Console nhưng không có chữ
Error→ thành công.
R cần biết file nằm ở đâu trên máy. Nếu dùng R
Project (khuyến nghị), thư mục tự động là thư mục chứa file
.Rproj — không cần setwd(). Nếu chưa dùng
Project, hãy chạy dòng setwd() ở dưới.
# Nếu CHƯA dùng R Project, bỏ dấu # và sửa đường dẫn:
# setwd("D:/Research/draft/dataset_r")
# Đọc file Excel, lấy sheet "responses"
df_raw <- read_excel("AI_appliance_survey_DATA.xlsx",
sheet = "responses")
# Xem nhanh cấu trúc
dim(df_raw) # số hàng × số cột[1] 382 41
[1] "Timestamp" "Consent" "Age18" "BuyerRole" "HeardOf" "UsageExp"
[7] "Devices" "SQ1" "SQ2" "SQ3" "SQ4" "SQ5"
[13] "PP1" "PP2" "PP3" "PP4" "PP5" "TR1"
[19] "TR2" "TR3" "PU1" "PU2" "PU3" "PU4"
[25] "PEOU1" "PEOU2" "PEOU3" "PEOU4" "BT1" "BT2"
[31] "BT3" "BT4" "BI1" "BI2" "BI3" "Gender"
[37] "City" "Age" "Education" "Job" "Income"
⚠️ Khi có dữ liệu thật từ Google Forms: Google Forms xuất tiêu đề câu hỏi làm tên cột — rất dài. Bước đầu tiên là đổi về mã ngắn:
# Định nghĩa nhóm item — dùng lại ở mọi bước phía sau
SQ_i <- paste0("SQ", 1:5) # AI System Quality
PP_i <- paste0("PP", 1:5) # Perceived Personalization
TR_i <- paste0("TR", 1:3) # AI Transparency
PU_i <- paste0("PU", 1:4) # Perceived Usefulness
PEOU_i <- paste0("PEOU", 1:4) # Perceived Ease of Use
BT_i <- paste0("BT", 1:4) # Brand Trust (biến trung gian)
BI_i <- paste0("BI", 1:3) # Behavioral Intention (biến phụ thuộc)
items <- c(SQ_i, PP_i, TR_i, PU_i, PEOU_i, BT_i, BI_i) # tất cả 28 itemDữ liệu khảo sát giống rau vừa mới hái — phải nhặt sạch trước khi nấu. Với Google Forms, “sạn” lớn nhất không phải giá trị lỗi (Forms đã ép chọn 1–5), mà là người không đủ điều kiện vẫn lọt vào, và người trả lời cẩu thả.
Có 4 việc cần làm theo thứ tự:
| Bước | Việc làm | Vì sao |
|---|---|---|
| 1 | Lọc sàng lọc | Giữ đúng đối tượng nghiên cứu |
| 2 | Xóa Likert trống | Người bị rẽ nhánh kết thúc sớm |
| 3 | Xóa trùng lặp | 1 người bấm gửi 2 lần |
| 4 | Xóa straight-liner | Trả lời tất cả 1 giá trị, nghi cẩu thả |
# Bước 1 + 2: Lọc người hợp lệ
df_q <- df_raw %>%
filter(
Consent == "Tôi đồng ý và tự nguyện tham gia khảo sát",
Age18 == "Có",
HeardOf == "Có",
UsageExp != "Tôi chưa từng nghe đến",
BuyerRole != "Không tham gia vào việc quyết định mua"
) %>%
drop_na(all_of(items)) # bỏ hàng còn Likert trống
cat("Sau lọc sàng lọc:", nrow(df_q), "người\n")Sau lọc sàng lọc: 350 người
# Bước 3: Xóa trùng lặp
truoc_dedup <- nrow(df_q)
df_q <- df_q[!duplicated(df_q[items]), ]
cat("Đã xóa", truoc_dedup - nrow(df_q), "dòng trùng lặp\n")Đã xóa 1 dòng trùng lặp
# Bước 4: Xóa straight-liner (SD hàng < 0.30)
row_sd <- apply(df_q[items], 1, sd)
truoc_sl <- nrow(df_q)
df_q <- df_q[row_sd > 0.30, ]
cat("Đã xóa", truoc_sl - nrow(df_q), "người straight-line\n")Đã xóa 2 người straight-line
✅ Cỡ mẫu cuối (df_clean): 347 người
# Lưu dữ liệu sạch để các bước sau dùng lại (không cần chạy lại từ đầu)
# saveRDS(df_clean, "data/processed/df_clean.rds")
# df_clean <- readRDS("data/processed/df_clean.rds") # đọc lại ở session khác📝 Ghi nhận kết quả:
- Tổng dữ liệu thô: ___ hàng
- Sau lọc sàng lọc: ___ người
- Sau xóa trùng + straight-liner: ___ người (= N cuối cùng)
⚠️ Lưu ý: Form của bạn KHÔNG có câu hỏi ngược (reverse item) — mọi phát biểu đều cùng chiều dương → không cần bước
6 - x.
Trước khi “khám bệnh” cho mô hình, hãy “đo thân nhiệt” dữ liệu. Thống kê mô tả cho bạn biết: mẫu của tôi trông như thế nào? Đây là nội dung đầu tiên của Chương 4 trong bài luận.
=== GIỚI TÍNH ===
Khác Nam Nữ
0.6 48.1 51.3
=== NHÓM TUỔI ===
Từ 18 - dưới 25 tuổi Từ 25 - dưới 35 tuổi Từ 35 - dưới 45 tuổi
45.8 30.0 11.8
Từ 45 - dưới 55 tuổi Từ 55 tuổi trở lên
7.2 5.2
=== HỌC VẤN ===
Cao đẳng Đại học Sau đại học Trung học phổ thông
23.6 51.3 8.9 16.1
=== NGHỀ NGHIỆP ===
Chuyên viên (bác sĩ, giáo viên, kỹ sư…) Học sinh / Sinh viên
17.6 34.9
Kinh doanh / tự kinh doanh Lao động tự do
11.2 5.5
Nhân viên văn phòng Nội trợ
28.0 2.9
=== THU NHẬP ===
Dưới 10 triệu VNĐ Không muốn trả lời Trên 60 triệu VNĐ
17.0 8.6 4.0
Từ 10 – dưới 20 triệu VNĐ Từ 20 – dưới 30 triệu VNĐ Từ 30 – dưới 40 triệu VNĐ
33.7 21.6 9.5
Từ 40 – dưới 60 triệu VNĐ
5.5
# --- Mô tả từng item (mean, sd, skew, kurtosis) ---
desc <- describe(df_clean[items])
round(desc[, c("mean", "sd", "skew", "kurtosis", "min", "max")], 2) mean sd skew kurtosis min max
SQ1 3.41 0.87 0.01 -0.47 1 5
SQ2 3.40 0.85 -0.06 -0.41 1 5
SQ3 3.41 0.91 0.05 -0.53 1 5
SQ4 3.42 0.89 -0.30 -0.32 1 5
SQ5 3.38 0.89 -0.02 -0.38 1 5
PP1 3.37 0.90 -0.28 -0.16 1 5
PP2 3.41 0.91 -0.22 -0.11 1 5
PP3 3.41 0.87 -0.23 -0.11 1 5
PP4 3.39 0.88 -0.10 -0.26 1 5
PP5 3.41 0.86 -0.13 -0.25 1 5
TR1 3.39 0.88 -0.21 -0.18 1 5
TR2 3.38 0.88 -0.16 -0.26 1 5
TR3 3.40 0.90 -0.12 -0.37 1 5
PU1 3.41 0.88 -0.09 -0.31 1 5
PU2 3.39 0.88 -0.06 -0.35 1 5
PU3 3.39 0.89 -0.19 -0.44 1 5
PU4 3.39 0.87 0.02 -0.59 1 5
PEOU1 3.41 0.88 -0.02 -0.64 1 5
PEOU2 3.43 0.89 -0.22 -0.18 1 5
PEOU3 3.40 0.87 -0.01 -0.48 1 5
PEOU4 3.40 0.88 -0.11 -0.22 1 5
BT1 3.41 0.88 0.06 -0.61 1 5
BT2 3.42 0.87 0.02 -0.36 1 5
BT3 3.41 0.88 -0.18 0.01 1 5
BT4 3.42 0.86 -0.05 -0.20 1 5
BI1 3.39 0.87 -0.01 -0.28 1 5
BI2 3.39 0.89 -0.15 -0.23 1 5
BI3 3.44 0.88 -0.04 -0.50 1 5
| Chỉ số | Ý nghĩa | Ngưỡng chú ý |
|---|---|---|
mean |
Mức đồng ý trung bình | Thang 1–5; > 3.5 = xu hướng đồng ý |
sd |
Mức phân tán ý kiến | SD lớn = ý kiến chia rẽ |
skew |
Độ lệch phân phối | Cần ❙skew❙ < 3 để dùng ML estimator |
kurtosis |
Độ nhọn phân phối | Cần ❙kurt❙ < 8 |
min / max |
Giá trị nhỏ/lớn nhất | Phải trong 1–5 |
# --- Tính điểm tổng hợp (mean composite) cho từng construct ---
# Dùng để chạy tương quan và hồi quy ở bước sau
df_clean <- df_clean %>% mutate(
SQ = rowMeans(across(all_of(SQ_i))),
PP = rowMeans(across(all_of(PP_i))),
TR = rowMeans(across(all_of(TR_i))),
PU = rowMeans(across(all_of(PU_i))),
PEOU = rowMeans(across(all_of(PEOU_i))),
BT = rowMeans(across(all_of(BT_i))),
BI = rowMeans(across(all_of(BI_i)))
)
constructs <- c("SQ","PP","TR","PU","PEOU","BT","BI")
round(describe(df_clean[constructs])[, c("mean","sd","min","max")], 2) mean sd min max
SQ 3.41 0.65 1.60 5
PP 3.40 0.69 1.00 5
TR 3.39 0.67 1.67 5
PU 3.40 0.70 1.50 5
PEOU 3.41 0.71 1.25 5
BT 3.42 0.71 1.50 5
BI 3.40 0.74 1.33 5
📝 Ghi nhận kết quả: (điền vào bảng trong bài)
Construct có mean cao nhất: ___ (M = ) Construct có SD lớn nhất: (SD = ) Item nào có skew hoặc kurtosis đáng lo?
4 item của Brand Trust giống 4 nhân chứng cùng kể một sự việc. Nếu họ kể khớp nhau → thang đo đáng tin (alpha cao). Một người kể ngược hoặc lan man (item kém) → alpha giảm → cân nhắc loại.
Alpha đo lường: tính nhất quán nội tại (internal consistency).
| Mức alpha | Đánh giá |
|---|---|
| ≥ 0.90 | Xuất sắc (coi chừng item trùng ý) |
| 0.80 – 0.89 | Tốt |
| 0.70 – 0.79 | Chấp nhận được |
| < 0.70 | Cần xem xét lại thang đo |
Hai cột cần chú ý thêm:
r.drop (corrected item-total correlation): item “ăn
khớp” thang đo cỡ nào. Nếu r.drop < 0.30 → item yếu →
cân nhắc loại.alpha if dropped: alpha sẽ là bao nhiêu nếu bỏ item đó.
Nếu con số này lớn hơn alpha hiện tại → nên bỏ item
đó.=== SQ: AI System Quality (5 items) ===
Reliability analysis
Call: psych::alpha(x = df_clean[SQ_i])
raw_alpha std.alpha G6(smc) average_r S/N ase mean sd median_r
0.78 0.78 0.75 0.42 3.6 0.018 3.4 0.65 0.42
95% confidence boundaries
lower alpha upper
Feldt 0.75 0.78 0.82
Duhachek 0.75 0.78 0.82
Reliability if an item is dropped:
raw_alpha std.alpha G6(smc) average_r S/N alpha se var.r med.r
SQ1 0.77 0.77 0.72 0.46 3.4 0.020 0.0023 0.45
SQ2 0.72 0.72 0.67 0.39 2.6 0.025 0.0055 0.41
SQ3 0.72 0.72 0.67 0.40 2.6 0.024 0.0067 0.42
SQ4 0.74 0.74 0.69 0.42 2.9 0.023 0.0046 0.42
SQ5 0.76 0.76 0.71 0.44 3.2 0.021 0.0065 0.46
Item statistics
n raw.r std.r r.cor r.drop mean sd
SQ1 347 0.67 0.67 0.54 0.47 3.4 0.87
SQ2 347 0.78 0.78 0.72 0.64 3.4 0.85
SQ3 347 0.78 0.78 0.70 0.62 3.4 0.91
SQ4 347 0.74 0.74 0.65 0.57 3.4 0.89
SQ5 347 0.70 0.70 0.57 0.51 3.4 0.89
Non missing response frequency for each item
1 2 3 4 5 miss
SQ1 0.01 0.13 0.41 0.35 0.11 0
SQ2 0.01 0.13 0.40 0.37 0.09 0
SQ3 0.01 0.14 0.41 0.31 0.13 0
SQ4 0.01 0.14 0.34 0.42 0.09 0
SQ5 0.01 0.14 0.41 0.33 0.11 0
=== PP: Perceived Personalization (5 items) ===
Reliability analysis
Call: psych::alpha(x = df_clean[PP_i])
raw_alpha std.alpha G6(smc) average_r S/N ase mean sd median_r
0.84 0.84 0.81 0.51 5.3 0.014 3.4 0.69 0.52
95% confidence boundaries
lower alpha upper
Feldt 0.81 0.84 0.87
Duhachek 0.81 0.84 0.87
Reliability if an item is dropped:
raw_alpha std.alpha G6(smc) average_r S/N alpha se var.r med.r
PP1 0.81 0.81 0.76 0.51 4.1 0.017 0.0024 0.52
PP2 0.80 0.80 0.76 0.50 4.1 0.017 0.0022 0.50
PP3 0.79 0.79 0.74 0.49 3.8 0.018 0.0014 0.48
PP4 0.82 0.82 0.77 0.53 4.4 0.016 0.0015 0.53
PP5 0.82 0.82 0.78 0.53 4.6 0.016 0.0011 0.54
Item statistics
n raw.r std.r r.cor r.drop mean sd
PP1 347 0.79 0.79 0.71 0.65 3.4 0.90
PP2 347 0.80 0.79 0.72 0.66 3.4 0.91
PP3 347 0.82 0.82 0.76 0.70 3.4 0.87
PP4 347 0.76 0.76 0.67 0.61 3.4 0.88
PP5 347 0.74 0.75 0.65 0.59 3.4 0.86
Non missing response frequency for each item
1 2 3 4 5 miss
PP1 0.02 0.13 0.38 0.38 0.09 0
PP2 0.02 0.11 0.40 0.35 0.11 0
PP3 0.02 0.12 0.39 0.38 0.09 0
PP4 0.01 0.13 0.41 0.35 0.10 0
PP5 0.01 0.12 0.40 0.37 0.09 0
=== TR: AI Transparency (3 items) ===
Reliability analysis
Call: psych::alpha(x = df_clean[TR_i])
raw_alpha std.alpha G6(smc) average_r S/N ase mean sd median_r
0.62 0.62 0.55 0.35 1.6 0.035 3.4 0.67 0.27
95% confidence boundaries
lower alpha upper
Feldt 0.55 0.62 0.69
Duhachek 0.55 0.62 0.69
Reliability if an item is dropped:
raw_alpha std.alpha G6(smc) average_r S/N alpha se var.r med.r
TR1 0.70 0.70 0.54 0.54 2.36 0.032 NA 0.54
TR2 0.43 0.43 0.27 0.27 0.75 0.061 NA 0.27
TR3 0.40 0.40 0.25 0.25 0.65 0.065 NA 0.25
Item statistics
n raw.r std.r r.cor r.drop mean sd
TR1 347 0.67 0.67 0.36 0.30 3.4 0.88
TR2 347 0.79 0.79 0.65 0.50 3.4 0.88
TR3 347 0.81 0.80 0.67 0.52 3.4 0.90
Non missing response frequency for each item
1 2 3 4 5 miss
TR1 0.02 0.13 0.39 0.37 0.09 0
TR2 0.01 0.13 0.40 0.37 0.09 0
TR3 0.01 0.14 0.39 0.35 0.11 0
# Chú ý TR1: "Tôi MONG MUỐN...minh bạch" — đo kỳ vọng, không đo cảm nhận
# → r.drop của TR1 có thể thấp=== PU: Perceived Usefulness (4 items) ===
Reliability analysis
Call: psych::alpha(x = df_clean[PU_i])
raw_alpha std.alpha G6(smc) average_r S/N ase mean sd median_r
0.8 0.8 0.76 0.51 4.1 0.017 3.4 0.7 0.51
95% confidence boundaries
lower alpha upper
Feldt 0.77 0.8 0.84
Duhachek 0.77 0.8 0.84
Reliability if an item is dropped:
raw_alpha std.alpha G6(smc) average_r S/N alpha se var.r med.r
PU1 0.73 0.73 0.65 0.48 2.7 0.025 0.00084 0.48
PU2 0.77 0.77 0.69 0.52 3.3 0.022 0.00206 0.53
PU3 0.77 0.77 0.69 0.53 3.4 0.021 0.00117 0.51
PU4 0.75 0.75 0.67 0.50 3.0 0.024 0.00173 0.51
Item statistics
n raw.r std.r r.cor r.drop mean sd
PU1 347 0.82 0.82 0.74 0.66 3.4 0.88
PU2 347 0.78 0.78 0.66 0.59 3.4 0.88
PU3 347 0.78 0.77 0.65 0.59 3.4 0.89
PU4 347 0.80 0.80 0.71 0.63 3.4 0.87
Non missing response frequency for each item
1 2 3 4 5 miss
PU1 0.01 0.13 0.41 0.35 0.10 0
PU2 0.01 0.13 0.41 0.34 0.10 0
PU3 0.01 0.15 0.36 0.39 0.09 0
PU4 0.00 0.15 0.39 0.35 0.10 0
=== PEOU: Perceived Ease of Use (4 items) ===
Reliability analysis
Call: psych::alpha(x = df_clean[PEOU_i])
raw_alpha std.alpha G6(smc) average_r S/N ase mean sd median_r
0.83 0.83 0.79 0.55 4.8 0.015 3.4 0.71 0.55
95% confidence boundaries
lower alpha upper
Feldt 0.8 0.83 0.86
Duhachek 0.8 0.83 0.86
Reliability if an item is dropped:
raw_alpha std.alpha G6(smc) average_r S/N alpha se var.r med.r
PEOU1 0.78 0.78 0.70 0.54 3.6 0.020 0.00038 0.54
PEOU2 0.77 0.77 0.69 0.52 3.3 0.022 0.00180 0.53
PEOU3 0.78 0.78 0.70 0.54 3.5 0.021 0.00348 0.54
PEOU4 0.80 0.80 0.73 0.58 4.1 0.018 0.00038 0.57
Item statistics
n raw.r std.r r.cor r.drop mean sd
PEOU1 347 0.81 0.81 0.73 0.66 3.4 0.88
PEOU2 347 0.83 0.83 0.76 0.69 3.4 0.89
PEOU3 347 0.82 0.82 0.73 0.66 3.4 0.87
PEOU4 347 0.78 0.78 0.67 0.61 3.4 0.88
Non missing response frequency for each item
1 2 3 4 5 miss
PEOU1 0.00 0.15 0.37 0.37 0.1 0
PEOU2 0.02 0.12 0.38 0.38 0.1 0
PEOU3 0.01 0.14 0.40 0.35 0.1 0
PEOU4 0.01 0.12 0.41 0.35 0.1 0
=== BT: Brand Trust — TRUNG GIAN (4 items) ===
Reliability analysis
Call: psych::alpha(x = df_clean[BT_i])
raw_alpha std.alpha G6(smc) average_r S/N ase mean sd median_r
0.82 0.82 0.78 0.54 4.7 0.015 3.4 0.71 0.54
95% confidence boundaries
lower alpha upper
Feldt 0.79 0.82 0.85
Duhachek 0.79 0.82 0.85
Reliability if an item is dropped:
raw_alpha std.alpha G6(smc) average_r S/N alpha se var.r med.r
BT1 0.77 0.77 0.69 0.53 3.4 0.021 0.00026 0.53
BT2 0.77 0.77 0.69 0.53 3.4 0.021 0.00034 0.53
BT3 0.78 0.78 0.70 0.54 3.6 0.020 0.00038 0.53
BT4 0.79 0.79 0.71 0.55 3.7 0.020 0.00014 0.55
Item statistics
n raw.r std.r r.cor r.drop mean sd
BT1 347 0.82 0.82 0.73 0.66 3.4 0.88
BT2 347 0.82 0.82 0.73 0.66 3.4 0.87
BT3 347 0.81 0.80 0.71 0.64 3.4 0.88
BT4 347 0.79 0.80 0.69 0.63 3.4 0.86
Non missing response frequency for each item
1 2 3 4 5 miss
BT1 0.00 0.14 0.40 0.34 0.11 0
BT2 0.01 0.12 0.43 0.33 0.11 0
BT3 0.02 0.10 0.43 0.35 0.10 0
BT4 0.01 0.11 0.43 0.35 0.10 0
=== BI: Behavioral Intention — PHỤ THUỘC (3 items) ===
Reliability analysis
Call: psych::alpha(x = df_clean[BI_i])
raw_alpha std.alpha G6(smc) average_r S/N ase mean sd median_r
0.78 0.78 0.71 0.55 3.6 0.02 3.4 0.74 0.55
95% confidence boundaries
lower alpha upper
Feldt 0.74 0.78 0.82
Duhachek 0.74 0.78 0.82
Reliability if an item is dropped:
raw_alpha std.alpha G6(smc) average_r S/N alpha se var.r med.r
BI1 0.68 0.68 0.51 0.51 2.1 0.034 NA 0.51
BI2 0.71 0.71 0.55 0.55 2.4 0.031 NA 0.55
BI3 0.73 0.73 0.58 0.58 2.7 0.029 NA 0.58
Item statistics
n raw.r std.r r.cor r.drop mean sd
BI1 347 0.85 0.85 0.73 0.65 3.4 0.87
BI2 347 0.84 0.83 0.70 0.62 3.4 0.89
BI3 347 0.82 0.82 0.68 0.60 3.4 0.88
Non missing response frequency for each item
1 2 3 4 5 miss
BI1 0.01 0.12 0.43 0.33 0.10 0
BI2 0.02 0.13 0.40 0.35 0.10 0
BI3 0.01 0.13 0.39 0.36 0.11 0
# --- Bảng tổng hợp alpha cho cả 7 construct ---
get_alpha <- function(data, label) {
a <- psych::alpha(data)
data.frame(
Construct = label,
N_items = ncol(data),
Alpha = round(a$total$raw_alpha, 3),
Dat_yeu_cau = ifelse(a$total$raw_alpha >= 0.70, "✅ Đạt", "❌ Chưa đạt")
)
}
alpha_table <- bind_rows(
get_alpha(df_clean[SQ_i], "SQ – AI System Quality"),
get_alpha(df_clean[PP_i], "PP – Personalization"),
get_alpha(df_clean[TR_i], "TR – Transparency"),
get_alpha(df_clean[PU_i], "PU – Perceived Usefulness"),
get_alpha(df_clean[PEOU_i], "PEOU – Ease of Use"),
get_alpha(df_clean[BT_i], "BT – Brand Trust"),
get_alpha(df_clean[BI_i], "BI – Behavioral Intention")
)
knitr::kable(alpha_table, caption = "Bảng tổng hợp Cronbach's Alpha")| Construct | N_items | Alpha | Dat_yeu_cau |
|---|---|---|---|
| SQ – AI System Quality | 5 | 0.784 | ✅ Đạt |
| PP – Personalization | 5 | 0.840 | ✅ Đạt |
| TR – Transparency | 3 | 0.622 | ❌ Chưa đạt |
| PU – Perceived Usefulness | 4 | 0.804 | ✅ Đạt |
| PEOU – Ease of Use | 4 | 0.828 | ✅ Đạt |
| BT – Brand Trust | 4 | 0.824 | ✅ Đạt |
| BI – Behavioral Intention | 3 | 0.784 | ✅ Đạt |
Kết quả kiểm định độ tin cậy cho thấy tất cả các thang đo đều đạt yêu cầu, với hệ số Cronbach’s Alpha dao động từ ___ (___ items) đến ___ (___ items), đều vượt ngưỡng khuyến nghị 0.70 (Nunnally & Bernstein, 1994). Hệ số tương quan biến–tổng hiệu chỉnh của mọi biến quan sát đều lớn hơn 0.30.
EFA là bước “kiểm tra sức khỏe sơ bộ” của thang đo trước khi CFA xác nhận chính thức.
=== KIỂM TRA ĐIỀU KIỆN TIÊN QUYẾT ===
KMO Overall MSA = 0.915
cat("Đánh giá:", ifelse(kmo_result$MSA >= 0.80, "✅ Tốt (≥ 0.80)",
ifelse(kmo_result$MSA >= 0.70, "✅ Chấp nhận được (≥ 0.70)",
"❌ Chưa đạt (< 0.70)")), "\n\n")Đánh giá: ✅ Tốt (≥ 0.80)
# Bartlett's Test
bart <- cortest.bartlett(df_clean[items])
cat("Bartlett's Test: Chi-square =", round(bart$chisq, 1),
", p =", format(bart$p.value, scientific = TRUE), "\n")Bartlett's Test: Chi-square = 3852 , p = 0e+00
Đánh giá: ✅ Đạt (p < 0.05)
# --- Xác định số nhân tố bằng Parallel Analysis ---
# Parallel analysis so sánh eigenvalue thực với eigenvalue ngẫu nhiên
# → số nhân tố = số điểm TRÊN đường chấm (random data line)
fa.parallel(df_clean[items],
fa = "fa",
fm = "pa",
main = "Parallel Analysis — Xác định số nhân tố")Parallel analysis suggests that the number of factors = 6 and the number of components = NA
Cách đọc Scree Plot: Đếm số điểm nằm trên đường đứt (Simulated Data) → đó là số nhân tố nên dùng. Kỳ vọng cho bài này: 7 nhân tố (khớp 7 construct trong mô hình).
# --- Chạy EFA ---
# fm = "pa": Principal Axis (tốt cho dữ liệu không chuẩn)
# rotate = "promax": xoay xiên — phù hợp khi các construct CÓ tương quan với nhau
efa <- fa(df_clean[items],
nfactors = 7,
fm = "pa",
rotate = "promax")
# In bảng factor loadings (chỉ hiển thị loading >= 0.30)
print(efa$loadings, cutoff = 0.30, sort = TRUE)
Loadings:
PA2 PA5 PA4 PA3 PA1 PA6 PA7
PP1 0.748
PP2 0.758
PP3 0.740
PP4 0.599
PP5 0.661
BT1 0.670
BT2 0.678
BT3 0.676
BT4 0.804
PU1 0.792
PU2 0.707
PU3 0.615
PU4 0.737
PEOU1 0.681
PEOU2 0.770
PEOU3 0.697
PEOU4 0.720
SQ2 0.660
SQ3 0.725
SQ4 0.727
SQ5 0.560
BI1 0.710
BI2 0.751
BI3 0.683
TR2 0.639
TR3 0.701
SQ1 0.352
TR1 0.394
PA2 PA5 PA4 PA3 PA1 PA6 PA7
SS loadings 2.528 2.212 2.210 2.131 2.005 1.630 1.109
Proportion Var 0.090 0.079 0.079 0.076 0.072 0.058 0.040
Cumulative Var 0.090 0.169 0.248 0.324 0.396 0.454 0.494
=== PHƯƠNG SAI GIẢI THÍCH ===
PA2 PA5 PA4 PA3 PA1 PA6 PA7
SS loadings 2.597 2.388 2.245 2.218 2.058 1.701 1.181
Proportion Var 0.093 0.085 0.080 0.079 0.073 0.061 0.042
Cumulative Var 0.093 0.178 0.258 0.337 0.411 0.472 0.514
Proportion Explained 0.181 0.166 0.156 0.154 0.143 0.118 0.082
Cumulative Proportion 0.181 0.346 0.503 0.657 0.800 0.918 1.000
cat("\nTổng phương sai giải thích:",
round(sum(efa$Vaccounted["Proportion Var", ]) * 100, 1), "%\n")
Tổng phương sai giải thích: 51.4 %
| Giá trị loading | Đánh giá |
|---|---|
| ≥ 0.70 | Rất mạnh ✅ |
| 0.50 – 0.69 | Tốt ✅ |
| 0.30 – 0.49 | Chấp nhận (xem xét) |
| Xuất hiện ở 2+ nhân tố (cross-loading) | ❌ Cần loại item |
⚠️ Hai điểm cần chú ý kỹ:
- SQ1 (“Tôi sử dụng…vì chúng rất hữu ích”) — wording đo sự hữu ích, có thể tải lên cả nhân tố SQ lẫn PU → nếu cross-loading > 0.30 thì loại.
- TR1 (“Tôi mong muốn…minh bạch”) — đo kỳ vọng, không đo cảm nhận, có thể tải yếu → nếu loading < 0.50 và TR chỉ còn 2 item → báo GVHD.
📝 Ghi nhận kết quả:
- KMO = ___
- Bartlett p = ___
- Số nhân tố đề xuất từ parallel analysis: ___
- Tổng phương sai giải thích: ___%
- Item cần xem xét loại: ___
Phân tích nhân tố khám phá được tiến hành với phép trích Principal Axis Factoring và phép xoay Promax. Hệ số KMO đạt ___ (> 0.70) và kiểm định Bartlett có ý nghĩa thống kê (χ² = , p < 0.001), khẳng định dữ liệu phù hợp để phân tích nhân tố. Kết quả trích được 7 nhân tố với tổng phương sai trích đạt %, các hệ số tải nhân tố đều lớn hơn 0.50.
EFA giống bạn đổ một rổ đồ chơi lẫn lộn và xem chúng tự gom thành mấy đống. CFA giống bạn áp một bản thiết kế đã vẽ sẵn (7 hộp mô hình) vào dữ liệu và hỏi: “Dữ liệu có vừa khớp với bản thiết kế này không?”
Nếu CFA “vừa khít” → mô hình đo lường của bạn đáng tin → mới được chạy SEM.
| Chỉ số | Chấp nhận | Tốt | Ý nghĩa nôm na |
|---|---|---|---|
| CFI | ≥ 0.90 | ≥ 0.95 | Càng gần 1 càng khớp |
| TLI | ≥ 0.90 | ≥ 0.95 | Như CFI, phạt mô hình phức tạp |
| RMSEA | ≤ 0.08 | ≤ 0.06 | Sai số xấp xỉ, càng nhỏ càng tốt |
| SRMR | ≤ 0.08 | ≤ 0.05 | Phần dư chuẩn hóa trung bình |
| χ²/df | ≤ 3 | ≤ 2 | Nhạy cảm với cỡ mẫu lớn |
# --- Định nghĩa mô hình đo lường ---
# "=~" đọc là "được đo bởi"
cfa_model <- '
SQ =~ SQ1 + SQ2 + SQ3 + SQ4 + SQ5
PP =~ PP1 + PP2 + PP3 + PP4 + PP5
TR =~ TR1 + TR2 + TR3
PU =~ PU1 + PU2 + PU3 + PU4
PEOU =~ PEOU1 + PEOU2 + PEOU3 + PEOU4
BT =~ BT1 + BT2 + BT3 + BT4
BI =~ BI1 + BI2 + BI3
'
# Chạy CFA với MLR (Robust Maximum Likelihood)
# std.lv = TRUE: neo thang đo bằng cách cố định variance = 1 (cách chuẩn)
fit_cfa <- cfa(cfa_model,
data = df_clean,
estimator = "MLR",
std.lv = TRUE)=== CHỈ SỐ PHÙ HỢP CFA ===
fit_idx <- fitMeasures(fit_cfa, c("chisq.scaled","df.scaled","pvalue.scaled",
"cfi.robust","tli.robust",
"rmsea.robust","srmr"))
print(round(fit_idx, 3)) chisq.scaled df.scaled pvalue.scaled cfi.robust tli.robust
352.626 329.000 0.177 0.993 0.992
rmsea.robust srmr
0.014 0.038
ChiSq/df = 1.07
=== STANDARDIZED FACTOR LOADINGS ===
lavaan 0.6-21 ended normally after 27 iterations
Estimator ML
Optimization method NLMINB
Number of model parameters 77
Number of observations 347
Model Test User Model:
Standard Scaled
Test Statistic 352.284 352.626
Degrees of freedom 329 329
P-value (Chi-square) 0.181 0.177
Scaling correction factor 0.999
Yuan-Bentler correction (Mplus variant)
Parameter Estimates:
Standard errors Sandwich
Information bread Observed
Observed information based on Hessian
Latent Variables:
Estimate Std.Err z-value P(>|z|) Std.lv Std.all
SQ =~
SQ1 0.512 0.045 11.321 0.000 0.512 0.589
SQ2 0.635 0.038 16.724 0.000 0.635 0.752
SQ3 0.640 0.042 15.225 0.000 0.640 0.702
SQ4 0.562 0.046 12.118 0.000 0.562 0.634
SQ5 0.518 0.045 11.504 0.000 0.518 0.581
PP =~
PP1 0.647 0.044 14.765 0.000 0.647 0.719
PP2 0.662 0.046 14.261 0.000 0.662 0.729
PP3 0.686 0.042 16.280 0.000 0.686 0.787
PP4 0.613 0.043 14.160 0.000 0.613 0.694
PP5 0.562 0.044 12.915 0.000 0.562 0.652
TR =~
TR1 0.293 0.053 5.501 0.000 0.293 0.333
TR2 0.676 0.053 12.702 0.000 0.676 0.772
TR3 0.640 0.051 12.515 0.000 0.640 0.708
PU =~
PU1 0.670 0.041 16.323 0.000 0.670 0.765
PU2 0.596 0.042 14.189 0.000 0.596 0.674
PU3 0.606 0.044 13.895 0.000 0.606 0.684
PU4 0.631 0.041 15.524 0.000 0.631 0.728
PEOU =~
PEOU1 0.666 0.037 17.766 0.000 0.666 0.757
PEOU2 0.689 0.044 15.611 0.000 0.689 0.773
PEOU3 0.657 0.040 16.399 0.000 0.657 0.757
PEOU4 0.585 0.045 12.965 0.000 0.585 0.667
BT =~
BT1 0.665 0.040 16.575 0.000 0.665 0.756
BT2 0.667 0.039 17.208 0.000 0.667 0.764
BT3 0.633 0.041 15.354 0.000 0.633 0.723
BT4 0.595 0.043 13.716 0.000 0.595 0.692
BI =~
BI1 0.689 0.041 16.824 0.000 0.689 0.789
BI2 0.645 0.045 14.323 0.000 0.645 0.723
BI3 0.620 0.043 14.458 0.000 0.620 0.709
Covariances:
Estimate Std.Err z-value P(>|z|) Std.lv Std.all
SQ ~~
PP 0.264 0.058 4.527 0.000 0.264 0.264
TR 0.367 0.070 5.254 0.000 0.367 0.367
PU 0.541 0.047 11.531 0.000 0.541 0.541
PEOU 0.556 0.049 11.333 0.000 0.556 0.556
BT 0.615 0.045 13.760 0.000 0.615 0.615
BI 0.556 0.047 11.735 0.000 0.556 0.556
PP ~~
TR 0.364 0.066 5.540 0.000 0.364 0.364
PU 0.459 0.054 8.562 0.000 0.459 0.459
PEOU 0.470 0.050 9.464 0.000 0.470 0.470
BT 0.577 0.054 10.787 0.000 0.577 0.577
BI 0.390 0.054 7.207 0.000 0.390 0.390
TR ~~
PU 0.523 0.054 9.651 0.000 0.523 0.523
PEOU 0.538 0.054 10.055 0.000 0.538 0.538
BT 0.602 0.052 11.581 0.000 0.602 0.602
BI 0.351 0.065 5.442 0.000 0.351 0.351
PU ~~
PEOU 0.579 0.047 12.251 0.000 0.579 0.579
BT 0.578 0.047 12.206 0.000 0.578 0.578
BI 0.561 0.051 10.967 0.000 0.561 0.561
PEOU ~~
BT 0.574 0.046 12.510 0.000 0.574 0.574
BI 0.492 0.049 9.960 0.000 0.492 0.492
BT ~~
BI 0.597 0.048 12.448 0.000 0.597 0.597
Variances:
Estimate Std.Err z-value P(>|z|) Std.lv Std.all
.SQ1 0.494 0.040 12.479 0.000 0.494 0.654
.SQ2 0.310 0.030 10.195 0.000 0.310 0.435
.SQ3 0.421 0.041 10.278 0.000 0.421 0.507
.SQ4 0.469 0.036 12.980 0.000 0.469 0.597
.SQ5 0.526 0.044 11.968 0.000 0.526 0.662
.PP1 0.391 0.036 10.931 0.000 0.391 0.483
.PP2 0.386 0.035 11.044 0.000 0.386 0.468
.PP3 0.289 0.026 10.930 0.000 0.289 0.380
.PP4 0.405 0.036 11.334 0.000 0.405 0.518
.PP5 0.427 0.033 12.952 0.000 0.427 0.575
.TR1 0.688 0.052 13.199 0.000 0.688 0.889
.TR2 0.310 0.057 5.478 0.000 0.310 0.404
.TR3 0.407 0.051 7.949 0.000 0.407 0.499
.PU1 0.317 0.032 10.023 0.000 0.317 0.415
.PU2 0.426 0.037 11.465 0.000 0.426 0.546
.PU3 0.418 0.036 11.609 0.000 0.418 0.532
.PU4 0.353 0.035 10.044 0.000 0.353 0.470
.PEOU1 0.330 0.032 10.306 0.000 0.330 0.427
.PEOU2 0.319 0.031 10.156 0.000 0.319 0.402
.PEOU3 0.322 0.032 10.194 0.000 0.322 0.427
.PEOU4 0.428 0.034 12.690 0.000 0.428 0.555
.BT1 0.331 0.033 10.028 0.000 0.331 0.428
.BT2 0.317 0.031 10.175 0.000 0.317 0.416
.BT3 0.366 0.036 10.094 0.000 0.366 0.478
.BT4 0.385 0.036 10.797 0.000 0.385 0.521
.BI1 0.288 0.038 7.560 0.000 0.288 0.377
.BI2 0.381 0.039 9.809 0.000 0.381 0.478
.BI3 0.381 0.038 10.077 0.000 0.381 0.498
SQ 1.000 1.000 1.000
PP 1.000 1.000 1.000
TR 1.000 1.000 1.000
PU 1.000 1.000 1.000
PEOU 1.000 1.000 1.000
BT 1.000 1.000 1.000
BI 1.000 1.000 1.000
# --- CR (Composite Reliability) và AVE (Average Variance Extracted) ---
# CR >= 0.70 → độ tin cậy tổng hợp đạt
# AVE >= 0.50 → giá trị hội tụ đạt
cat("=== CR & AVE (Convergent Validity) ===\n")=== CR & AVE (Convergent Validity) ===
SQ PP TR PU PEOU BT BI
alpha 0.7842197 0.8403041 0.6224480 0.8039503 0.8277972 0.8241253 0.7837275
omega 0.7873230 0.8412556 0.6479433 0.8052053 0.8281954 0.8240350 0.7843818
omega2 0.7873230 0.8412556 0.6479433 0.8052053 0.8281954 0.8240350 0.7843818
omega3 0.7894978 0.8412027 0.6420471 0.8062660 0.8272487 0.8229644 0.7842700
avevar 0.4276690 0.5156942 0.4037050 0.5087328 0.5473896 0.5398436 0.5485217
# --- Giá trị phân biệt — Tiêu chí Fornell-Larcker ---
# Điều kiện: sqrt(AVE) của mỗi construct > tương quan với mọi construct khác
cat("=== TƯƠNG QUAN GIỮA CÁC CONSTRUCT (CFA) ===\n")=== TƯƠNG QUAN GIỮA CÁC CONSTRUCT (CFA) ===
SQ PP TR PU PEOU BT BI
SQ 1.000
PP 0.264 1.000
TR 0.367 0.364 1.000
PU 0.541 0.459 0.523 1.000
PEOU 0.556 0.470 0.538 0.579 1.000
BT 0.615 0.577 0.602 0.578 0.574 1.000
BI 0.556 0.390 0.351 0.561 0.492 0.597 1.000
# Chạy dòng này khi RMSEA > 0.08 hoặc CFI < 0.90
mi <- modificationIndices(fit_cfa, sort. = TRUE, minimum.value = 10)
head(mi, 15)
# MI lớn gợi ý có thể thêm đường (covariance hoặc cross-loading)
# Chỉ thêm khi có LÝ THUYẾT biện minh, không thêm bừa để fit đẹp.📝 Ghi nhận kết quả:
Chỉ số Kết quả Đạt/Chưa CFI ___ ___ TLI ___ ___ RMSEA ___ ___ SRMR ___ ___ χ²/df ___ ___ CR thấp nhất ___ (construct: ___) ___ AVE thấp nhất ___ (construct: ___) ___
Mô hình đo lường được kiểm định bằng phân tích nhân tố khẳng định với ước lượng MLR. Các chỉ số phù hợp đạt mức tốt (CFI = ; TLI = ; RMSEA = ; SRMR = ), cho thấy mô hình tương thích với dữ liệu. Độ tin cậy tổng hợp (CR) của các khái niệm dao động từ ___ đến ___ và phương sai trích bình quân (AVE) đều vượt ngưỡng 0.50, khẳng định giá trị hội tụ. Giá trị phân biệt được thỏa mãn theo tiêu chí Fornell-Larcker khi căn bậc hai của AVE lớn hơn các hệ số tương quan giữa các khái niệm.
Tương quan là bức tranh sơ bộ — xem các construct có “đi cùng chiều” không trước khi khẳng định quan hệ nhân quả bằng SEM.
⚠️ Quan trọng: Tương quan ≠ nhân quả. Chỉ SEM mới nói được “X gây ra Y”.
corr_mat <- cor(df_clean[constructs], use = "pairwise.complete.obs")
# Bảng số
cat("=== MA TRẬN TƯƠNG QUAN ===\n")=== MA TRẬN TƯƠNG QUAN ===
SQ PP TR PU PEOU BT BI
SQ 1.00 0.21 0.27 0.44 0.45 0.50 0.44
PP 0.21 1.00 0.27 0.38 0.39 0.48 0.31
TR 0.27 0.27 1.00 0.38 0.39 0.42 0.25
PU 0.44 0.38 0.38 1.00 0.47 0.47 0.44
PEOU 0.45 0.39 0.39 0.47 1.00 0.47 0.40
BT 0.50 0.48 0.42 0.47 0.47 1.00 0.48
BI 0.44 0.31 0.25 0.44 0.40 0.48 1.00
# Biểu đồ nhiệt tương quan
corrplot(corr_mat,
method = "color",
type = "lower",
addCoef.col = "black",
number.cex = 0.75,
tl.col = "black",
tl.srt = 45,
col = colorRampPalette(c("#d73027","white","#1a9850"))(200),
title = "Ma trận tương quan giữa các construct",
mar = c(0,0,1,0))Cách đọc: Màu xanh đậm = tương quan dương mạnh. Màu đỏ = tương quan âm. Số trong ô = hệ số r (từ −1 đến +1).
📝 Ghi nhận: Tương quan mạnh nhất: ___ và ___ (r = ) Tương quan BT–BI: r = (kỳ vọng dương, đây là cặp mediator–DV)
Hồi quy dùng điểm tổng hợp (mean composite) nên chạy nhanh và dễ đọc. Đây là bước kiểm tra nhanh trước SEM, và cũng là cách kiểm tra giả định (VIF, phần dư) mà lavaan không cung cấp sẵn.
SEM dùng biến tiềm ẩn (latent variable) → kết quả chuẩn hơn nhưng phức tạp hơn.
# Hồi quy: BI phụ thuộc vào PU, PEOU và BT
reg <- lm(BI ~ PU + PEOU + BT, data = df_clean)
summary(reg)
Call:
lm(formula = BI ~ PU + PEOU + BT, data = df_clean)
Residuals:
Min 1Q Median 3Q Max
-1.6681 -0.4148 0.0203 0.4293 1.6345
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.97787 0.20135 4.856 1.82e-06 ***
PU 0.24278 0.05682 4.272 2.51e-05 ***
PEOU 0.15653 0.05539 2.826 0.00499 **
BT 0.31257 0.05601 5.581 4.87e-08 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 0.6158 on 343 degrees of freedom
Multiple R-squared: 0.3067, Adjusted R-squared: 0.3006
F-statistic: 50.58 on 3 and 343 DF, p-value: < 2.2e-16
=== VIF (đa cộng tuyến) ===
PU PEOU BT
1.43 1.43 1.43
→ VIF < 3: lý tưởng | VIF < 10: chấp nhận
=== CONFIDENCE INTERVALS (95%) ===
2.5 % 97.5 %
(Intercept) 0.582 1.374
PU 0.131 0.355
PEOU 0.048 0.265
BT 0.202 0.423
| Biểu đồ | Kiểm tra | Kỳ vọng |
|---|---|---|
| Residuals vs Fitted | Tuyến tính | Điểm phân tán đều, không có mẫu hình |
| Q-Q Plot | Phân phối chuẩn | Điểm bám sát đường chéo |
| Scale-Location | Phương sai đồng nhất | Đường nằm ngang |
| Cook’s Distance | Điểm ảnh hưởng lớn | Không có điểm vượt ngưỡng 0.5 |
📝 Ghi nhận:
- R² = ___ (mô hình giải thích ___% phương sai BI)
- VIF lớn nhất = ___ (construct: ___)
- Hệ số có ý nghĩa nhất: ___ (β = , p = )
| Hồi quy | SEM | |
|---|---|---|
| Loại biến | Composite score | Latent variable (chuẩn hơn) |
| Mô hình | 1 phương trình | Nhiều phương trình đồng thời |
| Sai số đo lường | Không tính đến | Tính đến (ít thiên lệch hơn) |
| Kiểm định trung gian | Cần chạy nhiều bước | Tích hợp trong 1 lần chạy |
PU → BT → BI
[a] [b]
Hiệu ứng gián tiếp (indirect effect) = a × b
Kiểm định: dùng BOOTSTRAP → nếu khoảng tin cậy 95% KHÔNG chứa 0 → có trung gian
sem_model <- '
# ===================== MEASUREMENT MODEL ===================================
SQ =~ SQ1 + SQ2 + SQ3 + SQ4 + SQ5
PP =~ PP1 + PP2 + PP3 + PP4 + PP5
TR =~ TR1 + TR2 + TR3
PU =~ PU1 + PU2 + PU3 + PU4
PEOU =~ PEOU1 + PEOU2 + PEOU3 + PEOU4
BT =~ BT1 + BT2 + BT3 + BT4
BI =~ BI1 + BI2 + BI3
# ===================== STRUCTURAL MODEL ====================================
# Biến nhận thức TAM (PEOU, PU)
PEOU ~ SQ + PP + TR
PU ~ PEOU + SQ + PP + TR
# Brand Trust nhận tác động từ cả 5 tiền đề
BT ~ a1*PU + a2*PEOU + SQ + PP + TR
# BI: biến phụ thuộc
BI ~ b*BT + cp1*PU + cp2*PEOU
# ===================== INDIRECT EFFECTS (MEDIATION) ========================
# Đặt nhãn cho từng đường để tính indirect effect
ind_PU := a1 * b # PU -> BT -> BI
ind_PEOU := a2 * b # PEOU -> BT -> BI
total_PU := cp1 + a1*b # tổng tác động của PU lên BI
'
fit_sem <- sem(sem_model,
data = df_clean,
estimator = "MLR",
std.lv = TRUE)=== CHỈ SỐ PHÙ HỢP SEM ===
fit_sem_idx <- fitMeasures(fit_sem, c("chisq.scaled","df.scaled",
"cfi.robust","tli.robust",
"rmsea.robust","srmr"))
print(round(fit_sem_idx, 3))chisq.scaled df.scaled cfi.robust tli.robust rmsea.robust srmr
361.201 332.000 0.992 0.991 0.016 0.039
Chi-sq/df = 1.09
=== HỆ SỐ ĐƯỜNG DẪN (STANDARDIZED) ===
params <- parameterEstimates(fit_sem,
standardized = TRUE,
rsquare = TRUE)
# Chỉ lấy các đường cấu trúc (loại đường đo lường)
paths <- params %>%
filter(op %in% c("~", ":=")) %>%
select(lhs, op, rhs, est, se, pvalue, std.all) %>%
mutate(across(c(est,se,pvalue,std.all), round, 3),
Sig = case_when(pvalue < 0.001 ~ "***",
pvalue < 0.01 ~ "**",
pvalue < 0.05 ~ "*",
TRUE ~ "ns"))
print(paths) lhs op rhs est se pvalue std.all Sig
1 PEOU ~ SQ 0.536 0.096 0.000 0.380 ***
2 PEOU ~ PP 0.365 0.079 0.000 0.259 ***
3 PEOU ~ TR 0.427 0.098 0.000 0.303 ***
4 PU ~ PEOU 0.187 0.087 0.031 0.189 *
5 PU ~ SQ 0.429 0.098 0.000 0.306 ***
6 PU ~ PP 0.288 0.090 0.001 0.206 **
7 PU ~ TR 0.320 0.105 0.002 0.228 **
8 BT ~ PU 0.055 0.091 0.550 0.045 ns
9 BT ~ PEOU 0.006 0.089 0.945 0.005 ns
10 BT ~ SQ 0.676 0.134 0.000 0.399 ***
11 BT ~ PP 0.574 0.117 0.000 0.339 ***
12 BT ~ TR 0.507 0.125 0.000 0.299 ***
13 BI ~ BT 0.295 0.069 0.000 0.374 ***
14 BI ~ PU 0.268 0.086 0.002 0.280 **
15 BI ~ PEOU 0.112 0.078 0.147 0.118 ns
16 ind_PU := a1*b 0.016 0.027 0.557 0.017 ns
17 ind_PEOU := a2*b 0.002 0.026 0.945 0.002 ns
18 total_PU := cp1+a1*b 0.284 0.084 0.001 0.297 **
=== R-SQUARED (phương sai giải thích) ===
lhs est
1 SQ1 0.350
2 SQ2 0.564
3 SQ3 0.495
4 SQ4 0.403
5 SQ5 0.332
6 PP1 0.517
7 PP2 0.532
8 PP3 0.620
9 PP4 0.481
10 PP5 0.425
11 TR1 0.112
12 TR2 0.588
13 TR3 0.508
14 PU1 0.585
15 PU2 0.454
16 PU3 0.467
17 PU4 0.530
18 PEOU1 0.573
19 PEOU2 0.597
20 PEOU3 0.573
21 PEOU4 0.445
22 BT1 0.571
23 BT2 0.582
24 BT3 0.524
25 BT4 0.477
26 BI1 0.621
27 BI2 0.521
28 BI3 0.505
29 PU 0.490
30 PEOU 0.496
31 BT 0.652
32 BI 0.442
# --- Bảng kiểm định giả thuyết tổng hợp ---
# Điền tên giả thuyết, đường, và kết quả sau khi chạy
hyp_table <- data.frame(
Gia_thuyet = c("H1a","H1b","H1c",
"H2a","H2b","H2c",
"H3",
"H4a","H4b","H4c",
"H5","H6",
"H7","H8","H9",
"H10a","H10b"),
Duong = c("SQ→PEOU","PP→PEOU","TR→PEOU",
"SQ→PU","PP→PU","TR→PU",
"PEOU→PU",
"SQ→BT","PP→BT","TR→BT",
"PU→BT","PEOU→BT",
"BT→BI","PU→BI","PEOU→BI",
"PU→BT→BI (indirect)","PEOU→BT→BI (indirect)"),
Beta = rep("___", 17),
p = rep("___", 17),
KQ = rep("Chờ kết quả", 17)
)
knitr::kable(hyp_table, caption = "Bảng kiểm định giả thuyết (điền sau khi chạy)")| Gia_thuyet | Duong | Beta | p | KQ |
|---|---|---|---|---|
| H1a | SQ→PEOU | ___ | ___ | Chờ kết quả |
| H1b | PP→PEOU | ___ | ___ | Chờ kết quả |
| H1c | TR→PEOU | ___ | ___ | Chờ kết quả |
| H2a | SQ→PU | ___ | ___ | Chờ kết quả |
| H2b | PP→PU | ___ | ___ | Chờ kết quả |
| H2c | TR→PU | ___ | ___ | Chờ kết quả |
| H3 | PEOU→PU | ___ | ___ | Chờ kết quả |
| H4a | SQ→BT | ___ | ___ | Chờ kết quả |
| H4b | PP→BT | ___ | ___ | Chờ kết quả |
| H4c | TR→BT | ___ | ___ | Chờ kết quả |
| H5 | PU→BT | ___ | ___ | Chờ kết quả |
| H6 | PEOU→BT | ___ | ___ | Chờ kết quả |
| H7 | BT→BI | ___ | ___ | Chờ kết quả |
| H8 | PU→BI | ___ | ___ | Chờ kết quả |
| H9 | PEOU→BI | ___ | ___ | Chờ kết quả |
| H10a | PU→BT→BI (indirect) | ___ | ___ | Chờ kết quả |
| H10b | PEOU→BT→BI (indirect) | ___ | ___ | Chờ kết quả |
Mô hình cấu trúc đạt độ phù hợp tốt (CFI = ; RMSEA = ). Kết quả cho thấy niềm tin thương hiệu có tác động dương và mạnh nhất đến ý định hành vi (β = ___; p < 0.001), ủng hộ giả thuyết H7.
Kết quả kiểm định bằng phương pháp bootstrap (1.000 mẫu lặp) xác nhận vai trò trung gian của niềm tin thương hiệu trong mối quan hệ giữa nhận thức sự hữu ích và ý định hành vi. Hiệu ứng gián tiếp có ý nghĩa thống kê (β = ___; CI 95% [; ], không chứa 0), ủng hộ giả thuyết H10a.
# Bootstrap mất ~5-10 phút — chỉ chạy khi đã chạy xong SEM thường ở trên.
# Đặt eval=TRUE để kích hoạt chunk này khi Knit.
set.seed(2026)
fit_boot <- sem(sem_model,
data = df_clean,
se = "bootstrap",
bootstrap = 1000)
# Xem khoảng tin cậy cho indirect effects
boot_ci <- parameterEstimates(fit_boot,
boot.ci.type = "perc",
level = 0.95) %>%
filter(label %in% c("ind_PU","ind_PEOU","total_PU")) %>%
select(label, est, ci.lower, ci.upper, pvalue)
print(boot_ci)
# Nếu ci.lower và ci.upper đều cùng dấu (cả 2 > 0 hoặc < 0) → có trung gianĐọc kết quả Bootstrap:
ind_PU: est=0.12, CI=[0.06, 0.19]→ CI không chứa 0 → có trung gian → H10a ủng hộ ✅
| Buoc | Phan_tich | Cong_cu | Viet_vao_chuong |
|---|---|---|---|
| 1 | Import & Screening | read_excel, filter, drop_na | Chương 3: Phương pháp |
| 2 | Descriptive Statistics | describe(), table() | Chương 4.1: Thực trạng mẫu |
| 3 | Cronbach’s Alpha | psych::alpha() | Chương 4.2: Đo lường |
| 4 | EFA | KMO, fa.parallel, fa() | Chương 4.2: Đo lường |
| 5 | CFA | cfa(), fitMeasures, reliability() | Chương 4.2: Đo lường |
| 6 | Correlation | cor(), corrplot() | Chương 4.2: Phân tích |
| 7 | Regression | lm(), vif() | Chương 4.2 (tham khảo) |
| 8 | SEM | sem(), parameterEstimates() | Chương 4.2: Kiểm định H |
| 9 | Bootstrap Mediation | sem(se=‘bootstrap’) | Chương 4.2: Trung gian |
📌 Nhắc nhở cuối:
- Luôn đi theo thứ tự: Cronbach → EFA → CFA (đo lường trước) → SEM (cấu trúc sau).
- Nếu CFA chưa đạt → không chạy SEM để kiểm định giả thuyết.
- Khi có dữ liệu thật → chỉ thay file ở bước Import, mọi code chạy lại y hệt.
- Bấm Knit → Knit to HTML để có báo cáo đẹp gửi GVHD.
File tạo bằng R Markdown | Dữ liệu: AI_appliance_survey_DATA.xlsx Mô hình: SQ, PP, TR → PEOU, PU → Brand Trust (BT) → Behavioral Intention (BI)