Suraj Kothari
Suraj Kothari

Reputation: 1632

Better approach to calculating probablity - Python

I would like help in finding a better approach to making my probabilty of dice program.

Here is all my code:

import random,collections

probabiltyOfDice = {}
rolls = 100

#Counters
counter1 = 0
counter2 = 0
counter3 = 0
counter4 = 0
counter5 = 0
counter6 = 0

for x in range(rolls):
    output = random.randint(1,6)
    if output == 1:
        counter1 += 1
        probabiltyOfDice[1] = counter1
    elif output == 2:
        counter2 += 1
        probabiltyOfDice[2] = counter2
    elif output == 3:
        counter3 += 1
        probabiltyOfDice[3] = counter3
    elif output == 4:
        counter4 += 1
        probabiltyOfDice[4] = counter4
    elif output == 5:
        counter5 += 1
        probabiltyOfDice[5] = counter5
    elif output == 6:
        counter6 += 1
        probabiltyOfDice[6] = counter6

ordered = collections.OrderedDict(sorted(probabiltyOfDice.items()))
print(ordered)

My approach works and here is the output if the constant number of rolls is set to 100:

OrderedDict([(1, 15), (2, 16), (3, 14), (4, 22), (5, 21), (6, 12)])

The OrderedDict displays the dice number and along with it how many times that number appeared. I am able to work this out by using 6 counter variables and using a set of if-elif statements.


I am using the collections library for ordering the dictionary for displaying. But I would like it if someone could show me a better way of tackling this problem.

Clearly using 6 variables and many if statements might be a long-winded approach to this situation.

Upvotes: 1

Views: 75

Answers (2)

serkef
serkef

Reputation: 319

So, python has a very convenient dictionary subclass called Counter, that in essence, is very fast at calculating counts. I crafted the following:

import random
from collections import Counter

prob = Counter([random.randint(1,6) for _ in range(10000)])

print(prob)
>> Counter({1: 1650, 2: 1750, 3: 1679, 4: 1546, 5: 1686, 6: 1689})

Now, the problem with that is that it can only work up to a reasonable large range. So, in order to avoid creating an intermediate list, we can have the following: import random from collections import Counter

prob = Counter()

for _ in range(10000000):
   prob[random.randint(1,6)] += 1

print(prob)
>> Counter({1: 13084052,
     2: 13087518,
     3: 13090177,
     4: 13086193,
     5: 13081778,
     6: 13085341})

edit: Adding a third version, which is basically the first, giving up the intermediate list for the much more convenient generator, as @Mark Dickinson suggested:

import random
from collections import Counter

prob = Counter(random.randint(1,6) for _ in range(1000000))

print(prob)
>> Counter({1: 166503, 2: 166833, 3: 166531, 4: 166681, 5: 166846, 6: 166606})

Upvotes: 2

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476659

We can simplify the code by using a list. Here the list contains six elements, initially all set to zero:

import random, collections

rolls = 100

#Counters
counters = [0] * 6

for x in range(rolls):
    output = random.randint(1,6)
    counters[output-1] += 1

ordered = collections.OrderedDict(enumerate(counters, 1))
print(ordered)

For a run, it prints on my machine:

>>> print(ordered)
OrderedDict([(0, 12), (1, 11), (2, 17), (3, 31), (4, 14), (5, 15)])

We can slighly improve the efficiency of the code by generating a number between 0 and 5 (both inclusive):

rolls = 100

#Counters
counters = [0] * 6

for x in range(rolls):
    output = random.randint(0, 5)
    counters[output] += 1

ordered = collections.OrderedDict(enumerate(counters, 1))
print(ordered)

Upvotes: 2

Related Questions