@Rui 提到了如何计算概率分布函数,但这在这里对你没有多大帮助。
您要使用的是Kolmogorov-Smirnov 检验或卡方检验。两者都用于将数据与已知概率分布进行比较,以确定数据集是否可能/不太可能具有该概率分布。
卡方用于离散分布,KS 用于连续分布。
对于使用带有 Benford 定律的卡方,您只需创建一个直方图 H[N],例如,使用 9 个 bin N=1,2,... 9,遍历数据集以检查第一个数字以计算样本数9 个非零数字中的每一个(或 90 个 bin 的前两位数字)。然后运行卡方检验以将直方图与预期计数 E[N] 进行比较。
例如,假设您有 100 条数据。E[N] 可以根据本福德定律计算:
E[1] = 30.1030 (=100*log(1+1))
E[2] = 17.6091 (=100*log(1+1/2))
E[3] = 12.4939 (=100*log(1+1/3))
E[4] = 9.6910
E[5] = 7.9181
E[6] = 6.6946
E[7] = 5.7992
E[8] = 5.1152
E[9] = 4.5757
然后计算 Χ 2 = sum((H[k]-E[k])^2/E[k]),并与测试中指定的阈值进行比较。(这里我们有一个没有参数的固定分布,所以参数个数 s=0 和 p = s+1 = 1,bins n 的数量为 9,所以自由度的数量 = np = 8*。然后你去你方便的花花公子卡方表,看看数字是否正常。对于 8 个自由度,置信水平如下所示:
X 2 > 13.362:数据集仍然符合本福德定律的概率为 10%
X 2 > 15.507:数据集仍然符合本福德定律的概率为 5%
X 2 > 17.535:数据集仍然符合本福德定律的概率为 2.5%
X 2 > 20.090:数据集仍然符合本福德定律的概率为 1%
X 2 > 26.125:0.1% 的可能性数据集仍然符合本福德定律
假设您的直方图产生 H = [29,17,12,10,8,7,6,5,6],对于 X 2 = 0.5585。这非常接近预期的分布。(甚至可能太近了!)
现在假设您的直方图产生 H = [27,16,10,9,5,11,6,5,11],对于 X 2 = 13.89。此直方图来自符合本福德定律的分布的可能性不到 10%。所以我认为数据集有问题,但并不过分。
请注意,您必须选择显着性水平(例如 10%/5%/等)。如果您使用 10%,预计每 10 个真正来自 Benford 分布的数据集中大约有 1 个会失败,即使它们没问题。这是一个判断电话。
看起来 Apache Commons Math 有一个卡方检验的 Java 实现:
ChiSquareTestImpl.chiSquare(double[] expected, long[] observed)
*注意自由度 = 8:这是有道理的;你有 9 个数字,但它们有 1 个约束,即它们都必须加起来等于数据集的大小,所以一旦你知道直方图的前 8 个数字,你就可以算出第九个。
Kolmogorov-Smirnov 实际上更简单(直到我找到一个足够简单的关于它如何工作的陈述之前我才意识到这一点)但适用于连续分布。该方法的工作原理如下:
- 您计算概率分布的累积分布函数 (CDF)。
- 您计算经验累积分布函数 (ECDF),通过将数据集按排序顺序轻松获得。
- 您会发现 D =(大约)两条曲线之间的最大垂直距离。
让我们更深入地处理本福德定律。
本福德定律的 CDF:这只是 C = log 10 x,其中 x 在区间 [1,10) 中,即包括 1 但不包括 10。如果您查看本福德定律的广义形式,就可以很容易地看出这一点,并且而不是把它写成 log(1+1/n),而是把它写成 log(n+1)-log(n)——换句话说,为了得到每个 bin 的概率,他们减去 log( n),所以 log(n) 必须是 CDF
ECDF:获取您的数据集,对于每个数字,使符号为正,用科学记数法书写,并将指数设置为 0。(如果您的数字为 0,不知道该怎么办;这似乎不适合到本福德定律分析。)然后按升序对数字进行排序。ECDF 是任何有效 x 的数据点数 <= x。
计算每个 d[k] = max(CDF(y[k]) - (k-1)/N, k/N - CDF(y[k]) 的最大差 D = max(d[k])。
这是一个示例:假设我们的数据集 = [3.02, 1.99, 28.3, 47, 0.61]。然后 ECDF 由排序后的数组 [1.99, 2.83, 3.02, 4.7, 6.1] 表示,你计算 D 如下:
D = max(
log10(1.99) - 0/5, 1/5 - log10(1.99),
log10(2.83) - 1/5, 2/5 - log10(2.83),
log10(3.02) - 2/5, 3/5 - log10(3.02),
log10(4.70) - 3/5, 4/5 - log10(4.70),
log10(6.10) - 4/5, 5/5 - log10(6.10)
)
其中 = 0.2988 (=log10(1.99) - 0)。
最后,您必须使用D 统计信息——我似乎无法在网上找到任何有信誉的表,但 Apache Commons Math 有一个KolmogorovSmirnovDistributionImpl.cdf()函数,该函数将计算出的 D 值作为输入并告诉您 D 将小于这个。采用 1-cdf(D) 可能更容易,它告诉您 D 大于或等于您计算的值的概率:如果这是 1% 或 0.1%,则可能意味着数据不符合本福德定律,但如果是 25% 或 50%,它可能是一个很好的匹配。