Point estimates¶

We are trying to reveal some parameter of unknown distribution that we sample from. In this problem we are sampling from distribution $U(0,\theta)$. To imagine a story about this: we play a game where the amount of time we get to play is random, generated by a device set up to generate a uniform random variable from interval $[0,\theta]$ for some value of $\theta$. How to decide the value of $\theta$ from several observations?

A discrete version of this is the "German tank problem". https://en.wikipedia.org/wiki/German_tank_problem

In [3]:
from scipy import stats
from math import sqrt
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns

The next function generates $n$ numbers from the distribution $U(0,\theta)$. Here we know $\theta$, in practice it would be an unknown parameter!!!

In [4]:
def sampleU(n, theta):
    """
        Returns a sample of num independent values from U(0,theta).
    """
    return stats.uniform.rvs(loc=0,scale=theta,size=n)

We present few variants of estimate.

The first one is obtained by the moment method, the second by the maximum likelihood.

(Can you find a better one? The best possible solution is not yet discovered.)

In [5]:
def my_estimate(x):
    return 2*x.mean()
In [5]:
def my_estimate2(x):
    return x.max()
In [6]:
def my_estimate3(x):
    n = len(x)
    return x.max()*(n+1)/n

Now: how to test which estimate is better?

We compute the bias and the mean squared error.

Observe the results and think about what it means.

Note the difference between two numbers: $n$ is the size of a sample from which the statistian decides about his/her estimate $\hat\theta$. OTOH, num is the number of repetitions we try this thing, to verify how good are the estimates.

That is, we use num to estimate the true expectation, while $n$ what allow us to compute, e.g., the sample mean.

In [6]:
def test_my_method(theta, sample_method, estimate_method, n=5, num=10**4, image=True, eps=0.1):
    if theta is None: theta  = 130
    L = []
    D = []
    for _ in range(num):
        data = sample_method(n,theta)   # one experiment -- perform sample_size measurements, predict what it implies
        D.append(data)
        L.append(estimate_method(data))

    estimates = np.array(L)   # theta se striskou
    MSE = np.mean((estimates-theta)**2)
    bias = estimates.mean()-theta
    p = np.mean(abs(estimates-theta)>eps)
    
    print(f"Mean: {estimates.mean():.3f}")
    print(f"Bias: {bias:.3f}")

    print(f"Mean squared error: {MSE:.3f}")
    print(f"Var+Bias^2: {estimates.var()+bias**2:.3f}, ")    
    print(f"P(error > {eps}) = {p}")
    
    if image:
        sns.set_style('whitegrid')
        sns.histplot(estimates)

Testing one of the methods.

We can see that $MSE = Var+Bias^2$

In [8]:
test_my_method(130, sampleU, my_estimate, n=100, num=10000, eps=5, image=True)
Mean: 129.975
Bias: -0.025
Mean squared error: 54.634
Var+Bias^2: 54.634, 
P(error > 5) = 0.5014
No description has been provided for this image

Here we can see that with increasing $n$ probability of error $>10$ decreases (rather fast). (The method is consistent.)

Also the MSE decreases.

OTOH, bias is small already for $n=5$ -- the method is unbiased.

In [11]:
test_my_method(130, sampleU, my_estimate, n=5, num=10**4, image=False, eps=10); print()
test_my_method(130, sampleU, my_estimate, n=50, num=10**4, image=False, eps=10); print()
test_my_method(130, sampleU, my_estimate, n=500, num=10**4, image=False, eps=10)
Mean: 130.374
Bias: 0.374
Mean squared error: 1096.876
Var+Bias^2: 1096.876, 
P(error > 10) = 0.7685

Mean: 130.030
Bias: 0.030
Mean squared error: 111.129
Var+Bias^2: 111.129, 
P(error > 10) = 0.3485

Mean: 130.010
Bias: 0.010
Mean squared error: 10.929
Var+Bias^2: 10.929, 
P(error > 10) = 0.0013

This method is not unbiased.

In fact, the histogram of $\hat\theta$ shows, that we always undershoot the true value of $\theta$.

In [237]:
test_my_method(130, sampleU, my_estimate2, sample_size=100, num=10000, eps=5)
Mean: 128.721
Bias: -1.279
Mean squared error: 3.296
Var+Bias^2: 3.296, 
P(error > 5) = 0.0204
No description has been provided for this image

Third method. Note that this is apparently unbiased, also we sometimes overshoot, sometimes undershoot.

The MSE is much smaller than in the other methods.

In [238]:
test_my_method(130, sampleU, my_estimate3, sample_size=100, num=10000, eps=5)
Mean: 130.011
Bias: 0.011
Mean squared error: 1.673
Var+Bias^2: 1.673, 
P(error > 5) = 0.0076
No description has been provided for this image
In [ ]:
 
In [13]:
def sampleGeom(n, secretp):
    """
        Returns a sample of num independent values from Geom(secretp).
    """
    return stats.geom.rvs(secretp,size=n)
In [12]:
def sampleExp(n, secretp):
    """
        Returns a sample of num independent values from Exp(secretp).
    """
    return stats.expon.rvs(scale=secretp,size=n)
In [38]:
a = sampleExp(10000,3)
In [39]:
a.mean()
Out[39]:
2.975340338068114
In [ ]:
 
In [17]:
def my_estimate4(x):
    return 1/x.mean()
In [18]:
def my_estimate5(x):
    return x.mean()
In [ ]:
 
In [19]:
test_my_method(1/6, sampleGeom, my_estimate4, n=50, num=10000, eps=0.05)
Mean: 0.170
Bias: 0.003
Mean squared error: 0.000
Var+Bias^2: 0.000, 
P(error > 0.05) = 0.0279
No description has been provided for this image
In [20]:
test_my_method(1/6, sampleGeom, my_estimate4, n=50, num=10000, eps=0.05)
Mean: 0.169
Bias: 0.003
Mean squared error: 0.000
Var+Bias^2: 0.000, 
P(error > 0.05) = 0.0277
No description has been provided for this image
In [ ]:
 
In [22]:
test_my_method(3, sampleExp, my_estimate5, n=5, num=10**5, eps=0.5)
Mean: 3.000
Bias: 0.000
Mean squared error: 1.795
Var+Bias^2: 1.795, 
P(error > 0.5) = 0.71342
No description has been provided for this image
In [ ]: