如何在Python中对离散概率分布执行卡方拟合优度检验及排错
问题描述
我尝试为数据拟合多种概率分布,对每个分布的拟合效果执行**极大似然估计(MLE)**和KS检验。连续概率分布的代码可正常运行,但离散概率分布因无.fit方法,改用卡方拟合优度检验时代码无法运行,出现参数缺失错误。
连续分布代码(可正常运行)
import pandas as pd import numpy as np import scipy.stats as st from scipy.stats import kstest data = pd.read_csv(r'...\\demo_data.csv') data = pd.DataFrame(data) #continuous variables continuous_results = [] for cvar in ["cvar1", "cva2", "cvar3"]: #probability distributions cdistributions = [ st.arcsine, st.alpha, st.beta, st.betaprime, st.bradford, st.burr, st.chi, st.chi2, st.cosine, st.dgamma, st.dweibull, st.expon, st.exponweib, st.exponpow, st.genlogistic, st.genpareto, st.genexpon, st.gengamma, st.genhyperbolic, st.geninvgauss, st.gennorm, st.f, st.gamma, st.invgamma, st.invgauss, st.invweibull, st.laplace, st.logistic, st.loggamma, st.loglaplace, st.loguniform, st.nakagami, st.norm, st.pareto, st.powernorm, st.powerlaw, st.rdist, st.semicircular, st.t, st.trapezoid, st.triang, st.tukeylambda, st.uniform, st.wald, st.weibull_max, st.weibull_min ] for distribution in cdistributions: try: #fit each probability distribution to each variable in the data pars = distribution.fit(data[cvar]) mle = distribution.nnlf(pars, data[cvar]) #perform ks test ks_result = kstest(data[cvar], distribution.cdf, args = pars) #create dictionary to store results for each variable/distribution result = { "variable": cvar, "distribution": distribution.name, "type": "continuous", "mle": mle, "ks_stat": ks_result.statistic, "ks_pvalue": ks_result.pvalue } continuous_results.append(result) except Exception as e: # assign 0 for error mle = 0
离散分布代码(无法运行)
#discrete variables discrete_results = [] for var in ["dvar1", "dvar2"]: #probability distributions distributions = [ st.bernoulli, st.betabinom, st.binom, st.boltzmann, st.poisson, st.geom, st.nbinom, st.hypergeom, st.zipf, st.zipfian, st.logser, st.randint, st.dlaplace ] for distribution in distributions: try: #fit each probability distribution to each variable in the data distfit = getattr(st, distribution.name) chisq_stat, pval = st.chisquare(data[var], f = distfit.pmf(range(len(data[var])))) #perform ks test ks_result = kstest(data[var], distribution.cdf, args = distfit.pmf(range(len(data[var])))) #create dictionary to store results for each variable/distribution result = { "variable": var, "distribution": distribution.name, "type": "continuous", "chisq": chisq_stat, "pvalue": pval, "ks_stat": ks_result.statistic, "ks_pvalue": ks_result.pvalue } discrete_results.append(result) except Exception as e: # assign 0 for error chisq_stat = 0
报错信息
_parse_args() missing 1 required positional argument: 'p' _parse_args() missing 3 required positional arguments: 'n', 'a', and 'b' _parse_args() missing 2 required positional arguments: 'n' and 'p' _parse_args() missing 2 required positional arguments: 'lambda_' and 'N' _parse_args() missing 1 required positional argument: 'mu' _parse_args() missing 1 required positional argument: 'p' _parse_args() missing 2 required positional arguments: 'n' and 'p' _parse_args() missing 3 required positional arguments: 'M', 'n', and 'N' _parse_args() missing 1 required positional argument: 'a' _parse_args() missing 2 required positional arguments: 'a' and 'n' _parse_args() missing 1 required positional argument: 'p' _parse_args() missing 2 required positional arguments: 'low' and 'high' _parse_args() missing 1 required positional argument: 'a' _parse_args() missing 1 required positional argument: 'p' _parse_args() missing 3 required positional arguments: 'n', 'a', and 'b' _parse_args() missing 2 required positional arguments: 'n' and 'p' _parse_args() missing 2 required positional arguments: 'lambda_' and 'N' _parse_args() missing 1 required positional argument: 'mu' _parse_args() missing 1 required positional argument: 'p' _parse_args() missing 2 required positional arguments: 'n' and 'p' _parse_args() missing 3 required positional arguments: 'M', 'n', and 'N' _parse_args() missing 1 required positional argument: 'a' _parse_args() missing 2 required positional arguments: 'a' and 'n' _parse_args() missing 1 required positional argument: 'p' _parse_args() missing 2 required positional arguments: 'low' and 'high' _parse_args() missing 1 required positional argument: 'a'
问题原因与修正方案
问题核心
- 离散分布参数未估计:调用
distfit.pmf时未传入分布所需的参数(如伯努利分布的p、二项分布的n和p),直接调用会触发参数缺失报错。 - 卡方检验用法错误:
st.chisquare需要输入观测频数和理论频数,而非原始数据和pmf值;且pmf值需乘以样本量得到理论频数,同时要保证每组理论频数≥5(卡方检验的前提条件)。 - KS检验不适用于离散数据:标准KS检验针对连续分布,用于离散数据会导致结果偏差,建议优先使用卡方检验,或用离散版本的KS检验作为补充。
- 部分离散分布支持.fit方法:scipy中多数常用离散分布(如
binom、poisson、geom)都有.fit方法,可用来自动估计参数。
修正后的离散分布代码
#discrete variables discrete_results = [] for var in ["dvar1", "dvar2"]: # 筛选支持拟合的离散分布(部分分布如hypergeom需要已知总体参数,无法直接拟合) distributions = [ st.bernoulli, st.binom, st.poisson, st.geom, st.nbinom, st.logser, st.randint ] # 获取当前变量的观测数据 obs_data = data[var].values # 统计观测频数:按唯一值分组 obs_counts, bins = np.histogram(obs_data, bins=np.arange(obs_data.min(), obs_data.max()+2), density=False) bin_centers = bins[:-1] # 离散值的实际取值 for distribution in distributions: try: # 1. 拟合分布,估计参数 pars = distribution.fit(obs_data) # 2. 计算MLE值(负对数似然) mle = distribution.nnlf(pars, obs_data) # 3. 计算理论频数:用拟合后的pmf乘以样本量 theoretical_pmf = distribution.pmf(bin_centers, *pars) theoretical_counts = theoretical_pmf * len(obs_data) # 过滤掉理论频数<5的组(卡方检验要求) valid_mask = theoretical_counts >= 5 if not np.any(valid_mask): # 无有效组,跳过当前分布 continue filtered_obs = obs_counts[valid_mask] filtered_theo = theoretical_counts[valid_mask] # 4. 执行卡方拟合优度检验 chisq_stat, chisq_pval = st.chisquare(f_obs=filtered_obs, f_exp=filtered_theo) # 5. 离散KS检验(scipy 1.7+支持,适合离散数据) ks_stat, ks_pval = st.kstest(obs_data, distribution.cdf, args=pars, alternative='two-sided') # 存储结果 result = { "variable": var, "distribution": distribution.name, "type": "discrete", "mle": mle, "chisq_stat": chisq_stat, "chisq_pvalue": chisq_pval, "ks_stat": ks_stat, "ks_pvalue": ks_pval } discrete_results.append(result) except Exception as e: # 捕获错误,记录无效结果 print(f"{distribution.name}处理{var}时出错: {str(e)}") result = { "variable": var, "distribution": distribution.name, "type": "discrete", "mle": np.nan, "chisq_stat": np.nan, "chisq_pvalue": np.nan, "ks_stat": np.nan, "ks_pvalue": np.nan } discrete_results.append(result)
额外说明
- 对于
hypergeom、betabinom这类需要已知额外参数(如总体大小、成功次数)的分布,无法直接用.fit估计所有参数,需手动传入已知参数后再拟合剩余参数。 - 卡方检验的分组方式需根据数据分布调整,确保每组理论频数达标,否则检验结果不可靠。
- 离散数据优先使用卡方检验,KS检验仅作为补充参考。
内容的提问来源于stack exchange,提问作者DrPaulVella
相关产品推荐
相关产品推荐

