Phân tích phương sai (ANOVA) và Kiểm định phi tham số trong Python: Hướng dẫn toàn diện cho Data Scientist

lúc 14:58 2 tháng 9, 2026
9 views

Trong lĩnh vực khoa học dữ liệu và thống kê, việc so sánh trung bình hoặc phân phối giữa các nhóm dữ liệu là một tác vụ cốt lõi. Khi bạn cần kiểm tra sự khác biệt giữa từ ba nhóm trở lên, Phân tích phương sai (ANOVA) là công cụ tiêu chuẩn. Tuy nhiên, khi dữ liệu không thỏa mãn các giả định về phân phối chuẩn, các kiểm định phi tham số (Non-parametric tests) sẽ là giải pháp thay thế hoàn hảo. Bài viết này sẽ hướng dẫn bạn cách thực hiện các kỹ thuật này bằng ngôn ngữ Python sử dụng các thư viện mạnh mẽ như scipy và statsmodels.

1. Giới thiệu về ANOVA và Kiểm định phi tham số trong Python 🐍

Trước khi đi vào code thực tế, việc nắm vững bản chất của từng phương pháp sẽ giúp bạn chọn đúng công cụ cho bài toán của mình.

  • ANOVA (Analysis of Variance): Kiểm định tham số dùng để kiểm tra xem có sự khác biệt có ý nghĩa thống kê giữa giá trị trung bình của từ ba nhóm độc lập trở lên hay không.
  • Kiểm định phi tham số: Các phương pháp không dựa trên giả định phân phối chuẩn của tổng thể (thường dựa trên thứ hạng - ranking), rất hữu ích khi dữ liệu bị lệch mạnh hoặc có chứa giá trị ngoại lai (outliers).

Python cung cấp hệ sinh thái phong phú giúp việc tính toán các kiểm định này trở nên cực kỳ nhanh chóng và chính xác. Hãy cùng thiết lập môi trường và đi vào các ví dụ mã nguồn cụ thể.

2. Phân tích phương sai (ANOVA) với Python 📈

Để thực hiện ANOVA trong Python, chúng ta thường sử dụng module stats từ thư viện scipy hoặc statsmodels cho các mô hình phức tạp hơn.

2.1. One-way ANOVA 🧪

One-way ANOVA được dùng khi bạn muốn nghiên cứu ảnh hưởng của một biến độc lập duy nhất (có từ 3 mức độ/nhóm trở lên) đến một biến phụ thuộc liên tục.

Code
import scipy.stats as stats

# Dữ liệu điểm số của học sinh từ 3 phương pháp giảng dạy khác nhau
method_a = [85, 90, 88, 92, 95]
method_b = [78, 82, 80, 85, 83]
method_c = [90, 93, 91, 89, 94]

# Thực hiện kiểm định One-way ANOVA
f_statistic, p_value = stats.f_oneway(method_a, method_b, method_c)

print(f"F-Statistic: {f_statistic:.4f}")
print(f"P-Value: {p_value:.4f}")

# Đánh giá kết quả
ALPHA_LEVEL = 0.05
if p_value < ALPHA_LEVEL:
    print("Bác bỏ giả thuyết H0: Có sự khác biệt có ý nghĩa thống kê giữa các phương pháp.")
else:
    print("Chấp nhận giả thuyết H0: Không có sự khác biệt rõ rệt.")

2.2. Two-way ANOVA 📊

Khi bạn có hai biến độc lập tác động lên một biến phụ thuộc, Two-way ANOVA cho phép bạn kiểm tra không chỉ tác động riêng lẻ của từng biến mà còn cả tác động tương tác (interaction effect) giữa chúng. Thư viện statsmodels hỗ trợ đắc lực việc này thông qua cú pháp công thức dạng bảng (formula).

Code
import pandas as pd
import statsmodels.api as sm
from statsmodels.formula.api import ols

