You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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'

问题原因与修正方案

问题核心

  1. 离散分布参数未估计:调用distfit.pmf时未传入分布所需的参数(如伯努利分布的p、二项分布的n和p),直接调用会触发参数缺失报错。
  2. 卡方检验用法错误:st.chisquare需要输入观测频数和理论频数,而非原始数据和pmf值;且pmf值需乘以样本量得到理论频数,同时要保证每组理论频数≥5(卡方检验的前提条件)。
  3. KS检验不适用于离散数据:标准KS检验针对连续分布,用于离散数据会导致结果偏差,建议优先使用卡方检验,或用离散版本的KS检验作为补充。
  4. 部分离散分布支持.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 23:45:55