Kiểm định Fisher Exact – Monte Carlo
Kiểm định Fisher Exact trong thực hành kinh tế lượng với SPSS

Tóm tắt: Kiểm định Fisher Exact là giải pháp thay thế quan trọng trong thực hành kinh tế lượng khi kiểm định chi bình phương không đáp ứng được các giả thiết cơ bản. Phương pháp này đặc biệt hữu ích với mẫu nhỏ (dưới 20 quan sát) hoặc khi tần suất kỳ vọng của các ô trong bảng chéo nhỏ hơn 5. Bài hướng dẫn này trình bày chi tiết cách thực hiện kiểm định Fisher Exact bằng SPSS qua ví dụ nghiên cứu mối quan hệ giữa trình độ học vấn và nhóm tuổi, bao gồm so sánh với kiểm định chi bình phương và cách diễn giải kết quả một cách chính xác.
Giới thiệu về kiểm định Fisher Exact
Nội dung chính
- Giới thiệu về kiểm định Fisher Exact
- Phương pháp tính toán trong kiểm định Fisher Exact
- Ví dụ thực tế từ dữ liệu lao động Việt Nam
- Xác định nhu cầu sử dụng Fisher Exact
- Hướng dẫn thực hành chi tiết trên SPSS
- Phân tích và giải thích kết quả
- Ưu điểm và hạn chế của kiểm định Fisher Exact
- Khi nào nên sử dụng Fisher Exact
- Ứng dụng trong nghiên cứu kinh tế
- Lưu ý quan trọng và khuyến nghị
- Tổng kết
- Phụ lục: Code tương đương cho các phần mềm khác
- Tài liệu tham khảo
Kiểm định này được ưu tiên sử dụng trong hai trường hợp chính:
- Mẫu nhỏ (từ 20 mẫu trở xuống)
- Một trong các ô trong bảng Crosstabs có tần suất kỳ vọng nhỏ hơn 5
SPSS sẽ tự động tính toán giá trị kiểm định Fisher Exact bên cạnh giá trị kiểm định chi bình phương đối với bảng 2×2. Vì thế, thực hiện kiểm định Fisher Exact ở bảng 2×2 chúng ta không cần thiết lập nút Exact. Nếu có bảng lớn hơn (chẳng hạn 2×5) nhưng cỡ mẫu nhỏ hoặc có tần suất kỳ vọng của ít nhất một ô nhỏ hơn 5 thì cần thiết lập kiểm định Fisher Exact.
Phương pháp tính toán trong kiểm định Fisher Exact
Kiểm định Fisher Exact bổ sung thêm hai kỹ thuật để tính toán mức ý nghĩa thống kê thông qua Crosstabs và các kiểm định phi tham số. Hai kỹ thuật này sẽ cho kết quả chính xác hơn khi dữ liệu không thỏa mãn các giả định của kiểm định chi bình phương:
Kỹ thuật Monte Carlo
- Cần nhập giá trị độ tin cậy cụ thể
- Xác định số mẫu được sử dụng trong tính toán xấp xỉ Monte Carlo
- Cho kết quả nhanh hơn so với kỹ thuật exact
- Phù hợp khi cần tính toán với tốc độ cao
Kỹ thuật Exact
- Cần xác định thời gian tối đa cho mỗi phép tính toán kiểm định
- Nếu thời gian tính toán trên 30 phút thì nên sử dụng Monte Carlo
- Cho kết quả chính xác tuyệt đối
- Phù hợp với các bảng chéo có kích thước vừa phải
Ví dụ thực tế từ dữ liệu lao động Việt Nam
Để minh họa cho thực hành kinh tế lượng, chúng ta sử dụng bộ dữ liệu vietlod.sav gồm 7,287 quan sát về người lao động trên toàn quốc.
Cấu trúc dữ liệu nghiên cứu
Các thông tin khảo sát chính bao gồm:
- gender: Giới tính
- age: Tuổi
- ethnic: Dân tộc
- degree: Bằng cấp
- region, urban: Nơi sinh sống
- school: Số năm đi học
- exp: Số năm kinh nghiệm
- section: Loại hình doanh nghiệp
- structure: Lĩnh vực làm việc
- earn: Thu nhập
Tạo biến nghiên cứu
Với bộ dữ liệu này, để minh họa kiểm định Fisher Exact, chúng ta tạo thêm biến giả sau đại học (đặt tên là upuniv
) bằng công cụ Recode into Different Variables.
Thiết lập mã hóa theo công thức:
$$upuniv = \left\{ \begin{array}{l}1\quad{degree = 6}\\0\quad{degree = 1 \div 5}\end{array} \right.$$
Trong đó:
- upuniv = 1: Có bằng cấp sau đại học (degree = 6)
- upuniv = 0: Không có bằng cấp sau đại học (degree = 1-5)
Xác định nhu cầu sử dụng Fisher Exact
Thực hiện tương tự như kiểm định chi bình phương về mối quan hệ giữa hai biến upuniv
và agegroup
, kết quả cho thấy:
Do vi phạm giả thiết, chúng ta không thể sử dụng kiểm định chi bình phương để kiểm tra mối quan hệ giữa hai biến upuniv
và agegroup
. Đây chính là lúc cần sử dụng kiểm định Fisher Exact.
Hướng dẫn thực hành chi tiết trên SPSS
Thực hiện kiểm định Fisher Exact trong SPSS theo các bước chi tiết sau:
Vào menu Analyze → Descriptive Statistics → Crosstabs…
Bước 2: Thiết lập biến phân tích
Tại cửa sổ Crosstabs:
- Đưa biến nhóm tuổi
agegroup
vào ô Row(s) - Đưa biến
upuniv
vào ô Column(s) - Có thể chọn hiển thị đồ thị thanh ở phần Display clustered bar charts
Bước 3: Thiết lập thống kê và hiển thị cell
Các thiết lập ở nút Statistics… và nút Cells… được thiết lập như kiểm định chi bình phương. Tuy nhiên, có một điểm khác biệt quan trọng:
Bước 4: Thiết lập kiểm định Fisher Exact
Đây là bước quan trọng nhất để thực hiện kiểm định Fisher Exact:
Bấm nút Exact… → chọn tùy chọn Exact như hình sau:
- Chọn Exact để sử dụng phương pháp tính toán chính xác
- Thiết lập thời gian tối đa nếu cần (mặc định thường phù hợp)
- Có thể chọn Monte Carlo nếu muốn tốc độ xử lý nhanh hơn
Bước 5: Thực hiện phân tích
Bấm Continue và OK để tiến hành thực hiện kiểm định.
Phân tích và giải thích kết quả
Kết quả kiểm định Fisher Exact trong thực hành kinh tế lượng cho thấy sự khác biệt quan trọng so với kiểm định chi bình phương:
So sánh kết quả giữa hai phương pháp
Kết quả cho thấy những điểm khác biệt quan trọng:
- Giá trị chi bình phương: Giống nhau ở hai phương pháp
- Mức ý nghĩa Sig. (2-sided): Có sự chênh lệch đáng kể
- Mức ý nghĩa Fisher Exact: Cao hơn so với chi bình phương
- Độ tin cậy: Fisher Exact chính xác hơn khi vi phạm giả thiết
Diễn giải kết quả cụ thể
Sự chênh lệch về mức ý nghĩa trong một số trường hợp có thể dẫn đến kết luận trái ngược nhau về chấp nhận/bác bỏ giả thuyết. Trong trường hợp này:
- Mức ý nghĩa 5%: Cả hai phương pháp đều bác bỏ giả thuyết H₀
- Kết luận: Có mối quan hệ giữa hai biến
agegroup
vàupuniv
- Cường độ mối quan hệ: Mối quan hệ giữa hai biến này là rất yếu
- Độ tin cậy: Kết quả Fisher Exact đáng tin cậy hơn do không vi phạm giả thiết
Ưu điểm và hạn chế của kiểm định Fisher Exact
Ưu điểm
- Chính xác tuyệt đối: Không dựa vào xấp xỉ như chi bình phương
- Phù hợp mẫu nhỏ: Hoạt động hiệu quả với cỡ mẫu bất kỳ
- Không yêu cầu giả thiết: Không cần tần suất kỳ vọng tối thiểu
- Tin cậy cao: Kết quả luôn chính xác về mặt thống kê
Hạn chế
- Thời gian tính toán: Chậm hơn đáng kể so với chi bình phương
- Hạn chế kích thước bảng: Khó khăn với bảng chéo lớn
- Yêu cầu phần mềm: Không thể tính toán thủ công
- Độ phức tạp: Khó hiểu cơ chế tính toán
Khi nào nên sử dụng Fisher Exact
Trong thực hành kinh tế lượng, nên sử dụng kiểm định Fisher Exact khi:
- Cỡ mẫu nhỏ (n ≤ 20)
- Bất kỳ ô nào có tần suất kỳ vọng < 5
- Hơn 20% các ô có tần suất kỳ vọng < 5
- Cần độ chính xác cao nhất
- Làm việc với dữ liệu khan hiếm
Ứng dụng trong nghiên cứu kinh tế
Kiểm định Fisher Exact có nhiều ứng dụng thực tiễn trong nghiên cứu kinh tế và xã hội:
Nghiên cứu thị trường
- Phân tích sở thích người tiêu dùng theo nhóm nhỏ
- Nghiên cứu mối quan hệ giữa đặc điểm nhân khẩu học và hành vi mua sắm
- Đánh giá hiệu quả chiến dịch marketing trong các phân khúc nhỏ
- Phân tích loyalty khách hàng theo vùng miền
Nghiên cứu chính sách
- Đánh giá tác động chính sách trên nhóm dân cư cụ thể
- Phân tích mối quan hệ giữa đặc điểm cá nhân và tuân thủ chính sách
- Nghiên cứu hiệu quả can thiệp trong các pilot program
- Đánh giá sự khác biệt giữa các nhóm xã hội
Lưu ý quan trọng và khuyến nghị
- Luôn kiểm tra tần suất kỳ vọng trước khi chọn phương pháp kiểm định
- Cân nhắc giữa độ chính xác và thời gian tính toán
- Không sử dụng Fisher Exact khi chi bình phương đã đủ điều kiện
- Chú ý đến ý nghĩa thực tiễn, không chỉ ý nghĩa thống kê
- Về mặt kỹ thuật: Đảm bảo hiểu rõ sự khác biệt giữa exact test và approximation
- Về diễn giải: Kết quả Fisher Exact thường bảo thủ hơn (p-value cao hơn)
- Về ứng dụng: Phù hợp nhất với nghiên cứu thăm dò và pilot study
- Về báo cáo: Nên báo cáo cả hai kết quả và giải thích lý do chọn Fisher Exact
Tổng kết
Kiểm định Fisher Exact là công cụ không thể thiếu trong thực hành kinh tế lượng khi nghiên cứu mối quan hệ giữa các biến phân loại với điều kiện đặc biệt. Qua ví dụ về mối quan hệ giữa trình độ học vấn và nhóm tuổi, chúng ta đã học được:
- Cách nhận biết khi nào cần sử dụng Fisher Exact thay vì chi bình phương
- Quy trình thực hiện kiểm định trong SPSS một cách chi tiết
- Cách diễn giải và so sánh kết quả với kiểm định chi bình phương
- Ứng dụng thực tiễn trong nghiên cứu kinh tế và xã hội
- Các lưu ý quan trọng để tránh sai sót trong phân tích
Phương pháp này đặc biệt quan trọng trong bối cảnh nghiên cứu ở Việt Nam, nơi nhiều nghiên cứu thường gặp phải vấn đề cỡ mẫu nhỏ hoặc phân phối không đều giữa các nhóm. Việc áp dụng đúng Fisher Exact không chỉ đảm bảo tính chính xác của kết quả mà còn nâng cao độ tin cậy của nghiên cứu.
Điểm chính cần ghi nhớ:
- Fisher Exact cho kết quả chính xác hơn chi bình phương khi vi phạm giả thiết
- Phù hợp với mẫu nhỏ và khi có ô có tần suất kỳ vọng nhỏ hơn 5
- Kết quả thường bảo thủ hơn (p-value cao hơn) so với chi bình phương
- Thời gian tính toán lâu hơn nhưng độ chính xác cao hơn
- Cần cân nhắc giữa độ chính xác và tính khả thi trong nghiên cứu
[1] Đây chỉ là ví dụ mang tính chất minh họa quá trình thực hiện kiểm định Fisher Exact. Lựa chọn kiểm định cặp biến nào tùy thuộc vào tình huống nghiên cứu cụ thể.
Phụ lục: Code tương đương cho các phần mềm khác
SPSS Syntax
SPSS Syntax (.sps file)
* Kiểm định Fisher Exact trong SPSS
* Mở dữ liệu
GET FILE='/data/vietlod.sav'.
* Tạo biến upuniv từ biến degree
RECODE degree (6=1) (1 thru 5=0) INTO upuniv.
VALUE LABELS upuniv 0 'Không có bằng sau đại học' 1 'Có bằng sau đại học'.
* Tạo biến agegroup (nếu chưa có)
RECODE age (LOWEST thru 25=1) (26 thru 35=2) (36 thru 45=3)
(46 thru 55=4) (56 thru HIGHEST=5) INTO agegroup.
VALUE LABELS agegroup 1 '≤25 tuổi' 2 '26-35 tuổi' 3 '36-45 tuổi'
4 '46-55 tuổi' 5 '≥56 tuổi'.
* Kiểm tra phân phối dữ liệu
FREQUENCIES VARIABLES=upuniv agegroup.
* Thực hiện kiểm định chi bình phương thông thường
CROSSTABS
/TABLES=agegroup BY upuniv
/FORMAT=AVALUE TABLES
/STATISTICS=CHISQ
/CELLS=COUNT EXPECTED ROW COLUMN TOTAL
/COUNT ROUND CELL.
* Thực hiện kiểm định Fisher Exact
CROSSTABS
/TABLES=agegroup BY upuniv
/FORMAT=AVALUE TABLES
/STATISTICS=CHISQ
/CELLS=COUNT EXPECTED ROW COLUMN TOTAL
/COUNT ROUND CELL
/EXACT FISHER.
* Kiểm định Fisher Exact với Monte Carlo (nếu cần)
CROSSTABS
/TABLES=agegroup BY upuniv
/FORMAT=AVALUE TABLES
/STATISTICS=CHISQ
/CELLS=COUNT EXPECTED ROW COLUMN TOTAL
/COUNT ROUND CELL
/EXACT FISHER MONTE CARLO CIN(95) SAMPLES(10000).
* Phân tích chi tiết cho từng nhóm tuổi
SPLIT FILE SEPARATE BY agegroup.
FREQUENCIES VARIABLES=upuniv.
SPLIT FILE OFF.
Stata
Stata Code (.do file)
* Kiểm định Fisher Exact trong Stata
* Mở dữ liệu
use "vietlod.dta", clear
* Tạo biến upuniv từ biến degree
gen upuniv = (degree == 6)
label define upuniv_lab 0 "Không có bằng sau đại học" 1 "Có bằng sau đại học"
label values upuniv upuniv_lab
* Tạo biến agegroup (nếu chưa có)
gen agegroup = 1 if age <= 25 replace agegroup = 2 if age >= 26 & age <= 35 replace agegroup = 3 if age >= 36 & age <= 45 replace agegroup = 4 if age >= 46 & age <= 55 replace agegroup = 5 if age >= 56
label define age_lab 1 "≤25 tuổi" 2 "26-35 tuổi" 3 "36-45 tuổi" ///
4 "46-55 tuổi" 5 "≥56 tuổi"
label values agegroup age_lab
* Kiểm tra phân phối dữ liệu
tab upuniv
tab agegroup
* Tạo bảng chéo cơ bản
tab agegroup upuniv
* Kiểm định chi bình phương thông thường
tab agegroup upuniv, chi2
* Kiểm định Fisher Exact
tab agegroup upuniv, exact
* Kiểm định Fisher Exact với chi tiết
tab agegroup upuniv, exact all
* Tính toán exact test cho từng cặp so sánh
forvalues i = 1/5 {
forvalues j = 1/1 {
tab agegroup upuniv if agegroup == `i', exact
}
}
* Vẽ đồ thị phân tích
graph bar (count), over(upuniv) over(agegroup) ///
title("Phân bố trình độ học vấn theo nhóm tuổi") ///
ytitle("Số lượng") ///
legend(label(1 "Không có bằng sau ĐH") label(2 "Có bằng sau ĐH"))
* Tính tỷ lệ phần trăm
tab agegroup upuniv, row col
* Kiểm tra điều kiện sử dụng Fisher Exact
tab agegroup upuniv, expected
* Xuất kết quả ra file
outreg2 using "fisher_exact_results.xls", replace ///
title("Kết quả kiểm định Fisher Exact") ///
addstat("Chi-square", r(chi2), "Fisher Exact p-value", r(p_exact))
R Programming
R Code (.R file)
# Kiểm định Fisher Exact trong R
# Cài đặt và load các package cần thiết
if (!require(foreign)) install.packages("foreign")
if (!require(gmodels)) install.packages("gmodels")
if (!require(exact2x2)) install.packages("exact2x2")
if (!require(DescTools)) install.packages("DescTools")
library(foreign)
library(gmodels)
library(exact2x2)
library(DescTools)
# Đọc dữ liệu SPSS
data <- read.spss("vietlod.sav", to.data.frame = TRUE)
# Tạo biến upuniv từ biến degree
data$upuniv <- ifelse(data$degree == 6, 1, 0)
data$upuniv <- factor(data$upuniv,
levels = c(0, 1),
labels = c("Không có bằng sau đại học", "Có bằng sau đại học"))
# Tạo biến agegroup (nếu chưa có)
data$agegroup <- cut(data$age,
breaks = c(0, 25, 35, 45, 55, 100),
labels = c("≤25 tuổi", "26-35 tuổi", "36-45 tuổi",
"46-55 tuổi", "≥56 tuổi"),
include.lowest = TRUE)
# Kiểm tra phân phối dữ liệu
table(data$upuniv)
table(data$agegroup)
# Tạo bảng chéo
contingency_table <- table(data$agegroup, data$upuniv)
print("Bảng chéo:")
print(contingency_table)
# Kiểm định chi bình phương thông thường
chi_square_test <- chisq.test(contingency_table)
print("Kết quả kiểm định chi bình phương:")
print(chi_square_test)
# Kiểm tra tần suất kỳ vọng
print("Tần suất kỳ vọng:")
print(chi_square_test$expected)
# Kiểm định Fisher Exact
fisher_test <- fisher.test(contingency_table)
print("Kết quả kiểm định Fisher Exact:")
print(fisher_test)
# Kiểm định Fisher Exact với simulate.p.value (tương tự Monte Carlo)
fisher_mc <- fisher.test(contingency_table, simulate.p.value = TRUE, B = 10000)
print("Kết quả kiểm định Fisher Exact (Monte Carlo):")
print(fisher_mc)
# Sử dụng package exact2x2 cho kiểm định chính xác hơn
if (ncol(contingency_table) == 2) {
exact_test <- exact2x2::exact2x2(contingency_table)
print("Kết quả kiểm định exact2x2:")
print(exact_test)
}
# Phân tích chi tiết
CrossTable(data$agegroup, data$upuniv,
expected = TRUE, prop.r = TRUE, prop.c = TRUE, prop.t = TRUE,
fisher = TRUE, chisq = TRUE, format = "SAS")
# Vẽ đồ thị
library(ggplot2)
library(dplyr)
# Tạo data frame cho visualization
plot_data <- data %>%
group_by(agegroup, upuniv) %>%
summarise(count = n(), .groups = "drop") %>%
group_by(agegroup) %>%
mutate(prop = count / sum(count))
# Đồ thị thanh
ggplot(plot_data, aes(x = agegroup, y = count, fill = upuniv)) +
geom_bar(stat = "identity", position = "stack") +
labs(title = "Phân bố trình độ học vấn theo nhóm tuổi",
x = "Nhóm tuổi",
y = "Số lượng",
fill = "Trình độ học vấn") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
# Đồ thị tỷ lệ
ggplot(plot_data, aes(x = agegroup, y = prop, fill = upuniv)) +
geom_bar(stat = "identity", position = "fill") +
labs(title = "Tỷ lệ trình độ học vấn theo nhóm tuổi",
x = "Nhóm tuổi",
y = "Tỷ lệ",
fill = "Trình độ học vấn") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
scale_y_continuous(labels = scales::percent)
# So sánh kết quả
comparison_results <- data.frame(
Method = c("Chi-square", "Fisher Exact", "Fisher MC"),
P_value = c(chi_square_test$p.value, fisher_test$p.value, fisher_mc$p.value),
Statistic = c(chi_square_test$statistic, NA, NA)
)
print("So sánh kết quả các phương pháp:")
print(comparison_results)
# Kiểm tra điều kiện sử dụng Fisher Exact
min_expected <- min(chi_square_test$expected)
prop_cells_below_5 <- sum(chi_square_test$expected < 5) / length(chi_square_test$expected)
print(paste("Tần suất kỳ vọng nhỏ nhất:", round(min_expected, 2)))
print(paste("Tỷ lệ ô có tần suất kỳ vọng < 5:", round(prop_cells_below_5 * 100, 1), "%"))
if (min_expected < 5 | prop_cells_below_5 > 0.2) {
print("Nên sử dụng Fisher Exact test")
} else {
print("Có thể sử dụng Chi-square test")
}
Python
Python Code (.py file)
# Kiểm định Fisher Exact trong Python
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats
from scipy.stats import chi2_contingency, fisher_exact
import warnings
warnings.filterwarnings('ignore')
# Đọc dữ liệu
# Nếu từ file SPSS
try:
data = pd.read_spss('vietlod.sav')
except:
# Nếu từ file CSV
data = pd.read_csv('vietlod.csv')
# Tạo biến upuniv từ biến degree
data['upuniv'] = (data['degree'] == 6).astype(int)
data['upuniv'] = data['upuniv'].map({0: 'Không có bằng sau đại học',
1: 'Có bằng sau đại học'})
# Tạo biến agegroup (nếu chưa có)
data['agegroup'] = pd.cut(data['age'],
bins=[0, 25, 35, 45, 55, 100],
labels=['≤25 tuổi', '26-35 tuổi', '36-45 tuổi',
'46-55 tuổi', '≥56 tuổi'],
include_lowest=True)
# Kiểm tra phân phối dữ liệu
print("Phân phối biến upuniv:")
print(data['upuniv'].value_counts())
print("\nPhân phối biến agegroup:")
print(data['agegroup'].value_counts())
# Tạo bảng chéo
contingency_table = pd.crosstab(data['agegroup'], data['upuniv'])
print("\nBảng chéo:")
print(contingency_table)
# Kiểm định chi bình phương thông thường
chi2, p_chi2, dof, expected = chi2_contingency(contingency_table)
print(f"\nKết quả kiểm định chi bình phương:")
print(f"Chi-square statistic: {chi2:.4f}")
print(f"P-value: {p_chi2:.6f}")
print(f"Degrees of freedom: {dof}")
print(f"\nTần suất kỳ vọng:")
expected_df = pd.DataFrame(expected,
index=contingency_table.index,
columns=contingency_table.columns)
print(expected_df)
# Kiểm tra điều kiện sử dụng Fisher Exact
min_expected = expected.min()
prop_cells_below_5 = (expected < 5).sum() / expected.size
print(f"\nTần suất kỳ vọng nhỏ nhất: {min_expected:.2f}")
print(f"Tỷ lệ ô có tần suất kỳ vọng < 5: {prop_cells_below_5*100:.1f}%") # Kiểm định Fisher Exact # Lưu ý: scipy.stats.fisher_exact chỉ làm việc với bảng 2x2 # Với bảng lớn hơn, cần sử dụng thư viện khác def fisher_exact_2xk(table): """ Thực hiện Fisher Exact test cho bảng 2xk """ try: from scipy.stats import chi2_contingency # Sử dụng Monte Carlo simulation _, p_value, _, _ = chi2_contingency(table, lambda_=None) return p_value except: return None # Nếu bảng chỉ có 2 hàng, có thể sử dụng Fisher exact if contingency_table.shape[0] == 2: # Chuyển đổi thành bảng 2x2 nếu cần if contingency_table.shape[1] == 2: odds_ratio, p_fisher = fisher_exact(contingency_table) print(f"\nKết quả kiểm định Fisher Exact (2x2):") print(f"Odds ratio: {odds_ratio:.4f}") print(f"P-value: {p_fisher:.6f}") else: print(f"\nBảng {contingency_table.shape[0]}x{contingency_table.shape[1]} - cần phương pháp khác") # Sử dụng thư viện rpy2 để gọi R's fisher.test (nếu có) try: import rpy2.robjects as ro from rpy2.robjects.packages import importr from rpy2.robjects import pandas2ri pandas2ri.activate() stats_r = importr('stats') # Chuyển đổi bảng chéo sang R r_table = pandas2ri.py2rpy(contingency_table) # Thực hiện Fisher Exact test fisher_result = stats_r.fisher_test(r_table) p_fisher_r = fisher_result.rx2('p.value')[0] print(f"\nKết quả Fisher Exact (sử dụng R):") print(f"P-value: {p_fisher_r:.6f}") except ImportError: print("\nrpy2 không có sẵn - không thể sử dụng R's fisher.test") # Simulation-based Fisher Exact (Monte Carlo) def monte_carlo_fisher_exact(table, n_simulations=10000): """ Thực hiện Fisher Exact test bằng Monte Carlo simulation """ from scipy.stats import hypergeom # Tính toán p-value bằng simulation row_sums = table.sum(axis=1) col_sums = table.sum(axis=0) total = table.sum().sum() observed_stat = chi2_contingency(table)[0] count = 0 for _ in range(n_simulations): # Tạo bảng ngẫu nhiên với cùng marginal totals simulated_table = np.random.multivariate_hypergeometric( row_sums, col_sums.sum()) # Tính chi-square statistic sim_stat = chi2_contingency(simulated_table.reshape(table.shape))[0] if sim_stat >= observed_stat:
count += 1
return count / n_simulations
# Thực hiện Monte Carlo simulation
try:
p_mc = monte_carlo_fisher_exact(contingency_table.values)
print(f"\nKết quả Monte Carlo Fisher Exact:")
print(f"P-value: {p_mc:.6f}")
except:
print("\nKhông thể thực hiện Monte Carlo simulation")
# Vẽ đồ thị
plt.style.use('default')
# Đồ thị 1: Heatmap
plt.figure(figsize=(10, 6))
sns.heatmap(contingency_table, annot=True, fmt='d', cmap='Blues')
plt.title('Bảng chéo: Nhóm tuổi vs Trình độ học vấn')
plt.tight_layout()
plt.show()
# Đồ thị 2: Stacked bar chart
plt.figure(figsize=(12, 6))
contingency_table.plot(kind='bar', stacked=True, color=['lightblue', 'lightcoral'])
plt.title('Phân bố trình độ học vấn theo nhóm tuổi')
plt.xlabel('Nhóm tuổi')
plt.ylabel('Số lượng')
plt.legend(title='Trình độ học vấn')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
# Đồ thị 3: Proportion chart
plt.figure(figsize=(12, 6))
prop_table = contingency_table.div(contingency_table.sum(axis=1), axis=0)
prop_table.plot(kind='bar', stacked=True, color=['lightblue', 'lightcoral'])
plt.title('Tỷ lệ trình độ học vấn theo nhóm tuổi')
plt.xlabel('Nhóm tuổi')
plt.ylabel('Tỷ lệ')
plt.legend(title='Trình độ học vấn')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
# So sánh kết quả
results_comparison = pd.DataFrame({
'Method': ['Chi-square', 'Fisher Exact (if 2x2)', 'Monte Carlo'],
'P_value': [p_chi2,
p_fisher if 'p_fisher' in locals() else np.nan,
p_mc if 'p_mc' in locals() else np.nan],
'Statistic': [chi2,
odds_ratio if 'odds_ratio' in locals() else np.nan,
np.nan]
})
print("\nSo sánh kết quả các phương pháp:")
print(results_comparison)
# Kết luận
print("\n" + "="*50)
print("KẾT LUẬN VÀ KHUYẾN NGHỊ")
print("="*50)
if min_expected < 5 or prop_cells_below_5 > 0.2:
print("✓ Nên sử dụng Fisher Exact test")
print("✗ Không nên sử dụng Chi-square test")
if 'p_fisher' in locals():
conclusion = "có" if p_fisher < 0.05 else "không có"
print(f"\nKết luận: {conclusion} mối quan hệ có ý nghĩa thống kê")
print(f"P-value (Fisher): {p_fisher:.6f}")
else:
print("✓ Có thể sử dụng Chi-square test")
print("✓ Fisher Exact test cũng có thể sử dụng (chính xác hơn)")
conclusion = "có" if p_chi2 < 0.05 else "không có"
print(f"\nKết luận: {conclusion} mối quan hệ có ý nghĩa thống kê")
print(f"P-value (Chi-square): {p_chi2:.6f}")
Tài liệu tham khảo
- Fisher, R. A. (1922). On the interpretation of χ² from contingency tables, and the calculation of P. Journal of the Royal Statistical Society, 85(1), 87-94
- Agresti, A. (2013). Categorical Data Analysis. John Wiley & Sons
- IBM SPSS Statistics Documentation: Crosstabs – Exact Tests
- Mehta, C. R., & Patel, N. R. (1983). A network algorithm for performing Fisher’s exact test in r × c contingency tables. Journal of the American Statistical Association, 78(382), 427-434
- Upton, G. J. (1982). A comparison of alternative tests for the 2×2 comparative trial. Journal of the Royal Statistical Society, 145(1), 86-105
- Nguyễn Đình Thọ (2013). Phương pháp nghiên cứu khoa học trong kinh doanh. NXB Lao động – Xã hội
- Hoàng Trọng & Chu Nguyễn Mộng Ngọc (2008). Phân tích dữ liệu nghiên cứu với SPSS. NXB Hồng Đức