10

Python 有多种方法可以生成不同的随机数分布,请参阅该模块的文档random。不幸的是,如果没有适当的数学背景,特别是考虑到所需的参数,它们并不是很容易理解。

我想知道这些方法中是否有任何一种能够产生分布符合本福德定律的随机数,以及哪些参数值是合适的。即对于整数群体,这些整数应该在大约 30% 的时间以“1”开头,大约 18% 的时间以“2”开头,等等。


使用John Dvorak 的答案,我将以下代码放在一起,它似乎可以完美运行。

def benfords_range_gen(stop, n):
    """ A generator that returns n random integers
    between 1 and stop-1 and whose distribution
    meets Benford's Law i.e. is logarithmic.
    """
    multiplier = math.log(stop)
    for i in range(n):
        yield int(math.exp(multiplier * random.random()))

>>> from collections import Counter
>>> Counter(str(i)[0] for i in benfords_range_gen(10000, 1000000))
Counter({'1': 300696, '2': 176142, '3': 124577, '4': 96756, '5': 79260, '6': 67413, '7': 58052, '8': 51308, '9': 45796})

还出现了一个问题,即这在不同版本的 Python 之间是否一致。由于随机数的性质,这不是一个微不足道的问题 - 您希望每次运行都会有一些变化,有时还会在random库的不同版本之间发生变化。避免这种情况的唯一方法是在每次运行之间一致地播种随机数生成器。我已将其添加到我的测试中,并且在 Python 2.7.1、3.8.6 和 3.9.1 中得到了完全相同的结果。

>>> random.seed(7919)
>>> Counter(str(i)[0] for i in benfords_range_gen(10000, 1000000))
Counter({'1': 301032, '2': 176404, '3': 125350, '4': 96503, '5': 78450, '6': 67198, '7': 58000, '8': 51342, '9': 45721})
4

2 回答 2

21

本福德定律描述了一组数字的第一个数字的分布,如果这些数字是从对数刻度上的一个很宽的范围内选择的。如果你准备一个十年内的对数均匀分布,它也将遵守法律。10^[0,1)将产生该分布。

这将产生所需的分布:math.floor(10**random.random())

于 2013-01-28T06:34:50.253 回答
0

只是在玩。

对于像我这样不太喜欢数学的人来说,这是一种效率低得多但可能更明显的实现......

创建任何所需分布的一种简单方法是用所需的项目百分比填充列表,然后使用random.choice(<list>),因为这会返回列表中项目的统一选择。

import random
probs = [30.1, 17.6, 12.5, 9.7, 7.9, 6.7, 5.8, 5.1, 4.6]
nums = [1, 2, 3, 4, 5, 6, 7, 8, 9]
population = sum([[n] * int(p * 10) for n, p in zip(nums, probs)], [])

max_value = 100
min_value = 1
result_pop = []
target_pop_size = 1000
while len(result_pop) < target_pop_size:
    s = str(random.choice(population))
    while True:
        r = random.randint(min_value, max_value)
        if str(r).startswith(s):
            break
    result_pop.append(r)
于 2013-01-28T07:00:56.870 回答