카이제곱 상관 분석 문서의 검증 코드다. if __name__ == "__main__": 아래가 자체 테스트다.
"""카이제곱 상관 분석 검증.
문서: 02.카이제곱 상관 분석 (예시, 정의, 카드 C2·C3)
주장:
1. 기대 빈도 e_ij = (행 합 × 열 합) / n. e11 = 300 × 450 / 1500 = 90.
2. 카이제곱 = Σ (o - e)^2 / e = 284.44 + 121.90 + 71.11 + 30.48 = 507.93 (항을 반올림해 더한 값, 정확히는 507.937).
3. 자유도 (r-1)(c-1) = 1의 유의수준 0.001 임계값 10.828보다 훨씬 커서 독립 가설을 버린다.
4. 두 속성이 독립이면(관측 = 기대) 카이제곱은 0이다. 표 전체를 k배하면 카이제곱도 k배가 된다.
5. 카드 C2: 2×2 표 [[30, 20], [20, 30]]의 카이제곱은 4.
"""
def expected(table):
rows = [sum(r) for r in table]
cols = [sum(c) for c in zip(*table)]
n = sum(rows)
return [[rows[i] * cols[j] / n for j in range(len(cols))] for i in range(len(rows))]
def chi2(table):
e = expected(table)
return sum((table[i][j] - e[i][j]) ** 2 / e[i][j] for i in range(len(table)) for j in range(len(table[0])))
def main():
t = [[250, 200], [50, 1000]] # 행: 소설, 비소설 / 열: 남, 여
e = expected(t)
assert e == [[90, 360], [210, 840]]
terms = [(t[i][j] - e[i][j]) ** 2 / e[i][j] for i in range(2) for j in range(2)]
assert [round(x, 2) for x in terms] == [284.44, 71.11, 121.9, 30.48]
x = chi2(t)
assert round(x, 2) == 507.94 or round(x, 2) == 507.93
print(f"[OK] 성별 × 선호 도서 분할표: 기대 빈도 {e}, 카이제곱 {x:.3f}")
print(" 항목:", [round(v, 2) for v in terms])
assert x > 10.828
print("[OK] 자유도 1, 유의수준 0.001 임계값 10.828보다 크다")
indep = [[30, 60], [10, 20]]
assert chi2(indep) == 0
assert abs(chi2([[3 * v for v in r] for r in t]) - 3 * x) < 1e-6
print("[OK] 독립이면 0, 표를 3배 하면 카이제곱도 3배")
assert abs(chi2([[30, 20], [20, 30]]) - 4) < 1e-12
print("[OK] 카드 C2: [[30, 20], [20, 30]] -> 4")
print("ALL CHECKS PASSED")
if __name__ == "__main__":
main()