Simulating bouts¶
This follows the simulation of mixed Poisson distributions in Luque & Guinet (2007), and the comparison of models for characterizing such distributions.
Set up the environment.
# Set up
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import skdiveMove.bouts as skbouts
# For figure sizes
_FIG3X1 = (9, 12)
pd.set_option("display.precision", 3)
np.set_printoptions(precision=3, sign="+")
%matplotlib inline
Generate two-process mixture¶
For a mixed distribution of two random Poisson processes with a mixing parameter \(p=0.7\), and density parameters \(\lambda_f=0.05\), and \(\lambda_s=0.005\), we can set up the following function to generate samples:
def genx(n, p, lda0, lda1):
chooser = np.random.uniform(size=n)
# We need to convert from scale to rate parameter
proc1 = np.random.exponential(1 / lda0, size=n)
proc2 = np.random.exponential(1 / lda1, size=n)
proc_mix = np.where(chooser < p, proc1, proc2)
return(proc_mix)
Define the true values described above, grouping the parameters into a Series to simplify further operations.
p_true = 0.7
lda0_true = 0.05
lda1_true = 0.005
pars_true = pd.Series({"lambda0": lda0_true,
"lambda1": lda1_true,
"p": p_true})
Declare the number of simulations and the number of samples to generate:
# Number of simulations
nsims = 500
# Size of each sample
nsamp = 1000
Set up variables to accumulate simulations:
# Set up NLS simulations
coefs_nls = []
# Set up MLE simulations
coefs_mle = []
# Fixed bounds fit 1
p_bnd = (-2, None)
lda0_bnd = (-5, None)
lda1_bnd = (-10, None)
opts1 = dict(method="L-BFGS-B",
bounds=(p_bnd, lda0_bnd, lda1_bnd))
# Fixed bounds fit 2
p_bnd = (1e-1, None)
lda0_bnd = (1e-3, None)
lda1_bnd = (1e-6, None)
opts2 = dict(method="L-BFGS-B",
bounds=(p_bnd, lda0_bnd, lda1_bnd))
Perform the simulations in a loop, fitting the nonlinear least squares (NLS) model, and the alternative maximum likelihood (MLE) model at each iteration.
# Estimate parameters `nsims` times
for i in range(nsims):
x = genx(nsamp, pars_true["p"], pars_true["lambda0"],
pars_true["lambda1"])
# NLS
xbouts = skbouts.BoutsNLS(x, 5)
init_pars = xbouts.init_pars([80], plot=False)
coefs, _ = xbouts.fit(init_pars)
p_i = skbouts.bouts.calc_p(coefs)[0][0] # only one here
coefs_i = coefs.loc["lambda"].append(pd.Series({"p": p_i}))
coefs_nls.append(coefs_i.to_numpy())
# MLE
xbouts = skbouts.BoutsMLE(x, 5)
init_pars = xbouts.init_pars([80], plot=False)
fit1, fit2 = xbouts.fit(init_pars, fit1_opts=opts1,
fit2_opts=opts2)
coefs_mle.append(np.roll(fit2.x, -1))
Non-linear least squares (NLS)¶
Collect and display NLS results from the simulations:
nls_coefs = pd.DataFrame(np.row_stack(coefs_nls),
columns=["lambda0", "lambda1", "p"])
# Centrality and variance
nls_coefs.describe()
lambda0 | lambda1 | p | |
---|---|---|---|
count | 500.000 | 5.000e+02 | 500.000 |
mean | 0.047 | 3.979e-03 | 0.729 |
std | 0.005 | 4.227e-04 | 0.020 |
min | 0.032 | 2.576e-03 | 0.655 |
25% | 0.044 | 3.715e-03 | 0.716 |
50% | 0.047 | 3.957e-03 | 0.730 |
75% | 0.050 | 4.245e-03 | 0.743 |
max | 0.061 | 5.356e-03 | 0.777 |
Maximum likelihood estimation (MLE)¶
Collect and display MLE results from the simulations:
mle_coefs = pd.DataFrame(np.row_stack(coefs_mle),
columns=["lambda0", "lambda1", "p"])
# Centrality and variance
mle_coefs.describe()
lambda0 | lambda1 | p | |
---|---|---|---|
count | 500.000 | 5.000e+02 | 500.000 |
mean | 0.050 | 4.996e-03 | 0.700 |
std | 0.003 | 3.818e-04 | 0.024 |
min | 0.042 | 4.108e-03 | 0.628 |
25% | 0.048 | 4.726e-03 | 0.684 |
50% | 0.050 | 4.967e-03 | 0.701 |
75% | 0.052 | 5.259e-03 | 0.716 |
max | 0.062 | 6.295e-03 | 0.760 |
Comparing NLS vs MLE¶
The bias relative to the true values of the mixed distribution can be readily assessed for NLS:
nls_coefs.mean() - pars_true
lambda0 -0.003
lambda1 -0.001
p 0.029
dtype: float64
and for MLE:
mle_coefs.mean() - pars_true
lambda0 2.183e-04
lambda1 -3.812e-06
p 1.466e-05
dtype: float64
To visualize the estimates obtained throughout the simulations, we can compare density plots, along with the true parameter values:

Feel free to download a copy of this demo (boutsimuldemo.py).