def binomial_exact(successes, trials, prob): """Returns binomial probability of exactly X successes. Works for integer and floating point values. Note: this function is only a probability mass function for integer values of 'trials' and 'successes', i.e. if you sum up non-integer values you probably won't get a sum of 1. """ if (prob < 0) or (prob > 1): raise ValueError, "Binomial prob must be between 0 and 1." if (successes < 0) or (trials < successes): raise ValueError, "Binomial successes must be between 0 and trials." return exp(ln_binomial(successes, trials, prob))
def test_ln_binomial_range(self): """ln_binomial should increase in a monotonically increasing region. """ start=0 end=1 step = 0.1 lower_lim = -1.783375-1e-4 upper_lim = -1.021235+1e-4 previous_value = -1.784 while start <= end: obs = ln_binomial(start,5,.3) assert lower_lim <= obs <= upper_lim assert obs > previous_value previous_value = obs start += step
def test_ln_binomial_floats(self): """Binomial exact should match values from R for integer successes""" expected = { (18.3, 100, 0.2): (math.log(0.09089812), math.log(0.09807429)), (2.7,1050,0.006): (math.log(0.03615498), math.log(0.07623827)), (2.7,1050,0.06): (math.log(1.365299e-25), math.log(3.044327e-24)), (2,100.5,0.6): (math.log(7.303533e-37), math.log(1.789727e-36)), (0.2, 60, 0.5): (math.log(8.673617e-19), math.log(5.20417e-17)), (.5,5,.3):(math.log(0.16807),math.log(0.36015)), (10,100.5,.5):(math.log(7.578011e-18),math.log(1.365543e-17)), } for (key, value) in expected.items(): min_val, max_val = value assert min_val < ln_binomial(*key) < max_val
def test_ln_binomial_range(self): """ln_binomial should increase in a monotonically increasing region. """ start = 0 end = 1 step = 0.1 lower_lim = -1.783375 - 1e-4 upper_lim = -1.021235 + 1e-4 previous_value = -1.784 while start <= end: obs = ln_binomial(start, 5, .3) assert lower_lim <= obs <= upper_lim assert obs > previous_value previous_value = obs start += step
def test_ln_binomial_integer(self): """ln_binomial should match R results for integer values""" expected = { (10,60,0.1): -3.247883, (1, 1, 0.5): math.log(0.5), (1, 1, 0.0000001): math.log(1e-07), (1, 1, 0.9999999): math.log(0.9999999), (3, 5, 0.75): math.log(0.2636719), (0, 60, 0.5): math.log(8.673617e-19), (129, 130, 0.5): math.log(9.550892e-38), (299, 300, 0.099): math.log(1.338965e-298), (9, 27, 0.0003): math.log(9.175389e-26), (1032, 2050, 0.5): math.log(0.01679804), } for (key, value) in expected.items(): self.assertFloatEqualRel(ln_binomial(*key), value, 1e-4)
def test_ln_binomial_integer(self): """ln_binomial should match R results for integer values""" expected = { (10, 60, 0.1): -3.247883, (1, 1, 0.5): math.log(0.5), (1, 1, 0.0000001): math.log(1e-07), (1, 1, 0.9999999): math.log(0.9999999), (3, 5, 0.75): math.log(0.2636719), (0, 60, 0.5): math.log(8.673617e-19), (129, 130, 0.5): math.log(9.550892e-38), (299, 300, 0.099): math.log(1.338965e-298), (9, 27, 0.0003): math.log(9.175389e-26), (1032, 2050, 0.5): math.log(0.01679804), } for (key, value) in list(expected.items()): self.assertFloatEqualRel(ln_binomial(*key), value, 1e-4)