0

Essential, what i have is a list like this: Thislist = [20, 34, 46]

And i want it so when randomly picking a number, the first number will have a 20% chance of being picked, the 2nd number will have a 34% chance of being picked, and the 3rd number will have a 46% chance of being picked.

  • Do you want the number chosen to be one of the set `{20, 34, 46}`, or is that list just the weightings you want applied to some *other* list? In other words, do you want to choose a number from, for example, `[1, 2, 3]` with percentage weightings `[20, 34, 46]`? And what do you want to do if the weightings don't add to 100? – paxdiablo May 09 '21 at 06:28
  • sorry, some clarification, you must assume that the list will always be different, and of different lengths. – Scott Pickslay May 09 '21 at 06:30
  • 1
    {20, 34, 46} should we the weightings for [20, 34, 46], also i have math in-place to assure that it adds to 100 – Scott Pickslay May 09 '21 at 06:31
  • Okay, I'm struggling to think of a use case for it but at least I understand now :-) – paxdiablo May 09 '21 at 06:32
  • for anyone wondering what i am working on, i am working on something like this: https://www.youtube.com/watch?v=9zfeTw-uFCw but, the problem has been solved, hanks! – Scott Pickslay May 09 '21 at 06:44
  • Does this answer your question? [A weighted version of random.choice](https://stackoverflow.com/questions/3679694/a-weighted-version-of-random-choice) – Peter O. May 10 '21 at 02:07

3 Answers3

2

You can make use of random.choices()

Example

import random
    
num = [20, 34, 46]
for i in range(10):
    item = random.choices(num,num)
    print("Iteration:", i, "Weighted Random choice is", item[0])

Reference: https://docs.python.org/3/library/random.html#random.choices

Tharun K
  • 1,160
  • 1
  • 7
  • 20
  • 2
    Why duplicate the list? You could just do `random.choices(num, num)` to use the same list for both arguments. (`k` defaults to 1.) – Samwise May 09 '21 at 06:22
  • because the OP just gave an example list, the list need not be the weights as it's elements – Tharun K May 09 '21 at 06:25
  • Nick, I understand what you and Sam are trying to tell me, but what if the list was not the weights, Ex: what if the list was `num = [1,2,3,4,5,6]` and the probabilities were `weights = (10,20,30,10,10,20)` – Tharun K May 09 '21 at 06:35
  • Tharun, based on comments added to the question in response to my query, it looks like the list and weights *are* always the same. – paxdiablo May 09 '21 at 06:35
  • oh right, the comments weren't there when I answered this – Tharun K May 09 '21 at 06:36
  • It's right in the title of the question that the list itself is the percent chance of each item being picked. – Samwise May 09 '21 at 16:17
2

As long as the numbers are integers adding to 100 then probably the simplest way to do this is to create a list which has each number repeated that many times in it, and then take a random choice from that list.

import random

Thislist = [20, 34, 46]
l = [n for v in Thislist for n in [v] * v]
print(random.choice(l))

Example test code:

res = {}
for _ in range(1000000):
    c = random.choice(l)
    res[c] = res.get(c, 0) + 1
    
print(res)

Sample output:

{46: 459771, 20: 200242, 34: 339987}

A note about performance.

There is obviously a setup cost here in forming the list l. If there are only to be a few selections from made from the list, @TharunK's answer is more efficient. However beyond that small number, random.choice is enough faster (~4x from my testing) than random.choices to make this solution far more efficient.

Nick
  • 138,499
  • 22
  • 57
  • 95
  • i am going to test this, brb – Scott Pickslay May 09 '21 at 06:36
  • @Scott, I think that's okay, it just creates a flattened list with twenty 20's, thirty-four 34s and so on. – paxdiablo May 09 '21 at 06:37
  • There's probably a better way than possibly constructing a massive list from, say, `[12345, 67890, 99999999999999]` but, since OP stated it would sum to a hundred, that's not a concern here. – paxdiablo May 09 '21 at 06:42
  • @paxdiablo yeah, I think in that situation Tharun's answer would work better – Nick May 09 '21 at 06:44
  • The answer of Tharun is the actual correct one. The point is, you can generate from ANY (positive) distribution (it does not matter to what it adds up). You first have to divide each entry by the total integral (and eventually bin width) then you get a normalized (to one) PDF (probability density function). You can get the CDF (cumulative density function) by CDF(y)=integrate(-inf,y) PDF(x) dx, then generate a uniform random number R in (0,1] and get the correct number from the inverse CDF: x_random = CDF^{-1} (R). random.choices() is doing this for you. – Ralf Ulrich May 09 '21 at 06:55
  • @RalfUlrich that's fine, you can suggest to Scott that he should accept that answer. This answer isn't incorrect though given OPs requirements (where the sum of the numbers in the list is 100). – Nick May 09 '21 at 06:58
  • @RalfUlrich note also that after setting up the selection list, this is 3-4x faster than using random.choices so if OP has to make a lot of choices this will save significant time. – Nick May 09 '21 at 07:08
  • All right. I take back the downvote, but from the question answered the solution is not necessarily the best since it is just for very specific set of problems. Since I believe future users of stackoverflow use the votes to look for answers I wanted to help them by changing the votes. Maybe, in addition to taking my downvote back, some of you guys also upvote the other answer?? – Ralf Ulrich May 09 '21 at 17:01
  • Sorry, I cannot change my vote... only if the answer would become edited once more. – Ralf Ulrich May 09 '21 at 17:02
  • @RalfUlrich I edited the answer to make a note about performance. And I've done as you asked. – Nick May 09 '21 at 23:24
0

Here is an example

import random
Thislist = [num for n in [[20]*20,[34]*34,[46]*46] for num in n]
print(random.choice(Thislist))
Buddy Bob
  • 5,829
  • 1
  • 13
  • 44
  • 1
    @Dion regardless, in general you shouldn't edit other people's answers, especially not to add code. In that case you ought to add your own answer. See https://meta.stackoverflow.com/questions/260245/when-should-i-make-edits-to-code – Nick May 09 '21 at 06:37
  • @Nick sorry, will be mindful from now on. – Dion May 09 '21 at 06:38