: 모든 그룹의 모집단 공분산 행렬은 동일하다. ()
: 적어도 하나의 그룹의 모집단 공분산 행렬은 다르다.
통계량을 확률 분포(카이제곱 분포)를 이용해 검정하기 위해, 편향을 줄여주는 보정 계수 를 계산
# 1. 붓꽃(Iris) 데이터 불러오기
iris = sns.load_dataset('iris')
dependent_cols = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
group_col = 'species'
groups = iris[group_col].unique()
k = len(groups) # 그룹의 개수 (3개)
p = len(dependent_cols) # 변수의 개수 (4개)
N = len(iris) # 전체 데이터 개수 (150개)
for group in groups:
# 해당 그룹의 데이터만 추출
sub_data = iris[iris[group_col] == group][dependent_cols]
n_i = len(sub_data)
v_i = n_i - 1 # 각 그룹의 자유도
v_list.append(v_i)
# 표본 공분산 행렬 계산 (S_i)
S_i = sub_data.cov().values
S_list.append(S_i)
# 공분산 행렬의 로그 행렬식 계산 (오버플로우 방지를 위해 slogdet 사용)
_, log_det = np.linalg.slogdet(S_i)
log_det_list.append(log_det)
V = sum(v_list) # 전체 자유도 (N - k)
# --- 2단계: 합동 공분산 행렬(S_p) 계산 ---
S_p = np.zeros((p, p))
for i in range(k):
S_p += (v_list[i] / V) * S_list[i]
# 합동 공분산 행렬의 로그 행렬식 계산
_, log_det_Sp = np.linalg.slogdet(S_p)
# --- 3단계: Box-M 통계량 (M) 계산 ---
sum_v_log_det = sum([v_list[i] * log_det_list[i] for i in range(k)])
M = V * log_det_Sp - sum_v_log_det
# --- 4단계: 카이제곱 근사를 위한 보정 계수 (C) 계산 ---
sum_inv_v = sum([1 / v for v in v_list])
term1 = (2 * p**2 + 3 * p - 1) / (6 * (p + 1) * (k - 1))
term2 = sum_inv_v - (1 / V)
C = term1 * term2
# --- 5단계: 최종 검정 통계량(Chi-square) 및 자유도(df) 계산 ---
chi2_stat = M * (1 - C)
df = p * (p + 1) * (k - 1) / 2
# --- 6단계: 유의확률 (p-value) 도출 ---
p_value = 1 - chi2.cdf(chi2_stat, df)
# 결과 출력
print("=== 수제 Box-M 검정 결과 (Iris 데이터) ===")
print(f"M 통계량: {M:.4f}")
print(f"카이제곱 통계량 (Chi2): {chi2_stat:.4f}")
print(f"자유도 (df): {df}")
print(f"p-value: {p_value:.6f}")