Probability calculator, tests

Probability calculator, second test

General

Jun 12

1 / 1

Jun 12

8m ago

Beatrix

8m

Hello everyone, I am currently doing the probability calculator challenge and cannot pass the second and third tests. Whilst I already have an idea of what is wrong in my code for the third test after reading posts from other people, I still am not sure why I am failing the second test, and any help would be appreciated. Many thanks!
Here is my code and below I have copied the text displayed by the failed second unit test:

""" This is a probability calculator. It has a Hat class that takes a number of arguments that
 specify the number of balls of each colour that are in the hat, and a draw method that randomly
 draws a number of balls WITHOUT REPLACEMENT.
There is then an experiment class that returns the probability of drawing balls of a  specific colour
if we repeat the experiment a specified number of times"""

import random
import copy

class Hat:

    """ This clas defines the Hat for whoch balls can be placed in, and a method to draw them """

    def __init__(self, **kwargs):
        self.hat = kwargs
        self.contents = []
        ball_colour_freq = kwargs.values()
        self.total_balls = sum(ball_colour_freq)
        for key, value in kwargs.items(): 
          for i in range(value):
            self.contents.append(key)


    def draw(self, balls_to_be_drawn):

        """ This is function that randomly draws a specified number of balls
        (called balls_to_be_drawn) from the hat."""

        self.balls_to_be_drawn = balls_to_be_drawn
        drawn = dict.fromkeys(self.hat.keys(), 0)
        for i in range(balls_to_be_drawn):
            # drawing a random ball
            ball_drawn = random.choice(list(self.hat))
            self.hat[ball_drawn] = - 1
            drawn[ball_drawn] = + 1
        drew = list(drawn.keys())
        return drew

   

def experiment(hat, expected_balls, num_balls_drawn, num_experiments):
#must usee copy hat in here
    """ a function that returns the probability of drawing certain types of balls over
    n experiments"""

    match = 0
    balls_drawn_in_experiment_set = set(hat.draw(num_balls_drawn))
    expected_balls_set = set(expected_balls.keys())
    expected_balls_set = set(expected_balls.keys())
    for i in range(num_experiments):
        copy.deepcopy(hat)
        if set(balls_drawn_in_experiment_set).intersection(set(expected_balls_set)) != 0:
          match = + 1
          
    copy.deepcopy(hat)
    probability = match / num_experiments
    return probability

Traceback (most recent call last):
File “/home/runner/boilerplate-probability-calculator-5/test_module.py”, line 16, in test_hat_draw
self.assertEqual(actual, expected, ‘Expected hat draw to return two random items from hat contents.’)
AssertionError: Lists differ: [‘red’, ‘blue’] != [‘blue’, ‘red’]

First differing element 0:
‘red’
‘blue’

  • [‘red’, ‘blue’]

  • [‘blue’, ‘red’] : Expected hat draw to return two random items from hat contents.

In your __init__(), you have the hat contents stored as a list in contents and a dict in hat and you use hat in your draw() method. Then to draw, you are doing

I don’t think you mean to assign -1 and +1 here; it looks like you mean to decrement/increment. Regardless, you are now using a list version of hat when you have that already, in self.contents. Use random.choice() on self.contents, remove the ball from there, and add it to drew. I’m not sure that selecting from a dict turned into a list will yield the expected results for the test anyway. It might, but I didn’t test it since you already have a list available.

Your probability is low because you are not copying the hat correctly in the experiment. Have a quick look at the python docs for the copy module and you’ll see why.

Also, your draw() method allows you to draw more balls than are available in the hat, so you will need to fix that too to pass all the experiment tests.

thank you, I modified the code to follow the first part of your advice. Here it is now, and it passes the second test, so i think i will leave it at that.
I will definitely look into using the copy method better.

 def draw(self, balls_to_be_drawn):

        """ This is a function that randomly draws a specified number of balls
        (called balls_to_be_drawn) out of the hat."""
        drew_balls = list()
        self.balls_to_be_drawn = balls_to_be_drawn
        for i in range(balls_to_be_drawn):
            # drawing a random ball
            ball_drawn = random.choice(list(self.contents))
            self.contents.remove(ball_drawn)
            drew_balls.append(ball_drawn)
            drew_balls.sort()
        return drew_balls

I am not sure I understand the last part of your advice… Because the number of balls that need to be drawn (num_balls_drawn) out of the hat at for each draw will always be smaller than the number of balls present in the hat.

So provided that the hat is refilled at the end of each iteration of the experiment ( i still need to figure out where to put the deepcopy method to achieve that), the balls in the hat will never run out and be less than the number of balls that need to be drawn, right?

Nope. The second part of the test_prob_experiment() test tests this explicitly. It creates a hat with 19 balls and draws 20.

copy.deepcopy() returns a copy. You’re calling it without assigning the return value to anything. So you’re making a copy but not using it.