Python实现卡方齐性检验时,NumPy数组除法如何保留小数?
解决卡方齐性检验中期望频数被取整的问题
你遇到的核心问题是期望频数数组被自动取整为整数,这直接导致卡方统计量计算偏差。大概率是创建或计算期望频数数组时使用了整数类型容器(比如numpy默认的整数数组),即使执行除法也会被强制取整。
问题根源排查
常见触发场景:
- 输入的观测频数是整数列表,转换成numpy数组时默认采用整数类型
- 计算期望频数(行和×列和/总频数)时,结果被存入整数数组,自动丢失小数部分
解决方案
1. 强制使用浮点型数组(推荐用numpy实现)
不要在计算后转换类型,而是在创建数组阶段就指定浮点类型,确保所有计算过程保留小数:
import numpy as np from scipy.stats import chi2 def chi_square_homogeneity(observed): # 直接将输入转为浮点型numpy数组 obs = np.array(observed, dtype=np.float64) row_totals = obs.sum(axis=1) col_totals = obs.sum(axis=0) total = obs.sum() # 计算期望频数,此时结果会保留完整小数 expected = np.outer(row_totals, col_totals) / total # 计算卡方值(跳过期望为0的情况,避免除以0错误) chi_sq = np.sum((obs - expected)**2 / expected, where=(expected != 0)) # 计算自由度与p值 df = (obs.shape[0] - 1) * (obs.shape[1] - 1) p_value = 1 - chi2.cdf(chi_sq, df) return chi_sq, p_value, expected
运行后expected数组会保留33.35、29.97这类小数,不会被取整。
2. 纯Python列表实现(避免numpy类型问题)
如果不用numpy,直接用Python列表计算时,要确保除法用/(返回浮点数)而非//(整数除法):
from scipy.stats import chi2 def chi_square_homogeneity(observed): row_totals = [sum(row) for row in observed] col_totals = [sum(col) for col in zip(*observed)] total = sum(row_totals) rows, cols = len(observed), len(observed[0]) # 计算期望频数,用/保证浮点数结果 expected = [ [(row_totals[i] * col_totals[j]) / total for j in range(cols)] for i in range(rows) ] # 计算卡方值 chi_sq = 0.0 for i in range(rows): for j in range(cols): if expected[i][j] != 0: chi_sq += (observed[i][j] - expected[i][j])**2 / expected[i][j] df = (rows - 1) * (cols - 1) p_value = 1 - chi2.cdf(chi_sq, df) return chi_sq, p_value, expected
这种实现完全依赖Python原生浮点数,不会出现自动取整问题。
验证结果
用你的测试数据运行上述代码,期望频数会保留完整小数,卡方值将接近预期的14.5,而非之前的15.58。
内容的提问来源于stack exchange,提问作者a0a912
相关产品推荐
相关产品推荐

