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年以上の対数一様分布を用意すれば、それも法則を尊重します。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 に答える