随机图边数的二项分布拟合性统计检验方法咨询
嗨,我来帮你搞定这个分布验证的问题~ 首先得明确:你用nx.gnp_random_graph(n,p)生成的随机图,它的边数理论上本来就服从二项分布——因为每对节点独立以概率p连边,总共有M = n*(n-1)//2个可能的边对,所以边数X ~ Binomial(M, p)。不过既然你想通过统计检验来验证数据是否符合这个分布,下面给你两种实用的方法:
一、为什么scipy.stats.binom_test不适合?
先解释下你遇到的困惑:binom_test是用来检验单个观测事件的发生次数是否符合二项分布的某个概率(比如抛硬币100次正面55次,检验是否是0.5的概率),它针对的是单个样本点,而你有10000个边数样本,要检验整体分布是否匹配,得用拟合优度检验,比如卡方检验或者Kolmogorov-Smirnov检验。
二、方法1:卡方拟合优度检验(最常用的离散分布验证方法)
这个方法的核心是对比观测频数和理论频数的差异,步骤如下:
步骤1:确定理论二项分布的参数
先算出总可能边数:
n = 你生成图时用的n值 p = 你生成图时用的p值 M = n * (n - 1) // 2 # 总可能的边对数
步骤2:准备观测频数和理论频数
从你的样本列表l中统计每个边数区间的观测次数,再计算对应区间的理论次数(基于二项分布的概率质量函数):
import numpy as np from scipy.stats import binom, chisquare # 统计观测频数(用auto自动选合适的bins,避免区间频数太少) obs_counts, bins = np.histogram(l, bins='auto') # 计算每个bin对应的理论频数 theoretical = [] for i in range(len(bins)-1): lower = bins[i] upper = bins[i+1] # 取区间内所有整数边数,计算它们的概率之和,再乘以样本量10000 k_vals = np.arange(np.ceil(lower), np.floor(upper) + 1) prob_sum = binom.pmf(k_vals, M, p).sum() theoretical.append(prob_sum * 10000)
步骤3:修正区间(满足卡方检验的前提)
卡方检验要求每个区间的理论频数≥5,所以需要合并小频数的区间:
merged_obs = [] merged_theo = [] current_obs, current_theo = 0, 0 for o, t in zip(obs_counts, theoretical): current_obs += o current_theo += t if current_theo >= 5: merged_obs.append(current_obs) merged_theo.append(current_theo) current_obs, current_theo = 0, 0 # 把最后剩余的小频数加到最后一个区间 if current_obs > 0: merged_obs[-1] += current_obs merged_theo[-1] += current_theo
步骤4:执行检验并解读结果
chi2_stat, p_value = chisquare(merged_obs, f_exp=merged_theo) print(f"卡方统计量: {chi2_stat:.2f}, p值: {p_value:.4f}")
- 如果
p值 > 0.05(常用的显著性水平),说明我们没有足够的证据拒绝“数据服从二项分布”的原假设,也就是支持你的观测符合二项分布的结论。
三、方法2:Kolmogorov-Smirnov检验(对比经验分布和理论分布)
KS检验通过对比经验分布函数(EDF)和理论分布函数(CDF)的差异来验证拟合度,适合大样本:
from scipy.stats import kstest # 把观测数据排序 l_sorted = np.sort(l) # 定义理论二项分布的CDF def binom_cdf(x): return binom.cdf(x, M, p) # 执行KS检验 ks_stat, ks_pvalue = kstest(l_sorted, binom_cdf) print(f"KS统计量: {ks_stat:.4f}, p值: {ks_pvalue:.4f}")
- 解读逻辑和卡方检验一致:p值大于0.05则支持分布拟合的结论。
额外小技巧:从数据中估计参数
如果你不想用预设的p,而是想从样本中估计二项分布的参数,可以用样本均值来反推:
estimated_p = np.mean(l) / M # 二项分布的均值是M*p,所以p=均值/M
然后把上面代码中的p换成estimated_p再做检验即可。
内容的提问来源于stack exchange,提问作者Daniel Chepenko




