Skip to content

Instantly share code, notes, and snippets.

@krishnanraman
Created June 5, 2014 00:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save krishnanraman/4be978cbe8979e4c97fa to your computer and use it in GitHub Desktop.
Save krishnanraman/4be978cbe8979e4c97fa to your computer and use it in GitHub Desktop.
AB Test per Evan Miller & Sean Harnett see: https://news.ycombinator.com/reply?id=7848208
object ABTest extends App{
case class Rate(successes:Int, failures:Int) {
override def toString = "[Successes: %d, Failures: %d]".format(successes, failures)
}
def BbeatsA(a:Rate, b:Rate) = {
val mu = Beta(1 + a.successes, 1 + a.failures).mean - Beta(1 + a.failures, 1 + b.failures).mean
val sigma = math.pow(Beta(1 + a.successes, 1 + a.failures).variance + Beta(1 + b.successes, 1 + b.failures).variance, 0.5)
100.0 * Gaussian.cdf(0, mu, sigma)
}
for(i<- 30 to 70) {
val a = Rate(successes = i, failures = 100 - i)
val b = Rate(successes = 100 - i, failures = i)
val odds = BbeatsA(a,b)
val msg = if (odds > 50) "A %s, B %s, B beats A with odds: %.3f %s".format(a,b,odds, "%")
else "A %s, B %s, A beats B with odds: %.3f %s".format(a,b, 100 - odds, "%")
println(msg)
}
}
case class Beta(a:Double, b:Double) {
def mean = a/(a+b)
def variance = a*b/(math.pow(a+b,2)*(a+b+1))
}
object Gaussian {
// standard Gaussian pdf
def pdf(x:Double) = math.exp(-x*x / 2) / math.sqrt(2 * math.Pi)
// standard Gaussian cdf using Taylor approximation
def cdf(z:Double):Double = {
if (z < -8.0) 0.0
else if (z > 8.0) 1.0
else {
var sum = 0.0
var term = z
var i = 3
while( sum + term != sum) {
sum = sum + term
term = term * z * z / i
i += 2
}
0.5 + sum * pdf(z)
}
}
// Gaussian cdf with mean mu and stddev sigma
def cdf(z:Double, mu:Double, sigma:Double):Double = cdf((z - mu) / sigma)
}
$ scala ABTest
A [Successes: 30, Failures: 70], B [Successes: 70, Failures: 30], B beats A with odds: 100.000 %
A [Successes: 31, Failures: 69], B [Successes: 69, Failures: 31], B beats A with odds: 100.000 %
A [Successes: 32, Failures: 68], B [Successes: 68, Failures: 32], B beats A with odds: 100.000 %
A [Successes: 33, Failures: 67], B [Successes: 67, Failures: 33], B beats A with odds: 100.000 %
A [Successes: 34, Failures: 66], B [Successes: 66, Failures: 34], B beats A with odds: 100.000 %
A [Successes: 35, Failures: 65], B [Successes: 65, Failures: 35], B beats A with odds: 99.999 %
A [Successes: 36, Failures: 64], B [Successes: 64, Failures: 36], B beats A with odds: 99.998 %
A [Successes: 37, Failures: 63], B [Successes: 63, Failures: 37], B beats A with odds: 99.992 %
A [Successes: 38, Failures: 62], B [Successes: 62, Failures: 38], B beats A with odds: 99.974 %
A [Successes: 39, Failures: 61], B [Successes: 61, Failures: 39], B beats A with odds: 99.924 %
A [Successes: 40, Failures: 60], B [Successes: 60, Failures: 40], B beats A with odds: 99.795 %
A [Successes: 41, Failures: 59], B [Successes: 59, Failures: 41], B beats A with odds: 99.496 %
A [Successes: 42, Failures: 58], B [Successes: 58, Failures: 42], B beats A with odds: 98.869 %
A [Successes: 43, Failures: 57], B [Successes: 57, Failures: 43], B beats A with odds: 97.664 %
A [Successes: 44, Failures: 56], B [Successes: 56, Failures: 44], B beats A with odds: 95.547 %
A [Successes: 45, Failures: 55], B [Successes: 55, Failures: 45], B beats A with odds: 92.131 %
A [Successes: 46, Failures: 54], B [Successes: 54, Failures: 46], B beats A with odds: 87.059 %
A [Successes: 47, Failures: 53], B [Successes: 53, Failures: 47], B beats A with odds: 80.115 %
A [Successes: 48, Failures: 52], B [Successes: 52, Failures: 48], B beats A with odds: 71.338 %
A [Successes: 49, Failures: 51], B [Successes: 51, Failures: 49], B beats A with odds: 61.083 %
A [Successes: 50, Failures: 50], B [Successes: 50, Failures: 50], A beats B with odds: 50.000 %
A [Successes: 51, Failures: 49], B [Successes: 49, Failures: 51], A beats B with odds: 61.083 %
A [Successes: 52, Failures: 48], B [Successes: 48, Failures: 52], A beats B with odds: 71.338 %
A [Successes: 53, Failures: 47], B [Successes: 47, Failures: 53], A beats B with odds: 80.115 %
A [Successes: 54, Failures: 46], B [Successes: 46, Failures: 54], A beats B with odds: 87.059 %
A [Successes: 55, Failures: 45], B [Successes: 45, Failures: 55], A beats B with odds: 92.131 %
A [Successes: 56, Failures: 44], B [Successes: 44, Failures: 56], A beats B with odds: 95.547 %
A [Successes: 57, Failures: 43], B [Successes: 43, Failures: 57], A beats B with odds: 97.664 %
A [Successes: 58, Failures: 42], B [Successes: 42, Failures: 58], A beats B with odds: 98.869 %
A [Successes: 59, Failures: 41], B [Successes: 41, Failures: 59], A beats B with odds: 99.496 %
A [Successes: 60, Failures: 40], B [Successes: 40, Failures: 60], A beats B with odds: 99.795 %
A [Successes: 61, Failures: 39], B [Successes: 39, Failures: 61], A beats B with odds: 99.924 %
A [Successes: 62, Failures: 38], B [Successes: 38, Failures: 62], A beats B with odds: 99.974 %
A [Successes: 63, Failures: 37], B [Successes: 37, Failures: 63], A beats B with odds: 99.992 %
A [Successes: 64, Failures: 36], B [Successes: 36, Failures: 64], A beats B with odds: 99.998 %
A [Successes: 65, Failures: 35], B [Successes: 35, Failures: 65], A beats B with odds: 99.999 %
A [Successes: 66, Failures: 34], B [Successes: 34, Failures: 66], A beats B with odds: 100.000 %
A [Successes: 67, Failures: 33], B [Successes: 33, Failures: 67], A beats B with odds: 100.000 %
A [Successes: 68, Failures: 32], B [Successes: 32, Failures: 68], A beats B with odds: 100.000 %
A [Successes: 69, Failures: 31], B [Successes: 31, Failures: 69], A beats B with odds: 100.000 %
A [Successes: 70, Failures: 30], B [Successes: 30, Failures: 70], A beats B with odds: 100.000 %
@nkconnor
Copy link

This is flawed. If you run the calculation with RateA = Rate(10, 90), RateB = Rate(10, 90) it gives 100% chance that B beats A

@nkconnor
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment