基于scipy.stats.kstest的大样本均匀性测试及技术疑问
我正在研究硬件熵生成方案,采用12-16位分辨率的A2D采集环境传感器数据,假设采样值的低位包含足够噪声与真实熵,可作为PRNG的种子。我的思路是逐步截断采样值的高位,直到结果呈现均匀分布,再将这些低位“随机”位组合成更大的随机整数。
暂不讨论该方案的合理性,我当前的核心问题是评估截断后样本分布的均匀性。最初尝试Chi-Square(卡方)检验,但它不适用于大样本(每个传感器有10k样本);转而使用Kolmogorov-Smirnov Test(KS检验),通过将整数样本归一化到0-1区间来适配scipy.stats.kstest()的要求,但低比特宽度时样本仍高度离散(如2位截断仅含0.0、0.25、0.5、0.75)。
我编写了测试代码:
import random import math from scipy.stats import kstest if __name__ == '__main__': samples = 1000 random.seed(0) print('samples: {}'.format(samples)) for bits in range(1, 16): max_val = (2 ** bits) - 1 obs = [] for i in range(samples): int_val = random.randint(0, max_val) obs.append(float(int_val) / max_val) stat, p = kstest(obs, 'uniform') print('{:3} bits : p={}'.format(bits, p))测试结果显示低比特时检验效果差,比特数增加后p值波动大。我的疑问:
- 针对0到2^n的整数样本,尤其是1-4位低比特场景,是否有更优的均匀性评估方法?求可量化评估的Python代码。
- 我对KS检验的应用是否正确?为何比特数超过5-6位后p值仍大幅波动?
问题1:低比特整数样本的均匀性评估方案
对于1-4位的离散整数样本(取值范围小、类别少),卡方检验是更合适的选择——你之前对它的误解是错误的,卡方检验对大样本反而更可靠,只要每个类别的期望频数≥5即可(10k样本下,哪怕1位只有2个类别,每个类别的期望是5k,远大于5)。同时可以搭配频率偏差评估(计算每个类别实际频率与理论频率的最大偏差、平均偏差)作为直观的量化指标。
实现代码
import random from scipy.stats import chisquare def evaluate_uniformity(int_samples, num_bits): num_categories = 2 ** num_bits # 统计每个类别的出现次数 counts = [0] * num_categories for val in int_samples: counts[val] += 1 # 卡方检验 chi_stat, chi_p = chisquare(counts) # 计算频率偏差 expected_freq = len(int_samples) / num_categories freq_deviations = [abs(c - expected_freq) / expected_freq for c in counts] max_deviation = max(freq_deviations) avg_deviation = sum(freq_deviations) / num_categories return { "chi_p_value": chi_p, "max_freq_deviation": max_deviation, "avg_freq_deviation": avg_deviation } if __name__ == '__main__': samples = 10000 random.seed(0) print(f"samples: {samples}") for bits in range(1, 5): max_val = (2 ** bits) - 1 int_samples = [random.randint(0, max_val) for _ in range(samples)] results = evaluate_uniformity(int_samples, bits) print(f"{bits:3} bits:") print(f" 卡方检验p值: {results['chi_p_value']:.6f}") print(f" 最大频率偏差: {results['max_freq_deviation']:.4f}") print(f" 平均频率偏差: {results['avg_freq_deviation']:.4f}")
结果说明
- 卡方检验p值:若p>0.05,在95%置信度下无法拒绝“样本服从均匀分布”的假设;
- 频率偏差:直接量化每个类别与理论均匀分布的差异,数值越小说明分布越均匀,适合快速直观判断。
问题2:KS检验的正确性与p值波动问题
你的KS检验应用是否正确?
不完全正确。KS检验原本是针对连续分布的检验,你把离散整数归一化到0-1区间后,样本仍然是离散的(比如2位只有4个取值),这会导致KS检验的统计量计算出现偏差——KS检验的核心是比较经验分布函数与理论分布函数的最大差异,离散样本的经验分布是阶梯状的,和连续均匀分布的拟合度天生就差,所以低比特时检验效果差是正常现象。
比特数增加后p值波动大的原因
- 样本量与离散程度的平衡:当比特数增加(比如5-6位,对应32/64个类别),样本离散程度降低,KS检验的统计量会更接近连续分布的情况,但此时样本量(1000)相对于类别数来说不算极大,每个类别的样本数波动会影响经验分布的阶梯形状,导致p值波动;
- 随机样本的固有方差:即使是完全均匀分布的随机样本,每次抽样得到的p值本身就会有波动,尤其是当样本量不足以完全抹平随机波动时,这种情况会更明显。如果将样本量增大到10k,p值的波动会显著减小。
修正建议
如果一定要用KS检验,建议针对离散均匀分布做对比,而非连续均匀分布。不过scipy的kstest没有直接支持离散分布的选项,更推荐优先用卡方检验处理离散样本场景。
内容的提问来源于stack exchange,提问作者cbp2

