import math
def binconf(p, n, c=0.95):
'''
Calculate binomial confidence interval based on the number of positive and
negative events observed. Uses Wilson score and approximations to inverse
of normal cumulative density function.
Parameters
----------
p: int
number of positive events observed
n: int
number of negative events observed
c : optional, [0,1]
confidence percentage. e.g. 0.95 means 95% confident the probability of
success lies between the 2 returned values
Returns
-------
theta_low : float
lower bound on confidence interval
theta_high : float
upper bound on confidence interval
'''
p, n = float(p), float(n)
N = p + n
if N == 0.0: return (0.0, 1.0)
p = p / N
z = normcdfi(1 - 0.5 * (1-c))
a1 = 1.0 / (1.0 + z * z / N)
a2 = p + z * z / (2 * N)
a3 = z * math.sqrt(p * (1-p) / N + z * z / (4 * N * N))
return (a1 * (a2 - a3), a1 * (a2 + a3))
def erfi(x):
"""Approximation to inverse error function"""
a = 0.147 # MAGIC!!!
a1 = math.log(1 - x * x)
a2 = (
2.0 / (math.pi * a)
+ a1 / 2.0
)
return (
sign(x) *
math.sqrt( math.sqrt(a2 * a2 - a1 / a) - a2 )
)
def sign(x):
if x < 0: return -1
if x == 0: return 0
if x > 0: return 1
def normcdfi(p, mu=0.0, sigma2=1.0):
"""Inverse CDF of normal distribution"""
if mu == 0.0 and sigma2 == 1.0:
return math.sqrt(2) * erfi(2 * p - 1)
else:
return mu + math.sqrt(sigma2) * normcdfi(p)
print binconf(14224,8935)
print "\n"
print binconf(6553,1181)
aW1wb3J0IG1hdGgKCmRlZiBiaW5jb25mKHAsIG4sIGM9MC45NSk6CiAgJycnCiAgQ2FsY3VsYXRlIGJpbm9taWFsIGNvbmZpZGVuY2UgaW50ZXJ2YWwgYmFzZWQgb24gdGhlIG51bWJlciBvZiBwb3NpdGl2ZSBhbmQKICBuZWdhdGl2ZSBldmVudHMgb2JzZXJ2ZWQuICBVc2VzIFdpbHNvbiBzY29yZSBhbmQgYXBwcm94aW1hdGlvbnMgdG8gaW52ZXJzZQogIG9mIG5vcm1hbCBjdW11bGF0aXZlIGRlbnNpdHkgZnVuY3Rpb24uCgogIFBhcmFtZXRlcnMKICAtLS0tLS0tLS0tCiAgcDogaW50CiAgICAgIG51bWJlciBvZiBwb3NpdGl2ZSBldmVudHMgb2JzZXJ2ZWQKICBuOiBpbnQKICAgICAgbnVtYmVyIG9mIG5lZ2F0aXZlIGV2ZW50cyBvYnNlcnZlZAogIGMgOiBvcHRpb25hbCwgWzAsMV0KICAgICAgY29uZmlkZW5jZSBwZXJjZW50YWdlLiBlLmcuIDAuOTUgbWVhbnMgOTUlIGNvbmZpZGVudCB0aGUgcHJvYmFiaWxpdHkgb2YKICAgICAgc3VjY2VzcyBsaWVzIGJldHdlZW4gdGhlIDIgcmV0dXJuZWQgdmFsdWVzCgogIFJldHVybnMKICAtLS0tLS0tCiAgdGhldGFfbG93ICA6IGZsb2F0CiAgICAgIGxvd2VyIGJvdW5kIG9uIGNvbmZpZGVuY2UgaW50ZXJ2YWwKICB0aGV0YV9oaWdoIDogZmxvYXQKICAgICAgdXBwZXIgYm91bmQgb24gY29uZmlkZW5jZSBpbnRlcnZhbAogICcnJwogIHAsIG4gPSBmbG9hdChwKSwgZmxvYXQobikKICBOICAgID0gcCArIG4KCiAgaWYgTiA9PSAwLjA6IHJldHVybiAoMC4wLCAxLjApCgogIHAgPSBwIC8gTgogIHogPSBub3JtY2RmaSgxIC0gMC41ICogKDEtYykpCgogIGExID0gMS4wIC8gKDEuMCArIHogKiB6IC8gTikKICBhMiA9IHAgKyB6ICogeiAvICgyICogTikKICBhMyA9IHogKiBtYXRoLnNxcnQocCAqICgxLXApIC8gTiArIHogKiB6IC8gKDQgKiBOICogTikpCgogIHJldHVybiAoYTEgKiAoYTIgLSBhMyksIGExICogKGEyICsgYTMpKQoKCmRlZiBlcmZpKHgpOgogICIiIkFwcHJveGltYXRpb24gdG8gaW52ZXJzZSBlcnJvciBmdW5jdGlvbiIiIgogIGEgID0gMC4xNDcgICMgTUFHSUMhISEKICBhMSA9IG1hdGgubG9nKDEgLSB4ICogeCkKICBhMiA9ICgKICAgIDIuMCAvIChtYXRoLnBpICogYSkKICAgICsgYTEgLyAyLjAKICApCgogIHJldHVybiAoCiAgICBzaWduKHgpICoKICAgIG1hdGguc3FydCggbWF0aC5zcXJ0KGEyICogYTIgLSBhMSAvIGEpIC0gYTIgKQogICkKCgpkZWYgc2lnbih4KToKICBpZiB4ICA8IDA6IHJldHVybiAtMQogIGlmIHggPT0gMDogcmV0dXJuICAwCiAgaWYgeCAgPiAwOiByZXR1cm4gIDEKCgpkZWYgbm9ybWNkZmkocCwgbXU9MC4wLCBzaWdtYTI9MS4wKToKICAiIiJJbnZlcnNlIENERiBvZiBub3JtYWwgZGlzdHJpYnV0aW9uIiIiCiAgaWYgbXUgPT0gMC4wIGFuZCBzaWdtYTIgPT0gMS4wOgogICAgcmV0dXJuIG1hdGguc3FydCgyKSAqIGVyZmkoMiAqIHAgLSAxKQogIGVsc2U6CiAgICByZXR1cm4gbXUgKyBtYXRoLnNxcnQoc2lnbWEyKSAqIG5vcm1jZGZpKHApCiAgICAKcHJpbnQgYmluY29uZigxNDIyNCw4OTM1KQpwcmludCAiXG4iCnByaW50IGJpbmNvbmYoNjU1MywxMTgxKQ==