0
$\begingroup$

I'm trying to build a simulation for this question:

"There are 50 cards of 5 different colors. Each color has cards numbered between 1 to 10. You pick 2 cards at random. What is the probability that they are not of same color and also not of same number?"

(From Glassdoor)

I should have a result like "73%" but with my code I get (consistently) "72%" or "71.8%".

Here is my code:

import numpy as np

# Building a deck of 10 cards for each of the 5 colors 
cards = np.array([c+str(n) for c in ("A", "B", "C", "D", "E") for n in range(1, 11)])

def random_cards_differ():
"""Returns True if two random cards differ"""
    a, b = np.random.choice(cards, 2, replace=False)
    if a[0] != b[0] and a[1] != b[1]:
        return True
    else:
        return False

nb_success = 0
nb_tries = 100000

for i in range(nb_tries):
    if random_cards_differ():
        nb_success += 1

print(nb_success / nb_tries)
>>> 0.71892

Is this normal? Is there a mistake in my code or is it a "random gotcha" caused by some seed or something else?

$\endgroup$
4
  • $\begingroup$ your code seems fine, the theoretical result 73% is supposed to be accurately reached when numtrials -> infinity, so you get pretty good results. Try running whole simulation 100 times (so 100 * 100000 draws) and get average of 100 simulations this is better estimator $\endgroup$ – Nikos M. Jul 28 '20 at 13:29
  • $\begingroup$ Well I ran a lot of simulations and got the same result. If I got 72% then 74% I would not suspect a problem, but consistently getting 71.8% instead of 73% seemed weird. Indeed, @bogovicj found the mistake in my code $\endgroup$ – Be Chiller Too Jul 28 '20 at 15:03
  • 1
    $\begingroup$ Yeap, missed that detail. Good catch! In fact creating string tuples and comparing substrings is a bad idea, This is perfect candidate for tuples, if you encoded cards as tuples it would save you a lot of trouble $\endgroup$ – Nikos M. Jul 28 '20 at 17:03
  • $\begingroup$ I agree 100%, I initially tried np.array([(c, n) for ...]) but np.random.choice wanted 1D arrays, so I used a quick solution, that led to my bug. $\endgroup$ – Be Chiller Too Jul 29 '20 at 9:04
2
$\begingroup$

There's an error in your code:

cards = np.array([c+str(n) for c in ("A", "B", "C", "D", "E") for n in range(1, 11)])

will produce "A10" and "A1" among other values, and

if a[0] != b[0] and a[1] != b[1]:

will return true when a=A10 and b=A1, for example. This is why you're probably consistently underestimating the number of differences.

An easy fix would be to use:

cards = np.array([c+str(n) for c in ("A", "B", "C", "D", "E") for n in range(0, 10)])

instead, which is more readable anyway. But if I were doing this, I might use itertools.product.

Even after this fix it's normal to not always get exactly the theoretical value, but it's bad if there's a bias (i.e. consistent under- or over- estimation).

$\endgroup$
1
  • $\begingroup$ Thanks a lot! Indeed I was not expecting the exact theoretical value, but getting the same precise result which was different from the expected result seemed off, thanks for noticing the bug! $\endgroup$ – Be Chiller Too Jul 28 '20 at 15:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.