Skip to content

Instantly share code, notes, and snippets.

@gerryjenkinslb
Last active June 27, 2018 22:53
Show Gist options
  • Save gerryjenkinslb/c9c0b5184cc076af3f7cb9ee0ba3f1b1 to your computer and use it in GitHub Desktop.
Save gerryjenkinslb/c9c0b5184cc076af3f7cb9ee0ba3f1b1 to your computer and use it in GitHub Desktop.
Python code to create random events where the events have different probabilites specified by a frequence table.
import random
""" Create random events where event probabilities are
set by a frequency list
This shows two functional approaches, the second being more terse
and then a object oriented approach"""
# functional approach using a closure
# setup: x = event_gen(freq_table)
# get sample: x() -> sample index
def event_gen(freq_table):
n = len(freq_table)
cumulative_frequency = []
total = 0.0
for p in freq_table: # build cumlative frequencies
total += p
cumulative_frequency.append(total)
def event_f():
r = random.uniform(0, total) # between 0.0 and total
for i in range(n):
if cumulative_frequency[i] >= r: # find interval
return i
return event_f
# functional approach using a closure
# and generators/list comprehensions
# setup: x = event_gen2(freq_table)
# get sample: x() -> sample index
def event_gen2(freq_table):
cumulative_frequency = [sum(freq_table[:i+1])
for i in range(len(freq_table))] # terse but O(n squared)
def event_i():
r = random.uniform(0, cumulative_frequency[-1])
return next((i for i, t
in enumerate(cumulative_frequency) if t >= r))
# return function that returns random sample index of event
return event_i
# Object Oriented approach
# setup: x = Event_gen(freq_table) # create object
# get sample: x() -> sample index
class EventGen(object):
def __init__(self, freq_table):
n = len(freq_table)
self.cumulative_frequency = []
total = 0.0
for p in freq_table:
total += p
self.cumulative_frequency.append(total)
def __call__(self): # allows us to 'call' object
r = random.uniform(0, self.cumulative_frequency[-1])
i = next((i for i, t in
enumerate(self.cumulative_frequency) if t >= r))
return i
def test():
# function/class test label
tests = ( (event_gen, 'event_gen functional case'),
(event_gen2,'event_gen2 functional case'),
(EventGen, 'EventGen OOP case'),
)
# simulate events for a game at sea
freq_table = (20, 3, 1, 5, 2, 1)
events = ('calm day', 'storm', 'alien',
'pirate', 'land', 'sea monster')
n = 1000000 # run n samples
for gen, label in tests: # run each case
sample = gen(freq_table) # get sampler function function
hist = {e: 0 for e in events} # histogram will be built
for _ in range(n):
hist[events[sample()]] += 1 # add 1 to historgram bucket
total = sum(freq_table)
print(label)
for event in hist.keys():
print(f"{event:11s} {hist[event]:6d} "
f"{hist[event]*total/n:5.2f}")
print()
if __name__ == '__main__':
test()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment