银行存款、河流长度等数据的首位数字更容易出现 1 而不是 9,这背后的数学原理是 本福特定律(Benford's Law)。
本福特定律的概述
本福特定律(Benford's Law)又称首位数字定律,是一种描述自然生成数据中数字分布规律的统计学现象。该定律揭示了在多种实际数据集中,数字1-9作为首位数字出现的概率呈现特定规律性分布。
数学表达式
首位数字d出现的概率为:
P(d) = log₁₀(1 + 1/d) ,其中 d ∈ {1,2,...,9}
概率分布表
| 首位数字 | 出现概率 |
|---------|---------|
| 1 | 30.1% |
| 2 | 17.6% |
| 3 | 12.5% |
| 4 | 9.7% |
| 5 | 7.9% |
| 6 | 6.7% |
| 7 | 5.8% |
| 8 | 5.1% |
| 9 | 4.6% |
本福特定律指出,在许多现实世界的数值数据集中,数字的首位(即最高位)更倾向于小数字,而不是均匀分布。例如,首位数字为 1 的概率大约是 30.1% ,而 9 只占 4.6% 。
为什么会出现这种现象?
本福特定律适用于跨多个数量级、呈指数增长或对数分布的数值数据集。银行存款、河流长度、人口统计等数据往往符合这些特征,原因如下:
- 对数尺度的均匀分布
在许多自然和社会现象中,数值往往不是线性增长的,而是按比例变化(即乘法增长)。如果数据在对数尺度上是均匀分布的,较小的首位数字会比较大的首位数字出现得更频繁。 - 数据的增长模式
例如,银行存款通常从小额开始增长,可能翻倍(100元 → 200元 → 400元 → 800元 → 1000元)。在这个过程中,数据在以 1 为首位的区间(100-199、1000-1999)停留的时间较长,而以 9 为首位的区间(900-999、9000-9999)停留的时间较短。 - 尺度不变性(Scale Invariance)
本福特定律适用于不同单位和尺度的数据。例如,无论河流长度是以英里还是公里度量,首位数字的分布仍然符合本福特定律。
检测代码示例(Go实现)
package main
import (
"fmt"
"math"
"strconv"
)
func benfordTest(data []float64) {
// 提取首位数字
firstDigits := make([]int, 0, len(data))
for _, num := range data {
if num == 0 {
continue
}
s := strconv.FormatFloat(math.Abs(num), 'f', -1, 64)
firstDigit, _ := strconv.Atoi(string(s[0]))
firstDigits = append(firstDigits, firstDigit)
}
// 计算实际分布
counts := make(map[int]int)
for _, d := range firstDigits {
counts[d]++
}
total := len(firstDigits)
actual := make(map[int]float64)
for d := 1; d <= 9; d++ {
actual[d] = float64(counts[d]) / float64(total)
}
// 理论分布
expected := make(map[int]float64)
for d := 1; d <= 9; d++ {
expected[d] = math.Log10(1 + 1.0/float64(d))
}
// 输出对比
fmt.Printf("%-5s %-8s %-8s\n", "数字", "实际", "理论")
for d := 1; d <= 9; d++ {
fmt.Printf("%-5d %-8.2f%% %-8.2f%%\n",
d,
actual[d]*100,
expected[d]*100)
}
}
// 示例用法
func main() {
// 测试数据(注意使用真实数据替换)
testData := []float64{
123, 4567, 890, 1234, 56789,
223, 445, 667, 889, 1123,
1567, 2234, 2890, 3123, 4234,
5234, 6234, 7234, 8234, 9234,
}
benfordTest(testData)
}
实际应用
本福特定律广泛适用于金融、科学和社会数据分析:
- 财务欺诈检测(若财务数据与本福特定律偏差过大,可能存在造假)
- 科学数据分析(核实实验数据的真实性)
- 网络流量分析(检测异常行为)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。