Conditional Probabilities, Seattle Rain, And Tricky Friends | by Tony Yiu | Towards Data Science

My least favorite kind of data science interview question is probability. It’s just not something that I think about everyday, so the probability muscles always feel super rusty whenever I am forced to exercise them. But if you are hunting for a data job, it’s inevitable that you will run into one at some point — so let’s keep our probability skills fresh with some practice. As usual, we will use simulation (and Python code) to better visualize what’s going on.
You’re headed to Seattle. You want to know if you should bring an umbrella so you call 3 random friends who live there and ask each independently whether it’s raining or not. Each friend has a 2/3 chance of telling you the truth and a 1/3 chance of lying (so mean!). All 3 friends tell you “Yes, it’s raining”. What is the probability that it’s actually raining in Seattle?
The first time I saw this problem, I thought “only if all 3 of my friends lied to me then it would mean it’s not raining in Seattle”. Because as long as one of my friends was not lying, then one of the yeses would be true (implying rain).
probability rain = 1 - probability all lying= 1 - (1/3)^3 = 0.963
But then I thought this seems too simple. How could this question gain such notoriety if it was this simple. Sadly my instincts were right and this question is more complicated than meets the eye.
My previous approach ignored the given condition. What condition you ask? The interviewer told us that all 3 of our friends answered yes. That’s relevant information that needs to be factored into our solution.
To see why, imagine that it’s raining in Seattle. Our friends answered [yes, yes, yes] when we asked them whether it was raining. Let’s think through the possible outcomes in this state of the world. If they all told the truth, then that is consistent with the world state that we’re in (because it IS raining in Seattle).
What if they all lied? That’s impossible. In a state of the world where it is raining, our friends can’t have answered “yes” and lied (to lie, they would have had to have replied “no”). Is it possible that just one of them lied? That’s not possible either — all of them said “yes” and to lie in the state of the world where it’s raining requires a “no”. So the only possible result if it IS raining in Seattle is that our friends are all telling the truth.
Now imagine that it’s sunny in Seattle. We can perform the same exercise to figure out what’s possible in this world state. If it’s sunny, then that must mean all 3 of our friends lied to us. That’s the only possibility! Because in the sunny state of the world, our friends would have had to respond “no, it’s not raining” in order to be telling the truth. And none of them said that.
So there are only two possibilities:
World state = it is raining:[yes,yes,yes] = [truth,truth,truth] = raining                [lie,lie,lie] = impossible                [lie,lie,truth] = impossible                [lie,truth,truth] = impossible                [lie,truth,lie] = impossible                [truth,truth,lie] = impossible                [truth,lie,lie] = impossible                [truth,lie,truth] = impossibleWorld state = it is not raining:[yes,yes,yes] = [truth,truth,truth] = impossible                [lie,lie,lie] = not raining                [lie,lie,truth] = impossible                [lie,truth,truth] = impossible                [lie,truth,lie] = impossible                [truth,truth,lie] = impossible                [truth,lie,lie] = impossible                [truth,lie,truth] = impossible
Basically, if it’s raining, they must all be telling the truth. And if it’s not, they must all be lying. These are the only possibilities given the condition that all 3 of our friends said yes.
Thus, we are estimating a conditional probability:
Prob(rain | [yes,yes,yes])Which is read as probability of rain given that the responses were yes, yes, and yes].
We could bust out Bayes’ Theorem here, but I prefer a more intuitive and in depth approach so that we can truly grasp what’s going on.
Let’s write up some code to simulate this brainteaser. I’ve put some comments in the code to describe how it works and my thought process. But let’s quickly run through it as well.
We will run 100,000 simulations. We also need to specify the probability of rain. That seems odd, right? Aren’t we trying to estimate the probability of rain? No, actually we’re estimating the probability of rain given that our friends all said “yes, it’s raining”. And in order to do that, we need to model the two possible states of the world (raining or not raining). We can do so with a coin flip like random variable (uniform distribution between 0 and 1) — if the random variable, rain, is less than prob_rain, then it is raining in our simulation.
Next we simulate the responses of our 3 friends in the same way — if any of the 3 random variables in responses is greater than 2/3, then that specific friend lied to us (since they have 2/3 chance of telling the truth and 1/3 of lying).
We have 3 counter variables to keep track of the outcomes that we care about:
times_rained_3yes keeps track of the number of times it rained and our friends all told the truth and said “yes, it’s raining”.times_dry_3yes keeps track of the number of times it did not rain and our friends all lied and said “yes, it’s raining”.times_rained keeps track of the number of times in our simulation that it rained (roughly 50% of the time since we set prob_rain = 0.5).
times_rained_3yes keeps track of the number of times it rained and our friends all told the truth and said “yes, it’s raining”.
times_dry_3yes keeps track of the number of times it did not rain and our friends all lied and said “yes, it’s raining”.
times_rained keeps track of the number of times in our simulation that it rained (roughly 50% of the time since we set prob_rain = 0.5).
# Inputssims = 100000prob_rain = 0.50# Counter variables to tally the simulation outcomestimes_rained_3yes = 0times_dry_3yes = 0times_rained = 0# Loop that runs the simulationsfor i in range(sims):       # Random variable to simulte whether it rains or not    rain = np.random.random()        # Raining Case    if rain < prob_rain:        # If it is raining, increment counter        times_rained += 1        # Random variables to simulate whether friends lie        responses = [np.random.random(),                     np.random.random(),                     np.random.random()]        # Tally the number of lies        lies = sum([1 for i in responses if i > 2/3])                # If sum(lies) == 0, then all truth        if lies == 0:            # This is outcome we are looking for, where the            # world state = RAINING and all friends tell truth            times_rained_3yes += 1        # Not Raining Case    else:            # Random variables to simulate whether friends lie        responses = [np.random.random(),                     np.random.random(),                     np.random.random()]        # Tally the number of lies        lies = sum([1 for i in responses if i > 2/3])                # If sum(lies) == 3, then all lies        if lies == 3:            # This is outcome we are looking for, where the            # world state = DRY and all friends lie            times_dry_3yes += 1
After running the simulation, we can use our counter variables to calculate the probabilities we are interested in.
sims = 100,000times_rained = 49,990times_rained_3yes = 14,852times_dry_3yes = 1,889
So it rains around 50% of the time (since we set it up that way). And when it does rain, our friends tell the truth about 29% (14,852/49,990) of the time — (2/3)3 = 0.295. And when it’s not raining, all 3 of our friends lie to us 3.77% (1,889/50,010) of the time — (1/3)3 = 0.037, slight difference due to simulation noise.
We now have all the numbers we need to solve the problem! Can you see how? Let’s think back to our problem — we want to know the probability that it is raining when all 3 of our friends say “yes, it’s raining”. So the numerator of our probability calculation should be a count of the times it rained and all said yes. And the denominator should be the number of times that all of our friends replied yes in all states of the world (there are only 2 states — rain and not rain).
Numerator = times_rained_3yes = 14,852Denominator = number of times our friends said 3 yeses            = times_rained_3yes + times_dry_3yes            = 14,852 + 1,889 = 16,741The Answer = 14,852 / 16,741 = 0.888
So given the responses of our friends, there is an 89% chance that it’s raining in Seattle (definitely bring an umbrella).
We can also solve for this analytically as follows:
The numerator is the joint probability of 3 yeses and rain. Since they are independent events, we can just multiply the probability of 3 truths (since answering yes when it’s raining equals to telling the truth) with the probability of rain.
The denominator is the probability of 3 yeses. We can calculate this by recognizing that 3 yeses can only result from 2 cases: either 3 truths when it’s raining or 3 lies when it’s not raining. We already have the first probability (it’s our numerator). We can calculate the second one (3 lies when it’s not raining) in the same way — by multiplying the probability of 3 lies with the probability of not raining. Finally we sum the probabilities of our 2 cases to get the probability of 3 yeses.
Numerator = Prob. 3 Truths * Prob. Rain  = (2/3)^3 * (1/2)Denominator = Prob. 3 Yeses = (Prob. 3 Truths * Prob. Rain) + (Prob. 3 Lies * (1 - Prob. Rain)) = (2/3)^3 * (1/2) + (1/3)^3 * (1/2)Plugging into Python:(2/3)**3*(1/2) /((2/3)**3*(1/2) + (1/3)**3*(1/2))We get:0.888
Finally, it’s important to note that the answer varies based on our estimate of the probability of rain (which we previously set to 0.5). This makes sense — regardless of our friend’s responses, our prior assumption of the probability of rain is still important. Our friends’ responses modify our starting prior assumption but they do not override it. For example, if we were heading to Las Vegas instead of Seattle, even with 3 “yes, it’s raining” responses, we could probably get away with not bringing an umbrella. The following plot shows how our assumption about the probability of rain (the prob_rain variable in my code) changes our answer:
And that’s all for today folks! Good luck with interviews and all things data science. Cheers!