# Tạo bộ dữ liệu giả định về năng suất cây trồng
data = pd.DataFrame({
    'Yield': [10, 12, 14, 15, 20, 22, 25, 28, 11, 13, 16, 18],
    'Fertilizer': ['A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'C', 'C', 'C'],
    'Watering': ['Low', 'Low', 'High', 'High', 'Low', 'Low', 'High', 'High', 'Low', 'Low', 'High', 'High']
})

# Xây dựng mô hình OLS cho Two-way ANOVA
model = ols('Yield ~ C(Fertilizer) + C(Watering) + C(Fertilizer):C(Watering)', data=data).fit()
anova_table = sm.stats.anova_lm(model, typ=2)

print(anova_table)

3. Các kiểm định phi tham số phổ biến trong Python 🔄

Khi dữ liệu không tuân theo phân phối chuẩn hoặc cỡ mẫu quá nhỏ, việc dùng ANOVA có thể dẫn đến kết quả sai lệch. Lúc này, các kiểm định phi tham số là lựa chọn thay thế tối ưu.

3.1. Kiểm định Kruskal-Wallis (Thay thế One-way ANOVA) 📉

Kiểm định Kruskal-Wallis là phiên bản phi tham số của One-way ANOVA. Phương pháp này dựa trên việc chuyển đổi dữ liệu thành các thứ hạng (ranks) thay vì dùng giá trị gốc.

Code
import scipy.stats as stats

# Dữ liệu lương của nhân viên ở 3 phòng ban có phân phối bị lệch phải
department_hr = [45, 50, 48, 52, 120] # Có giá trị ngoại lai cao
department_it = [60, 65, 62, 70, 75]
department_sales = [55, 58, 53, 57, 80]

# Thực hiện kiểm định Kruskal-Wallis
h_statistic, p_value_kw = stats.kruskal(department_hr, department_it, department_sales)

print(f"H-Statistic: {h_statistic:.4f}")
print(f"P-Value: {p_value_kw:.4f}")

if p_value_kw < 0.05:
    print("Có sự khác biệt đáng kể về mức lương giữa các phòng ban (theo Kruskal-Wallis).")
else:
    print("Không tìm thấy sự khác biệt có ý nghĩa thống kê.")

3.2. Kiểm định Mann-Whitney U (Thay thế Independent t-test) ⚖️

Trong trường hợp bạn chỉ cần so sánh giữa hai nhóm độc lập nhưng dữ liệu vi phạm tính chuẩn tắc, Mann-Whitney U test là sự thay thế hoàn hảo cho Independent T-test truyền thống.

Code
import scipy.stats as stats

# Điểm số của hai nhóm học viên
group_control = [70, 75, 78, 82, 65, 88]
group_treatment = [85, 90, 92, 95, 88, 91]

# Thực hiện kiểm định Mann-Whitney U
u_statistic, p_value_mw = stats.mannwhitneyu(group_control, group_treatment, alternative='two-sided')

print(f"U-Statistic: {u_statistic:.4f}")
print(f"P-Value: {p_value_mw:.4f}")

4. Khi nào nên dùng ANOVA hay Kiểm định phi tham số? 💡

Việc lựa chọn giữa kiểm định tham số và phi tham số phụ thuộc vào đặc điểm của tập dữ liệu:

  1. Kiểm tra tính chuẩn tắc (Normality Test): Sử dụng kiểm định Shapiro-Wilk (stats.shapiro) để kiểm tra xem dữ liệu có phân phối chuẩn hay không.
  2. Kiểm tra phương sai đồng nhất (Homogeneity of Variance): Sử dụng kiểm định Levene (stats.levene) cho ANOVA.
  3. Ra quyết định: Nếu dữ liệu thỏa mãn các điều kiện trên, hãy ưu tiên ANOVA vì nó có độ nhạy (statistical power) cao hơn. Ngược lại, nếu dữ liệu vi phạm nghiêm trọng (sai lệch phân phối, dữ liệu ordinal), hãy chuyển sang Kruskal-Wallis hoặc Mann-Whitney U để đảm bảo tính tin cậy của kết quả phân tích.

5. Bài tập thực hành vận dụng 📝

Để củng cố kiến thức về kiểm định phương sai và các phương pháp phi tham số trong Python, bạn hãy tự tay giải quyết hai bài tập thực hành dưới đây.

Bài tập 1: One-way ANOVA và Kiểm tra giả định 🧪

Đề bài: Một chuỗi cửa hàng bán lẻ muốn kiểm tra xem doanh thu trung bình hàng ngày (đơn vị: triệu VNĐ) tại 3 chi nhánh (Miền Bắc, Miền Trung, Miền Nam) có sự khác biệt đáng kể hay không. Hãy viết mã Python thực hiện các bước sau:

  1. Kiểm tra tính chuẩn tắc của dữ liệu từng chi nhánh bằng kiểm định Shapiro-Wilk (stats.shapiro).
  2. Kiểm tra tính đồng nhất phương sai bằng kiểm định Levene (stats.levene).
  3. Thực hiện One-way ANOVA để đưa ra kết luận cuối cùng với mức ý nghĩa α = 0.05.
Code
import scipy.stats as stats

# Dữ liệu doanh thu giả định của 3 chi nhánh
revenue_north = [45, 50, 52, 48, 55, 49, 51]
revenue_central = [38, 42, 40, 41, 39, 43, 44]
revenue_south = [60, 65, 62, 58, 63, 61, 64]

# 1. Kiểm tra tính chuẩn tắc (Normality Test) cho từng nhóm
_, p_north = stats.shapiro(revenue_north)
_, p_central = stats.shapiro(revenue_central)
_, p_south = stats.shapiro(revenue_south)

print(f"P-value Shapiro-Wilk (North): {p_north:.4f}")
print(f"P-value Shapiro-Wilk (Central): {p_central:.4f}")
print(f"P-value Shapiro-Wilk (South): {p_south:.4f}")

# 2. Kiểm tra tính đồng nhất phương sai (Homogeneity of Variance)
_, p_levene = stats.levene(revenue_north, revenue_central, revenue_south)
print(f"P-value Levene test: {p_levene:.4f}")

# 3. Thực hiện One-way ANOVA
f_stat, p_value_anova = stats.f_oneway(revenue_north, revenue_central, revenue_south)
print(f"F-Statistic: {f_stat:.4f}, P-Value: {p_value_anova:.4f}")

Bài tập 2: Kiểm định Kruskal-Wallis cho dữ liệu không chuẩn tắc 📉

Đề bài: Giả sử bạn khảo sát thời gian phản hồi (tính bằng phút) của hệ thống hỗ trợ khách hàng từ 3 nhóm kỹ thuật viên khác nhau. Do dữ liệu thời gian phản hồi có chứa nhiều giá trị ngoại lai lớn (khách hàng phản hồi chậm bất thường), dữ liệu không thỏa mãn phân phối chuẩn. Hãy sử dụng kiểm định Kruskal-Wallis để đánh giá sự khác biệt giữa các nhóm.

Code
import scipy.stats as stats

# Thời gian phản hồi của 3 nhóm kỹ thuật viên
team_alpha = [5, 8, 12, 6, 45]  # Có giá trị ngoại lai cao (45 phút)
team_beta = [7, 9, 6, 8, 10]
team_gamma = [10, 11, 9, 12, 14]

# Thực hiện kiểm định Kruskal-Wallis thay thế cho One-way ANOVA
h_statistic, p_value_kw = stats.kruskal(team_alpha, team_beta, team_gamma)

print(f"H-Statistic: {h_statistic:.4f}")
print(f"P-Value: {p_value_kw:.4f}")

# Đánh giá kết quả với ngưỡng alpha 0.05
SIGNIFICANCE_LEVEL = 0.05
if p_value_kw < SIGNIFICANCE_LEVEL:
    print("Có sự khác biệt có ý nghĩa thống kê về thời gian phản hồi giữa các nhóm kỹ thuật viên.")
else:
    print("Không đủ bằng chứng để bác bỏ giả thuyết H0.")

Bình luận

Đăng nhập để để lại bình luận.
Chưa có bình luận nào cho bài viết này.

Bài viết liên quan