Domanda

I am trying to work out the probability of 'Susie' winning a match.

Probability of 'Susie' winning a game = 0.837
Probability of 'Bob' winning a game = 0.163

If the first person to win n games wins a match, what is the smallest value of n such that Susie has a better than 0.9 chance of winning the match?

So far I have this code:

import itertools

W = 0.837
L = 0.163
for product in itertools.product(['W','L'], repeat=3): #3=number of games
    print product

Which prints:

('W', 'W', 'W')
('W', 'W', 'L')
('W', 'L', 'W')
('W', 'L', 'L')
('L', 'W', 'W')
('L', 'W', 'L')
('L', 'L', 'W')
('L', 'L', 'L')

I then want to use these results to work out the probability of 'Susie' winning the match overall.

I have worked out this problem on paper, the more games played, the more chance there is of 'Susie' winning the match.

È stato utile?

Soluzione

You can use a dictionary for probabilities:

import itertools
import operator

probabilities = {'W':0.837, 'L':0.163}

for product in itertools.product(['W','L'], repeat=3): #3=number of games
    p = reduce(operator.mul,
               [probabilities[p] for p in product])
    print product, ":", p

The reduce function accumulates all elements of a list using function given in the first argument - here we accumulate them by multiplying.

This gives you probabilities of each event sequence. From this you can easily choose which one is "Susie winning a match", and sum the probabilities. One possibility to do this is:

import itertools
import operator

probabilities = {'W':0.837, 'L':0.163}

winProbability = 0
for product in itertools.product(['W','L'], repeat=3): #3=number of games
    p = reduce(operator.mul,
               [probabilities[p] for p in product])

    if product.count('W') > 1: #works only for 3 games
        winProbability += p
        print "Susie wins:", product, "with probability:", p
    else:
        print "Susie looses:", product, "with probability:", p

print "Total probability of Susie winning:", winProbability 

The condition works only for 3 games, but I'm really leaving this one to you - it's easy to generalize this for n games :)

Altri suggerimenti

You also need to loop over values of n. Also note that 'first to n' is the same as 'best out of 2n-1'. So we can say m = 2 * n - 1 and see who wins the most games of that set. max(set(product), key=product.count) is a short but opaque way of working out who won the most games. Also, why bother with representing the probabilities with strings and then using a dictionary to read them, when you can store the values in your tuples directly.

import itertools

pWin = 0 #the probability susie wins the match
n = 0
while pWin<0.9:
    n += 1
    m = 2 * n - 1
    pWin = 0
    for prod in itertools.product([0.837,0.163], repeat=m):
        #test who wins the match
        if max(set(prod), key=prod.count) == 0.837:
            pWin += reduce(lambda total,current: total * current, prod)
print '{} probability that Susie wins the match, with {} games'.format(pWin, n)

I was intrigued by @desired_login's point, but thought I'd try calculating the permutations instead of iterating through them:

import sys
if sys.hexversion >= 0x3000000:
    rng = range     # Python 3.x
else:
    rng = xrange    # Python 2.x

def P(n, k):
    """
    Calculate permutations of (n choose k) items
    """
    if 2*k > n:
        k = n - k
    res = 1
    for i in rng(k):
        res = res * (n-i) // (i+1)
    return res

Ps = 0.837    # Probability of Susie winning one match
Px = 0.980    # Target probability

# Probability of Susie winning exactly k of n matches
win_k         = lambda n,k: P(n, k) * Ps**k * (1.0-Ps)**(n-k)
# Probability of Susie winning k or more of n matches
win_k_or_more = lambda n,k: sum(win_k(n, i) for i in rng(k, n+1))

def main():
    # Find lowest k such that the probability of Susie winning k or more of 2*k - 1 matches is at least Px
    k = 0
    while True:
        k += 1
        n = 2*k - 1
        prob = win_k_or_more(n, k)
        print('Susie wins {} or more of {} matches: {}'.format(k, n, prob))
        if prob >= Px:
            print('At first to {} wins, Susie has >= {} chance of winning the match.'.format(k, Px))
            break

if __name__=="__main__":
    main()

For Px=0.98, this results in

Susie wins 1 or more of 1 matches: 0.837
Susie wins 2 or more of 3 matches: 0.9289544940000001
Susie wins 3 or more of 5 matches: 0.9665908247127419
Susie wins 4 or more of 7 matches: 0.9837066988309756
At first to 4 wins, Susie has >= 0.98 chance of winning the match.

Runtime is something like O(n^3) for this algorithm, as opposed to O(2^n) for the others.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top