5

我有一个快速的问题。我正在尝试用java制作一个欺诈检测应用程序,该应用程序将主要基于本福德定律。Benford 定律超级酷,基本上可以解释为,在真实的金融交易中,第一个数字通常是 1、2 或 3,很少是 8、9。我一直无法得到 Benford 公式翻译成可以在 Java 中运行的代码。

http://www.mathpages.com/home/kmath302/kmath302.htm此链接包含有关本福德定律是什么以及如何使用它的更多信息。

我知道我必须使用 java 数学类才能使用自然对数函数,但我不知道该怎么做。任何帮助将不胜感激。

非常感谢!!

4

3 回答 3

8

@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 =(大约)两条曲线之间的最大垂直距离。

在此处输入图像描述

让我们更深入地处理本福德定律。

  1. 本福德定律的 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

  2. ECDF:获取您的数据集,对于每个数字,使符号为正,用科学记数法书写,并将指数设置为 0。(如果您的数字为 0,不知道该怎么办;这似乎不适合到本福德定律分析。)然后按升序对数字进行排序。ECDF 是任何有效 x 的数据点数 <= x。

  3. 计算每个 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%,它可能是一个很好的匹配。

于 2011-10-19T11:57:03.853 回答
4

如果我理解正确,您想要 Java 语法中的 Benford 公式吗?

public static double probability(int i) {   
    return Math.log(1+(1/(double) i))/Math.log(10);
}

记得插入一个

import java.lang.Math;

在您的包裹声明之后。

我觉得很可疑,还没有人回答这个问题……>_>

于 2011-10-19T10:14:50.563 回答
1

我认为您正在寻找的是这样的:

for(int i = (int)Math.pow(10, position-1); i <= (Math.pow(10, position)-1); i++)
        {
           answer +=  Math.log(1+(1/(i*10+(double) digit)));
        }

answer *= (1/Math.log(10)));
于 2011-10-21T21:32:27.353 回答