In [42]:
################### FLIPPING UTILS ###################
from random import random
import numpy as np

def flip(q):
    #returns 1 w.p q and 0 o.w
    return int(random()<q)

def sequence(n, q):
    #returns a sequence of n coin tosses
    #HEADS(1) w.p q and TAILS(0) o.w
    return np.array([flip(q) for _ in range(n)])
In [43]:
################### MLE ###################
from functools import partial as curry

def mle_uniform(X):
    #returns MLE on X with uniform prior
    return X.sum()/len(X)

def mle_two_coins(e, X):
    #retuns MLE on X with prior p(1/2 - e) = p(1/2 + e) = 1/2
    return 0.5 + e if X.sum() >= len(X)/2.0 else 0.5-e
In [44]:
################### ERROR ###################
def zero_one_loss(q, q_hat):
    #returns 1 if q \neq q_hat and 0 o.w
    return q != q_hat

def absolute_loss(q, q_hat):
    #returns |q- q_hat|
    return np.absolute(q - q_hat)

def check_error(estimator, loss_function, n, q, trials):
    #sample a sequence with bias q
    #use estimator to estimate q
    #returns the average loss incurred in all trials
    loss = 0.0
    for _ in range(int(trials)):
        X = sequence(int(n), q)
        q_hat = estimator(X)
        loss = loss + loss_function(q, q_hat)
    return loss/trials
    
In [47]:
################### PLOT ###################
import matplotlib.pyplot as plt

def plot(x, y):
    plt.xlabel('Number of Coin Tosses')
    plt.ylabel('Error')
    plt.plot(x, y)
    plt.show()
In [59]:
n_list = np.linspace(100, 4000, 10)
loss_list = [check_error(mle_uniform, absolute_loss, n, 0.1, 100) for n in n_list]
plot(n_list, loss_list)
In [61]:
n_list = np.linspace(100, 300, 10)
loss_list = [check_error(curry(mle_two_coins, 0.1), zero_one_loss, n, 0.4, 10000) for n in n_list]
plt.plot(n_list, loss_list)
plt.show()