'Random-generate tuples according to probability function
I have a probability density distribution function for the angle combination (theta, phi). Theta and phi can take 360 and 180 values respectively, resulting in a total of 64800 elements, each one with its own specific probability. Is there a way in python to generate random numbers for a 2D n-tuple, as they are generated in random.choices(list, probabilities) for a list?
Solution 1:[1]
Even if the approach mentioned in jonrsharpe's comment, seems somewhat inelegant at first glance,
[…] create the lists of tuples
(theta, phi)and their probabilities and userandom.choicesdirectly […]
it is surprisingly fast, so that I wouldn't expect “a more pythonic way” to do this.
The following example shows a probability distribution that is easier to grasp:
import random
# Model two dice that fall so that their number of points (a,b) is
# always close to each other. The approach taken is to subtract the
# difference of points from the possible maximum (5=6-1).
def make_dice_choices():
# individual probabilities (rows and columns show a die each):
#
# | 1 2 3 4 5 6
# --+------------
# 1 | 5 4 3 2 1 0
# 2 | 4 5 4 3 2 1
# 3 | 3 4 5 4 3 2
# 4 | 2 3 4 5 4 3
# 5 | 1 2 3 4 5 4
# 6 | 0 1 2 3 4 5
def probability(a, b):
return 5-abs(a-b)
population=[]
weights=[]
for a in range(1,7):
for b in range(1,7):
population.append((a, b))
weights.append(probability(a, b))
# We derive a function from the original function to which
# two parameters are already bound.
return lambda k: random.choices(population, weights, k=k)
# Create samples following the given probability. Scaling the
# sum (110=30+40+24+12+4) of all probabilities in the table, we
# can observe the balancing effect of the law of large numbers [1]
# in our actual results. (We expect no couccurences of 1 and 6)
# [1] https://en.wikipedia.org/wiki/Law_of_large_numbers
def experiment():
dice_choices = make_dice_choices()
for scale in (1, 10, 100, 1000):
roll_count = 110*scale
rolls = dice_choices(roll_count)
# Quick "analysis" of results
roll_delta = {}
for r in rolls:
k = abs(r[0]-r[1])
roll_delta[k] = roll_delta.get(k, 0)+1
print(f'delta: rolls (of {roll_count})')
for k in sorted(roll_delta.keys()):
print(f'{k:5}: {roll_delta[k]}')
experiment()
Here is a sample output of above script:
delta: rolls (of 110)
0: 32
1: 41
2: 18
3: 14
4: 5
delta: rolls (of 1100)
0: 293
1: 416
2: 235
3: 117
4: 39
delta: rolls (of 11000)
0: 2947
1: 3997
2: 2499
3: 1167
4: 390
delta: rolls (of 110000)
0: 30146
1: 39766
2: 23967
3: 12032
4: 4089
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
