Trong khoảng 10 năm trở lại đây những nghiên cứu với thang đo Likert 5 dùng các phương pháp phân tích EFA, CFA, SEM trở thành một phong trào. Những phương pháp phân tích này chiếm một tỉ trọng lớn trong các nghiên cứu đăng tạp chí và PhD Thesis và điều đáng ngạc nhiên là gần như 100% các kết quả nghiên cứu đều rất đẹp (các giả thuyết nghiên cứu đặt ra đều thỏa mãn, các tiêu chí đánh giá độ phù hợp của mô hình SEM đều tốt, bảng ma trận xoay của hệ số tải hội tụ, các kiểm định KMO Test, Cronbach Alpha đều đẹp lung linh). Sử dụng Google chúng ta có thể tìm thấy rất rất nhiều nghiên cứu có cụm từ kiểu như “..các nhân tố ảnh hưởng..” như thế này. Một trong số đó là:
Các nhân tố tác động lên sự hài lòng của nhân viên: Nghiên cứu tại Hà Nội của tác giả LTP đăng trên một tạp chí thuộc nhóm uy tín nhất VN trong lĩnh vực kinh tế.
Như đã nói, trong số hầu hết các paper được đọc, thì 100% các kết quả đều rất đẹp. Trong post này tôi sẽ hướng dẫn cách thức tạo ra dữ liệu sao cho khi chạy các phân tích, kết quả sẽ đẹp lung linh. Dữ liệu được tạo ra nhằm mô phỏng nghiên cứu của tác giả LTP đăng trên tạp chí Kinh Tế Phát Triển. Cụ thể, tác giả LTP sẽ thu thập dữ liệu Likert 5 của 151 quant sát để đánh giá ảnh hưởng của bốn nhân tố: (1) Tính chất công việc (TCCV), (2) Tiền lương và phúc lợi (TLPL), (3) Đào tạo - phát triển (DTPT), và (4) Quan hệ công việc (QH) lên Mức độ hài lòng (SHL) của nhân viên. Số lượng các items/questions tương ứng với các nhân tố trên là 7, 4, 4, 6 và 3. Phần 1 của sẽ hướng dẫn tạo dữ liệu sao cho khi thực hiện các phân tích thì:
Bảng ma trận xoay hội tụ, thậm chí là các hệ số tải nhân tố rất cao (càng cao càng đẹp).
Các kiểm định như KMO Test, Cronbach Alpha đẹp.
Để tạo ra dữ liệu, cách đơn giản nhất là.. sử dụng một bộ dữ liệu bất kì nào đó. Trong post này tôi chọn bộ dữ liệu raq.dat từ cuốn Discovering Statistics Using IBM SPSS Statistics. Trước hết đọc bộ dữ liệu này vào R:
#============================
# Import and prepare data
#============================
# Clear R environment:
rm(list = ls())
library(dplyr)
# Import data:
read.delim("http://www.discoveringstatistics.com/docs/ds_data_files/R%20Data%20Files/raq.dat") -> saq_data
Chọn số lượng mẫu nghiên cứu, chẳng hạn, là 400 từ bộ dữ liệu này:
set.seed(12)
<- saq_data %>% sample_n(400) data_mini
Thực hiện cái gọi là “ma trận xoay - rotated matrix” như cách gọi phổ biến ở các paper tiếng Việt. Vì có tất cả 5 nhân tố nên:
library(psych)
<- principal(data_mini, nfactors = 5, rotate = "varimax")
rotated_fMatrix
print.psych(rotated_fMatrix, cut = 0.3, digits = 3, sort = TRUE) # Page 665.
## Principal Components Analysis
## Call: principal(r = data_mini, nfactors = 5, rotate = "varimax")
## Standardized loadings (pattern matrix) based upon correlation matrix
## item RC1 RC3 RC5 RC4 RC2 h2 u2 com
## Q21 21 0.670 0.601 0.399 1.72
## Q02 2 -0.567 0.407 0.508 0.492 1.96
## Q12 12 0.559 0.372 0.542 0.458 2.43
## Q18 18 0.558 0.447 0.603 0.397 2.54
## Q13 13 0.535 0.458 0.542 2.25
## Q20 20 0.513 0.328 0.409 0.591 2.06
## Q14 14 0.501 0.479 0.556 0.444 2.60
## Q03 3 -0.442 -0.304 0.355 0.490 0.510 3.58
## Q08 8 0.836 0.734 0.266 1.10
## Q17 17 0.768 0.683 0.317 1.33
## Q11 11 0.741 0.670 0.330 1.47
## Q04 4 0.352 0.405 0.396 0.493 0.507 3.53
## Q01 1 0.725 0.660 0.340 1.53
## Q05 5 0.692 0.536 0.464 1.25
## Q16 16 0.630 0.609 0.391 2.19
## Q06 6 0.794 0.683 0.317 1.17
## Q07 7 0.380 0.618 0.590 0.410 2.06
## Q10 10 0.409 0.578 0.535 0.465 2.04
## Q15 15 0.396 0.432 0.432 0.568 2.95
## Q09 9 0.691 0.504 0.496 1.11
## Q22 22 0.660 0.462 0.538 1.12
## Q23 23 0.320 0.561 0.501 0.499 2.22
## Q19 19 -0.309 0.437 0.349 0.651 2.56
##
## RC1 RC3 RC5 RC4 RC2
## SS loadings 3.132 2.707 2.438 2.414 1.917
## Proportion Var 0.136 0.118 0.106 0.105 0.083
## Cumulative Var 0.136 0.254 0.360 0.465 0.548
## Proportion Explained 0.248 0.215 0.193 0.191 0.152
## Cumulative Proportion 0.248 0.463 0.656 0.848 1.000
##
## Mean item complexity = 2
## Test of the hypothesis that 5 components are sufficient.
##
## The root mean square of the residuals (RMSR) is 0.06
## with the empirical chi square 725.341 with prob < 6.1e-77
##
## Fit based upon off diagonal values = 0.956
Kết quả này cho thấy:
Không sao. Dựa trên kết quả sơ bộ trên chúng ta có thể tạo ra bộ dữ liệu rất đẹp. Trước hết viết một hàm có tên là replace_someVar mà khi nhận đầu vào x sẽ:
Tất cả thay thế trên, là thay thế ngẫu nhiên. Dứoi đây là hàm đó:
# Function replaces some values:
<- function(x) {
replace_someVar
<- which(x == 1)
y
<- sample(y, floor(0.2*length(y)))
z1
<- 2
x[z1]
<- which(x == 5)
y5
<- sample(y5, floor(0.2*length(y5)))
z2
<- 4
x[z2]
<- which(x == 4)
y4
<- sample(y4, floor(0.3*length(y4)))
z3
<- 5
x[z3]
<- which(x == 2)
y2
<- sample(y2, floor(0.3*length(y2)))
t2
<- 3
x[t2]
<- which(x == 3)
y3
<- sample(y3, floor(0.2*length(y3)))
k3
<- 4
x[k3]
return(x)
}
Sử dụng hàm đã có để, trước hết, tạo ra data phù hợp với số lượng các items/questions tương ứng với các nhân tố đồng thời thực hiện cái gọi là kiểm định Cronbach Alpha luôn:
#==================
# Generate data
#==================
# TCCV:
<- data_mini %>%
factor_TCCV mutate(tccv1 = Q21,
tccv2 = replace_someVar(tccv1),
tccv3 = replace_someVar(tccv1),
tccv4 = replace_someVar(tccv1),
tccv5 = replace_someVar(tccv1),
tccv6 = replace_someVar(tccv1),
tccv7 = replace_someVar(tccv1),
tccv8 = replace_someVar(tccv1)) %>%
select(contains("tccv"))
::alpha(factor_TCCV) -> cronbach_TCCV
psych
# QHCV:
<- data_mini %>%
factor_QH mutate(qh1 = Q17,
qh2 = replace_someVar(qh1),
qh3 = replace_someVar(qh1),
qh4 = replace_someVar(qh1),
qh5 = replace_someVar(qh1),
qh6 = replace_someVar(qh1)) %>%
select(contains("qh"))
::alpha(factor_QH) -> cronbach_QH
psych
# TLPL:
<- data_mini %>%
factor_TLPL mutate(tlpl1 = Q01,
tlpl2 = replace_someVar(tlpl1),
tlpl3 = replace_someVar(tlpl1),
tlpl4 = replace_someVar(tlpl1)) %>%
select(contains("tlpl"))
::alpha(factor_TLPL) -> cronbach_TLPL
psych
# DTPT:
<- data_mini %>%
factor_DTPT mutate(dtpt1 = Q06,
dtpt2 = replace_someVar(dtpt1),
dtpt3 = replace_someVar(dtpt1),
dtpt4 = replace_someVar(dtpt1)) %>%
select(contains("dtpt"))
::alpha(factor_DTPT) -> cronbach_DTPT
psych
# SHL:
<- data_mini %>%
factor_SHL mutate(shl1 = Q22,
shl2 = replace_someVar(shl1),
shl3 = replace_someVar(shl1)) %>%
select(contains("shl"))
::alpha(factor_SHL) -> cronbach_SHL
psych
# Combine data sets:
%>%
factor_DTPT bind_cols(factor_QH) %>%
bind_cols(factor_SHL) %>%
bind_cols(factor_TCCV) %>%
bind_cols(factor_TLPL) -> data_for_paper
Đã có dữ liệu cho tất cả các nhân tố đề cập trong paper. Việc tiếp theo là lưu lại để phần mềm SPSS có thể đọc để gửi cho thầy, editor hoặc hội đồng PhD:
::write_sav(data_for_paper, "data_for_paper.sav") haven
Trước hết kiểm tra lại rằng bảng ma trận xoay là hội tụ và đẹp lung linh:
# Rotated matrix (or loadings matrix):
<- principal(data_for_paper, nfactors = 5, rotate = "varimax")
rotated_fMatrix_paper
print.psych(rotated_fMatrix_paper, cut = 0.3, digits = 3, sort = TRUE)
## Principal Components Analysis
## Call: principal(r = data_for_paper, nfactors = 5, rotate = "varimax")
## Standardized loadings (pattern matrix) based upon correlation matrix
## item RC1 RC2 RC3 RC5 RC4 h2 u2 com
## tccv1 14 0.958 0.969 0.0311 1.12
## tccv8 21 0.900 0.834 0.1659 1.06
## tccv4 17 0.890 0.824 0.1761 1.08
## tccv6 19 0.886 0.818 0.1820 1.08
## tccv5 18 0.884 0.819 0.1809 1.10
## tccv3 16 0.883 0.828 0.1725 1.12
## tccv2 15 0.881 0.818 0.1822 1.11
## tccv7 20 0.879 0.811 0.1894 1.10
## qh1 5 0.952 0.954 0.0460 1.11
## qh5 9 0.895 0.829 0.1708 1.07
## qh3 7 0.892 0.828 0.1720 1.08
## qh2 6 0.888 0.826 0.1743 1.10
## qh4 8 0.887 0.825 0.1749 1.10
## qh6 10 0.886 0.829 0.1706 1.11
## dtpt1 1 0.958 0.956 0.0442 1.08
## dtpt2 2 0.937 0.894 0.1061 1.04
## dtpt3 3 0.930 0.893 0.1065 1.07
## dtpt4 4 0.926 0.883 0.1172 1.06
## tlpl1 22 0.924 0.934 0.0657 1.19
## tlpl2 23 0.886 0.834 0.1656 1.13
## tlpl3 24 0.883 0.832 0.1683 1.14
## tlpl4 25 0.869 0.825 0.1751 1.19
## shl1 11 0.967 0.950 0.0495 1.03
## shl2 12 0.940 0.892 0.1084 1.02
## shl3 13 0.934 0.882 0.1176 1.02
##
## RC1 RC2 RC3 RC5 RC4
## SS loadings 6.718 5.108 3.627 3.407 2.727
## Proportion Var 0.269 0.204 0.145 0.136 0.109
## Cumulative Var 0.269 0.473 0.618 0.754 0.863
## Proportion Explained 0.311 0.237 0.168 0.158 0.126
## Cumulative Proportion 0.311 0.548 0.716 0.874 1.000
##
## Mean item complexity = 1.1
## Test of the hypothesis that 5 components are sufficient.
##
## The root mean square of the residuals (RMSR) is 0.017
## with the empirical chi square 67.744 with prob < 1
##
## Fit based upon off diagonal values = 0.998
KMO Test cũng hoàn hảo:
# Measure of Sampling Adequacy (MSA) - KMO Test:
KMO(data_for_paper)
## Kaiser-Meyer-Olkin factor adequacy
## Call: KMO(r = data_for_paper)
## Overall MSA = 0.91
## MSA for each item =
## dtpt1 dtpt2 dtpt3 dtpt4 qh1 qh2 qh3 qh4 qh5 qh6 shl1 shl2 shl3
## 0.81 0.88 0.89 0.90 0.85 0.95 0.94 0.94 0.95 0.94 0.66 0.75 0.77
## tccv1 tccv2 tccv3 tccv4 tccv5 tccv6 tccv7 tccv8 tlpl1 tlpl2 tlpl3 tlpl4
## 0.88 0.97 0.97 0.97 0.96 0.97 0.97 0.96 0.83 0.92 0.91 0.90
Và cả Cronbach Alpha cho từng nhân tố cũng không thể đẹp hơn:
# Cronbach Alpha:
print(cronbach_DTPT)
##
## Reliability analysis
## Call: psych::alpha(x = factor_DTPT)
##
## raw_alpha std.alpha G6(smc) average_r S/N ase mean sd median_r
## 0.96 0.96 0.96 0.87 27 0.0029 4 1 0.88
##
## lower alpha upper 95% confidence boundaries
## 0.96 0.96 0.97
##
## Reliability if an item is dropped:
## raw_alpha std.alpha G6(smc) average_r S/N alpha se var.r med.r
## dtpt1 0.94 0.94 0.91 0.84 16 0.0052 9.3e-05 0.84
## dtpt2 0.96 0.96 0.94 0.88 23 0.0037 1.6e-03 0.90
## dtpt3 0.96 0.96 0.94 0.88 22 0.0038 1.6e-03 0.90
## dtpt4 0.96 0.96 0.95 0.89 24 0.0035 1.0e-03 0.90
##
## Item statistics
## n raw.r std.r r.cor r.drop mean sd
## dtpt1 400 0.98 0.98 0.98 0.96 3.8 1.1
## dtpt2 400 0.94 0.94 0.92 0.90 4.0 1.1
## dtpt3 400 0.95 0.95 0.92 0.90 4.0 1.1
## dtpt4 400 0.94 0.94 0.91 0.89 4.0 1.1
##
## Non missing response frequency for each item
## 1 2 3 4 5 miss
## dtpt1 0.04 0.09 0.17 0.39 0.31 0
## dtpt2 0.04 0.07 0.16 0.36 0.38 0
## dtpt3 0.04 0.07 0.16 0.36 0.38 0
## dtpt4 0.04 0.07 0.16 0.36 0.38 0
print(cronbach_QH)
##
## Reliability analysis
## Call: psych::alpha(x = factor_QH)
##
## raw_alpha std.alpha G6(smc) average_r S/N ase mean sd median_r
## 0.96 0.96 0.96 0.82 27 0.0029 3.7 0.88 0.79
##
## lower alpha upper 95% confidence boundaries
## 0.96 0.96 0.97
##
## Reliability if an item is dropped:
## raw_alpha std.alpha G6(smc) average_r S/N alpha se var.r med.r
## qh1 0.95 0.95 0.94 0.78 18 0.0041 2.8e-05 0.78
## qh2 0.96 0.96 0.95 0.82 23 0.0034 2.4e-03 0.79
## qh3 0.96 0.96 0.95 0.82 23 0.0034 2.2e-03 0.79
## qh4 0.96 0.96 0.95 0.82 23 0.0034 2.2e-03 0.79
## qh5 0.96 0.96 0.95 0.82 23 0.0034 2.4e-03 0.79
## qh6 0.96 0.96 0.95 0.82 23 0.0034 2.4e-03 0.79
##
## Item statistics
## n raw.r std.r r.cor r.drop mean sd
## qh1 400 0.98 0.98 0.98 0.96 3.5 0.90
## qh2 400 0.91 0.91 0.88 0.87 3.7 0.96
## qh3 400 0.91 0.91 0.88 0.87 3.7 0.96
## qh4 400 0.91 0.91 0.89 0.87 3.7 0.96
## qh5 400 0.91 0.91 0.89 0.87 3.7 0.96
## qh6 400 0.91 0.91 0.89 0.87 3.7 0.96
##
## Non missing response frequency for each item
## 1 2 3 4 5 miss
## qh1 0.03 0.11 0.28 0.48 0.10 0
## qh2 0.02 0.08 0.26 0.42 0.23 0
## qh3 0.02 0.08 0.26 0.42 0.23 0
## qh4 0.02 0.08 0.26 0.42 0.23 0
## qh5 0.02 0.08 0.26 0.42 0.23 0
## qh6 0.02 0.08 0.26 0.42 0.23 0
print(cronbach_SHL)
##
## Reliability analysis
## Call: psych::alpha(x = factor_SHL)
##
## raw_alpha std.alpha G6(smc) average_r S/N ase mean sd median_r
## 0.95 0.95 0.94 0.86 19 0.0046 3.2 1 0.89
##
## lower alpha upper 95% confidence boundaries
## 0.94 0.95 0.96
##
## Reliability if an item is dropped:
## raw_alpha std.alpha G6(smc) average_r S/N alpha se var.r med.r
## shl1 0.89 0.89 0.80 0.80 8 0.0112 NA 0.80
## shl2 0.94 0.94 0.89 0.89 15 0.0061 NA 0.89
## shl3 0.95 0.95 0.90 0.90 18 0.0054 NA 0.90
##
## Item statistics
## n raw.r std.r r.cor r.drop mean sd
## shl1 400 0.97 0.97 0.97 0.94 3.1 1.0
## shl2 400 0.94 0.94 0.91 0.87 3.3 1.1
## shl3 400 0.94 0.94 0.89 0.86 3.3 1.1
##
## Non missing response frequency for each item
## 1 2 3 4 5 miss
## shl1 0.06 0.26 0.33 0.26 0.09 0
## shl2 0.04 0.19 0.33 0.28 0.15 0
## shl3 0.04 0.19 0.33 0.28 0.15 0
print(cronbach_TCCV)
##
## Reliability analysis
## Call: psych::alpha(x = factor_TCCV)
##
## raw_alpha std.alpha G6(smc) average_r S/N ase mean sd median_r
## 0.97 0.97 0.97 0.81 35 0.0021 3 0.99 0.79
##
## lower alpha upper 95% confidence boundaries
## 0.97 0.97 0.98
##
## Reliability if an item is dropped:
## raw_alpha std.alpha G6(smc) average_r S/N alpha se var.r med.r
## tccv1 0.96 0.96 0.96 0.79 26 0.0028 0.00019 0.79
## tccv2 0.97 0.97 0.97 0.82 32 0.0024 0.00210 0.79
## tccv3 0.97 0.97 0.97 0.82 31 0.0024 0.00211 0.80
## tccv4 0.97 0.97 0.97 0.82 31 0.0024 0.00205 0.79
## tccv5 0.97 0.97 0.97 0.82 31 0.0024 0.00203 0.79
## tccv6 0.97 0.97 0.97 0.82 32 0.0024 0.00214 0.79
## tccv7 0.97 0.97 0.97 0.82 32 0.0024 0.00206 0.80
## tccv8 0.97 0.97 0.97 0.82 31 0.0025 0.00215 0.79
##
## Item statistics
## n raw.r std.r r.cor r.drop mean sd
## tccv1 400 0.98 0.98 0.99 0.98 2.8 1.0
## tccv2 400 0.90 0.90 0.89 0.87 3.1 1.1
## tccv3 400 0.91 0.91 0.89 0.88 3.1 1.1
## tccv4 400 0.91 0.91 0.89 0.88 3.1 1.1
## tccv5 400 0.90 0.90 0.89 0.87 3.1 1.1
## tccv6 400 0.90 0.90 0.89 0.87 3.1 1.1
## tccv7 400 0.90 0.90 0.88 0.87 3.1 1.1
## tccv8 400 0.91 0.91 0.90 0.88 3.1 1.1
##
## Non missing response frequency for each item
## 1 2 3 4 5 miss
## tccv1 0.10 0.30 0.32 0.25 0.03 0
## tccv2 0.08 0.23 0.34 0.26 0.10 0
## tccv3 0.08 0.23 0.34 0.26 0.10 0
## tccv4 0.08 0.23 0.34 0.26 0.10 0
## tccv5 0.08 0.23 0.34 0.26 0.10 0
## tccv6 0.08 0.23 0.34 0.26 0.10 0
## tccv7 0.08 0.23 0.34 0.26 0.10 0
## tccv8 0.08 0.23 0.34 0.26 0.10 0
print(cronbach_TLPL)
##
## Reliability analysis
## Call: psych::alpha(x = factor_TLPL)
##
## raw_alpha std.alpha G6(smc) average_r S/N ase mean sd median_r
## 0.94 0.94 0.93 0.81 17 0.0048 3.8 0.83 0.81
##
## lower alpha upper 95% confidence boundaries
## 0.93 0.94 0.95
##
## Reliability if an item is dropped:
## raw_alpha std.alpha G6(smc) average_r S/N alpha se var.r med.r
## tlpl1 0.90 0.90 0.86 0.76 9.3 0.0084 0.00015 0.75
## tlpl2 0.93 0.93 0.92 0.82 13.9 0.0061 0.00439 0.86
## tlpl3 0.93 0.93 0.91 0.82 14.0 0.0060 0.00363 0.85
## tlpl4 0.93 0.93 0.91 0.83 14.2 0.0059 0.00234 0.85
##
## Item statistics
## n raw.r std.r r.cor r.drop mean sd
## tlpl1 400 0.96 0.97 0.97 0.94 3.6 0.85
## tlpl2 400 0.91 0.91 0.87 0.84 3.8 0.91
## tlpl3 400 0.91 0.91 0.87 0.84 3.8 0.91
## tlpl4 400 0.91 0.91 0.87 0.84 3.8 0.91
##
## Non missing response frequency for each item
## 1 2 3 4 5 miss
## tlpl1 0.02 0.07 0.30 0.50 0.12 0
## tlpl2 0.01 0.05 0.26 0.43 0.25 0
## tlpl3 0.01 0.05 0.26 0.43 0.25 0
## tlpl4 0.01 0.05 0.26 0.43 0.25 0
Các kết quả ở trên có thể tái lập lại bằng SPSS nếu muốn. Ma trận xoay, KMO Test và Cronbach Alpha cho nhân tố DTPT: