Probability Calculator (Failure in 3rd test)

Hello guys, I have been working on the Prob. Calculator for the past weeks (stopped to enjoy christmas and jumped back into it today) and I had some issues with replit (Some questions on the forum helped me advance a little bit, but I’m still getting issues with the final test.

Thanks in advance for your replies.

Here’s the error message:

======================================================================
FAIL: test_prob_experiment (test_module.UnitTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/boilerplate-probability-calculator-1/test_module.py", line 27, in test_prob_experiment
    self.assertAlmostEqual(actual, expected, delta = 0.01, msg = 'Expected experiment method to return a different probability.')
AssertionError: 1.0 != 0.272 within 0.01 delta (0.728 difference) : Expected experiment method to return a different probability.

----------------------------------------------------------------------
Ran 3 tests in 0.003s

FAILED (failures=1)
 

And here’s my code:

import copy
import random


class Hat:
      def __init__(self, **kwargs):        
        self.contents = []   
        self.total_number_balls = sum( kwargs.values())
        self.list_keys = list(kwargs.keys())
        self.dict = dict(kwargs)
        for keys in kwargs:
            num_balls = kwargs[keys]
            colour_name = keys
            for balls in range(num_balls):
                self.contents.append(colour_name) 
         
    
      def draw (self,num_balls):
        #_______Remove balls at random from the hat       
        Total_quantity = self.total_number_balls
        content_copy = self.contents.copy()        
        content_copy_length = len(content_copy)
        random_balls_list = []

        for draws in range(num_balls):
          ball_drawn = random.choice(content_copy)                        
          random_balls_list.append(ball_drawn)
          self.contents.remove(ball_drawn)
          if num_balls > content_copy_length:
            self.contents.append(ball_drawn) 
          
          
        return random_balls_list

def experiment (hat,num_balls_drawn,num_experiments,expected_balls):
# def experiment (hat=None,num_balls_drawn=None,num_experiments=None,expected_balls=None):
    event = 0
    total_trials =0
    for trials in range(num_experiments):
              
        for keys,values in hat.dict.items(): 
            for keys2,values2 in expected_balls.items():
              if keys ==keys2 and values >= values2:
                total_trials +=1
        if total_trials >= len(expected_balls):
          total_trials = 0
          event += 1          
        else:
          total_trials = 0
      
    
    return event / num_experiments
1 Like

I don’t see where you’re drawing balls from the hat for the experiment. It appears that you are comparing the initial set of balls with a subset that should be drawn, which should always succeed unless you are looking for balls not present in the original set. Since your probability is 1, that means every trial is a success, which is wrong in most cases. For your experiment code, the easiest way to debug is to log the expected balls, the drawn balls, and whether the draw was successful or not and find the misclassified experiments.

Second, I’m not sure your draw() method is coded according to the spec since it does not appear to handle the cases of drawing all balls or more balls than are present correctly.

1 Like

I changed my code according to your suggestions and I feel closer now. Here is the error message:

FAIL: test_prob_experiment (test_module.UnitTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/boilerplate-probability-calculator-1/test_module.py", line 27, in test_prob_experiment
    self.assertAlmostEqual(actual, expected, delta = 0.01, msg = 'Expected experiment method to return a different probability.')
AssertionError: 0.126 != 0.272 within 0.01 delta (0.14600000000000002 difference) : Expected experiment method to return a different probability.

----------------------------------------------------------------------
Ran 3 tests in 0.017s

FAILED (failures=1)

And here’s my code:

import copy
import random

class Hat:
      def __init__(self, **kwargs):        
        self.contents = []   
        self.total_number_balls = sum( kwargs.values())
        self.list_keys = list(kwargs.keys())
        self.dict = dict(kwargs)
        for keys in kwargs:
            num_balls = kwargs[keys]
            colour_name = keys
            for balls in range(num_balls):
                self.contents.append(colour_name) 
         
    
      def draw (self,num_balls):
        #_______Remove balls at random from the hat      
        
        content_copy = self.contents.copy()
        random_balls_list = []
        ball_drawn = ''

        for draws in range(num_balls):
          if num_balls < len(self.contents):
            ball_drawn = random.choice(self.contents)                        
            random_balls_list.append(ball_drawn)
            self.contents.remove(ball_drawn)
          else:
            self.contents = content_copy
          
          
        return random_balls_list

def experiment (hat,num_balls_drawn,num_experiments,expected_balls):
# def experiment (hat=None,num_balls_drawn=None,num_experiments=None,expected_balls=None):
    event = 0
    total_trials =0
    draws = []
    sum_expected_values = sum(expected_balls.values())
    
    for trials in range(num_experiments):
      
        draws= hat.draw(num_balls=num_balls_drawn)        
        for keys in draws: 
            values = draws.count(keys)
            for expected_keys,expected_values in expected_balls.items():
              if keys == expected_keys and values >= expected_values:
                total_trials +=1
        if total_trials >= sum_expected_values:
          event += 1
          total_trials = 0
                   
        else:
          total_trials = 0
          
      
    
    return event / num_experiments```

The draw method is not drawing balls from content_copy unless all or more of the balls are requested and I don’t see where any copies of the hat are being made elsewhere when you run out of balls. Since your probability is low, you need to log the results of your experiment with the success or failure, the balls drawn, and the expected balls to find the trials that are misclassified as failures instead of successes.

Hi Jeremy, happy new year!

I have been working on the project and I starting to realize that I don’t think I understand the challenge properly. I did the changes to the draw method and here is the message:

   probability = prob_calculator.experiment(
  File "/home/runner/boilerplate-probability-calculator-1/prob_calculator.py", line 65, in experiment
    draws= hat.draw(num_balls=num_balls_drawn) 
  File "/home/runner/boilerplate-probability-calculator-1/prob_calculator.py", line 25, in draw
    self.contents.remove(ball_drawn)
ValueError: list.remove(x): x not in list
exit status 1

And here’s my code (just the draw function):

      def draw (self,num_balls):
        #_______Remove balls at random from the hat      
        
        content_copy = self.contents.copy()
        random_balls_list = []        
          
        for draws in range(num_balls):
          ball_drawn = random.choice(self.contents)
          self.contents.remove(ball_drawn)
          random_balls_list.append(ball_drawn)
          if num_balls > len(content_copy):
            self.contents = content_copy                      
                   
        return random_balls_list

I did as you said and tried logging the results, and I think that maybe the reason why my results are getting either low or high (one got 0.627) are because (like you said) the draw function isn’t working.

I get it everytime it loops the code removes one ball from the self.contents list. However shouldn’t the code loop as many time as the number of balls in the argument?
You also mentioned I should have a copy of the Hat in case the original gets empty, I haven’t figured it out yet the best way to use it.

I think you’re just making it too difficult. The spec says to return all the balls in the hat if all or more are requested. You can do that without looping, but it really shouldn’t be in the loop. If not, then you draw randomly, like your loop.

The problem with copying is that it’s harder to do in the draw method (not to mention it’s a side effect that’s not really part of what would usually be considered drawing balls from hats) as opposed to creating a copy of the original hat on each experiment.

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.