كيف يمكنني محاكاة يموت منحازة في بيثون؟

StackOverflow https://stackoverflow.com/questions/479236

  •  20-08-2019
  •  | 
  •  

سؤال

وأريد أن محاكاة N من جانب ويموت منحازة؟

def roll(N,bias):
     '''this function rolls N dimensional die with biasing provided'''
     # do something
     return result

>> N=6
>> bias=( 0.20,0.20,0.15,0.15,0.14,0.16,)
>> roll(N,bias)
   2
هل كانت مفيدة؟

المحلول

وقليلا من الرياضيات هنا.

وهناك يموت العادية سوف يعطي كل رقم 06/01 مع احتمال المساواة، وهي 1/6. هذا ويشار إليها باسم توزيع موحدة (نسخة منفصلة من ذلك، خلافا ل النسخة مستمر). وهذا يعني أنه إذا X هو متغير عشوائي واصفا نتيجة لدور واحد ثم X~U[1,6] - يعني X يتم توزيعها بالتساوي على جميع النتائج الممكنة للفة يموت، من 1 إلى 6

وهذا يساوي اختيار رقم في [0,1) بينما تقسيمه إلى 6 أقسام: [0,1/6)، [1/6,2/6)، [2/6,3/6)، [3/6,4/6)، [4/6,5/6)، [5/6,1)

وأنت تطلب التوزيع المختلفة، والتي منحازة. أسهل طريقة لذلك هي تحقيق لتقسيم القسم [0,1) إلى 6 أجزاء اعتمادا على التحيز تريد. حتى في قضيتك هل تريد تقسيمه إلى ما يلي: [0,0.2)، [0.2,0.4)، [0.4,0.55)، 0.55,0.7)، [0.7,0.84)، [0.84,1).

إذا كنت تأخذ نظرة على ويكيبيديا دخول ، سترى أن في هذه الحالة، لن تتألف دالة الاحتمال التراكمي من 6 أجزاء متساوية طول بل من 6 أجزاء والتي تختلف في طول وفقا للانحياز <م> ما قدمتموه لهم. الشيء نفسه ينطبق على التوزيع الشامل.

عودة إلى السؤال، اعتمادا على اللغة التي تستخدم، فقط ترجمة هذا إلى لفة يموت الخاص بك. في بيثون، وهنا هو سطحية للغاية، وإن كان ذلك العمل، على سبيل المثال:

import random
sampleMassDist = (0.2, 0.1, 0.15, 0.15, 0.25, 0.15)

# assume sum of bias is 1
def roll(massDist):
    randRoll = random.random() # in [0,1)
    sum = 0
    result = 1
    for mass in massDist:
        sum += mass
        if randRoll < sum:
            return result
        result+=1

print roll(sampleMassDist)

نصائح أخرى

والمزيد من لغة الملحد، ولكن هل يمكن استخدام طاولة البحث.

استخدم رقم عشوائي في نطاق 0-1 والبحث عن القيمة في جدول:

0.00 - 0.20   1
0.20 - 0.40   2
0.40 - 0.55   3
0.55 - 0.70   4
0.70 - 0.84   5
0.84 - 1.00   6
import random

def roll(sides, bias_list):
    assert len(bias_list) == sides
    number = random.uniform(0, sum(bias_list))
    current = 0
    for i, bias in enumerate(bias_list):
        current += bias
        if number <= current:
            return i + 1

والتحيز سوف يكون متناسبا.

>>> print roll(6, (0.20, 0.20, 0.15, 0.15, 0.14, 0.16))
6
>>> print roll(6, (0.20, 0.20, 0.15, 0.15, 0.14, 0.16))
2

ويمكن استخدام الأعداد الصحيحة جدا (أفضل):

>>> print roll(6, (10, 1, 1, 1, 1, 1))
5
>>> print roll(6, (10, 1, 1, 1, 1, 1))
1
>>> print roll(6, (10, 1, 1, 1, 1, 1))
1
>>> print roll(6, (10, 5, 5, 10, 4, 8))
2
>>> print roll(6, (1,) * 6)
4

وانظر صفة ل وكر طريقة الملقب للحصول على الأشياء العشوائية مع probablities مختلفة.
على سبيل المثال، سلاسل A B C أو D مع احتمالات 0.1 0.2 0.3 0.4 -

abcd = dict( A=1, D=4, C=3, B=2 )
  # keys can be any immutables: 2d points, colors, atoms ...
wrand = Walkerrandom( abcd.values(), abcd.keys() )
wrand.random()  # each call -> "A" "B" "C" or "D"
                # fast: 1 randint(), 1 uniform(), table lookup

وهتافات
  - دينيس

مجرد اقتراح حل أكثر كفاءة (وpythonic3)، يمكن للمرء استخدام <لأ href = "http://docs.python.org/3.3/library/bisect.html#module-bisect" يختلط = "نوفولو" > تنصيف للبحث في ناقلات القيم المتراكمة - التي يمكن علاوة على ذلك أن precomputed وتخزينها على أمل أن المكالمات اللاحقة إلى وظيفة والرجوع إلى نفس "التحيز" (اتباع لغة السؤال)

from bisect import bisect
from itertools import accumulate
from random import uniform

def pick( amplitudes ):
    if pick.amplitudes != amplitudes:
        pick.dist = list( accumulate( amplitudes ) )
        pick.amplitudes = amplitudes
    return bisect( pick.dist, uniform( 0, pick.dist[ -1 ] ) )
pick.amplitudes = None

في غياب بيثون 3 تتراكم، يمكن للمرء أن مجرد كتابة حلقة بسيطة لحساب مجموع التراكمي.

from random import random
biases = [0.0,0.3,0.5,0.99]
coins = [1 if random()<bias else 0 for bias in biases]

ولقد خلق رمز للالقاموس إعطاء الحدث واحتمال المقابل، فإنه يعيد المفتاح المطابق أي حالة من هذا الاحتمال.

import random


def WeightedDie(Probabilities):   


    high_p = 0   
    rand = random.uniform(0,1)

    for j,i in Probabilities.items():
        high_p = high_p + i
        if rand< high_p:
            return j
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top