#!/usr/bin/python3
# ====================================================================
# Generate random numbers with a given (numerical) distribution
# from: https://stackoverflow.com/questions/4265988/
# generate-random-numbers-with-a-given-numerical-distribution
# ====================================================================
# The optional keyword-only argument k allows one to request more
# than one sample at once. This is valuable because there is some
# preparatory work that random.choices has to do every time it is
# called, prior to generating any samples; by generating many samples
# at once, we only have to do that preparatory work once. Here we
# generate a million samples, and use collections.Counter to check
# that the distribution we get roughly matches the weights we gave.
#
# from random import choices
# population = [1, 2, 3, 4, 5, 6]
# weights = [0.1, 0.05, 0.05, 0.2, 0.4, 0.2]
# million_samples = choices(population, weights, k=10**6)
# from collections import Counter
# Counter(million_samples)
# Counter({5: 399616, 6: 200387, 4: 200117, 1: 99636,
# 3: 50219, 2: 50025})
# ====================================================================
import sys
from random import choices
population = [0,1,2,3,4,5,6,7,8,9]
weights = [1,2,3,4,3,3,4,3,2,1]
wtotal = 0
for w in weights:
wtotal += w
print(f'total-weights = {wtotal}')
# ---- collect a sample of the population based on weights distribution
total = 0
counts = [0 for _ in range(len(population))]
for _ in range(10000):
x = choices(population,weights)
if len(x) > 1:
print('choices returned more that one value')
sys.exit()
total += 1
counts[x[0]] += 1
# ---- display sample counts, etc.
print(f'total = {total}')
print(f'counts = {counts}')
print()
print(' idx weight sample')
for i,c in enumerate(counts):
print(f'[{i:2}] ({float(weights[i]/wtotal):<7.4}) {float(c/total):<6.4}')