Input format

To demonstrate the python data types required to represent the input, we use the utility function make_data which returns randomly generated data that we will use for this example. See the function’s documentation for more information regarding its parameters.

[1]:
from occuspytial.utils import make_data

Q, W, X, y, true_alpha, true_beta, true_tau, true_z = make_data(random_state=0)

The Gibbs samplers expect (at the minimum) as input the design matrix for occupancy covariates, the design matrices for detection covariates, the detection/non-detection data and the spatial precision matrix of the ICAR spatial random effects.

Q represents the spatial precision matrix and can either be scipy’s sparse matrix object or a numpy array. If a numpy array is used, the sampler convert it to a sparse matrix. It is advised that Q be in sparse format since the format is more memory efficient.

[2]:
Q
[2]:
<150x150 sparse matrix of type '<class 'numpy.float64'>'
        with 1204 stored elements in COOrdinate format>

Detection/non-detection observed data (y) should be depresented using a dictionary whose key is the site number (only sites that were surveyed) and value is a numpy array whose elements are 1’s (if the species is detected on that visit) and 0’s. The length of the array should represent the number of visits for that site.

[3]:
y.keys()
[3]:
dict_keys([15, 130, 33, 114, 7, 105, 121, 148, 27, 103, 40, 106, 1, 90, 69, 8, 29, 76, 101, 24, 75, 112, 142, 77, 85, 51, 43, 30, 47, 139, 93, 99, 45, 26, 55, 131, 79, 122, 115, 120, 54, 125, 117, 36, 28, 57, 22, 37, 78, 5, 109, 95, 49, 17, 4, 62, 13, 104, 108, 118, 135, 137, 3, 32, 18, 116, 100, 53, 65, 80, 91, 86, 42, 2, 14])
[4]:
y[15]  # 4 visits in site 15 with no detection of the species on
[4]:
array([0, 0, 0, 0])

Similarly, the detection covariates (W) are represented by a dictionary whose key is the site number (only sites that were surveyed) and value is a 2d numpy array representing the design matrix of the detection covariates of that site.

[5]:
W[15]
[5]:
array([[ 1.        , -0.54769293,  1.19683385],
       [ 1.        ,  0.56049534,  0.06091067],
       [ 1.        ,  1.49854722,  0.39848634],
       [ 1.        ,  1.74023235, -1.3585544 ]])

Occupancy covariates (X) are represented by a design matrix which is a 2d numpy array.

[6]:
X[:5]  # occupancy design matrix for the first 5 sites
[6]:
array([[ 1.        ,  1.9343916 ,  0.41607945],
       [ 1.        ,  1.57410391, -0.88706203],
       [ 1.        , -1.4857609 ,  0.31065634],
       [ 1.        , -0.72944554,  0.27830849],
       [ 1.        , -1.36270245,  0.22016475]])

The rest of the output from make_data are the simulated true values for spatial occupancy model parameters.

[7]:
print('alpha: ', true_alpha, '\n', 'beta: ', true_beta, '\n', 'tau: ', true_tau, '\n', 'z (occupancy state): ', true_z)
alpha:  [-0.62578191 -0.76973348  0.89920592]
 beta:  [ 0.16133415 -1.4298573  -1.29695223]
 tau:  0.6567761989615925
 z (occupancy state):  [0 1 1 1 1 1 1 0 1 1 0 1 0 0 1 0 0 1 1 0 1 0 0 1 0 0 1 1 0 1 1 0 0 0 0 0 0
 1 1 0 0 1 0 1 1 0 0 1 1 0 1 0 0 1 1 1 1 1 0 1 1 1 1 1 0 0 1 0 0 0 1 1 1 0
 0 1 0 1 1 1 0 0 1 0 1 1 0 0 0 0 1 1 0 1 0 0 0 0 1 0 0 1 1 1 1 1 0 0 0 1 1
 0 1 1 1 1 0 0 1 1 0 0 1 0 1 0 1 1 1 1 1 1 0 1 1 1 0 1 1 0 0 1 0 0 1 1 1 1
 1 1]

Sampling example

This section contains basic examples of how to use the available samplers.

Gibbs sampling

Here we show how to use the Gibbs sampler presented in Clark & Altwegg (2019) using OccuSpytial’s sampler API. The name of the class implementing this sampler is LogitRSRGibbs

[8]:
import numpy as np

from occuspytial import LogitRSRGibbs
from occuspytial.utils import make_data

# generate fake data with 500 sites in total
Q, W, X, y, true_alpha, true_beta, true_tau, true_z = make_data(500, tau_range=(0.1, 0.5), random_state=0)

Lets print out the true values of the parameters of interest.

[9]:
print('alpha: ', true_alpha, '\n', 'beta: ', true_beta, '\n', 'tau: ', true_tau)
alpha:  [-1.8990662   1.46050246  0.35355792]
 beta:  [ 0.45288262 -0.50514168  0.10059925]
 tau:  0.36959287108483785
[10]:
rsr = LogitRSRGibbs(Q, W, X, y, random_state=10)
rsr_samples = rsr.sample(2000, burnin=1000, chains=2)
# The progressbar is on by default, but Jupyter notebook only displays it on the console
# so it is not visible in the output cell of this notebook unlike if we are working on the console.

The output of the sample method is an instance of the PosteriorParameter class and inference of the samples obtained are done via the instance stored in the variable rsr_samples. We can display the summary table using the summary attribute.

[11]:
rsr_samples.summary
[11]:
mean sd hdi_3% hdi_97% mcse_mean mcse_sd ess_bulk ess_tail r_hat
alpha[0] -2.090 0.072 -2.224 -1.959 0.004 0.003 280.0 607.0 1.01
alpha[1] 1.643 0.063 1.517 1.760 0.004 0.003 291.0 678.0 1.02
alpha[2] 0.437 0.042 0.348 0.510 0.002 0.001 659.0 1338.0 1.00
beta[0] 0.415 0.251 -0.014 0.929 0.018 0.013 185.0 271.0 1.01
beta[1] -0.705 0.201 -1.082 -0.328 0.014 0.010 200.0 392.0 1.01
beta[2] -0.153 0.190 -0.500 0.220 0.014 0.010 196.0 454.0 1.01
tau 0.030 0.012 0.011 0.051 0.001 0.001 75.0 249.0 1.06

To access the individual parameters we can use the the parameter’s name as the key.

[12]:
rsr_samples['alpha']
[12]:
array([[[-2.01705032,  1.65307598,  0.401219  ],
        [-2.14701198,  1.64676912,  0.43997882],
        [-2.01331818,  1.58390992,  0.39207318],
        ...,
        [-2.0125808 ,  1.62231449,  0.45280794],
        [-1.96998293,  1.62743685,  0.39180286],
        [-2.05031195,  1.67996656,  0.47238301]],

       [[-2.00735185,  1.65148581,  0.44014908],
        [-2.02527985,  1.568106  ,  0.39224504],
        [-2.00480733,  1.54194479,  0.32078477],
        ...,
        [-2.09342836,  1.57293681,  0.46988205],
        [-2.06795498,  1.61602514,  0.48115473],
        [-2.02151848,  1.60897632,  0.45971322]]])

Since we generated 2 chains, alpha parameter array is three dimensional; where the first dimension is the chain index, the second dimension is the length of the post-burnin samples, and the third dimension is the size of the parameter (in elements).

[13]:
rsr_samples['alpha'].shape
[13]:
(2, 1000, 3)

LogitRSRGibbs expects the prior distributions for alpha and beta to be normal distributed, and the prior for tau to be Gamma distributed. We can pass custom values for the hyperparameters of these priors through the hparams dictionary parameter during instantiation of the class instance. More details on legal keys and values can be found in the docstring of the class.

[14]:
a_size = true_alpha.shape[0]
b_size = true_beta.shape[0]
hypers = {
    'a_mu': np.ones(a_size),  # alpha mean is an array of 1's
    'a_prec': np.eye(a_size) / 1000,  # alpha precision matrix (inverse of covariance) is diagonal matrix with entries (1/1000)
    'b_mu': np.ones(b_size),
    'b_prec': np.eye(a_size) / 1000,
    'tau_rate': 2,  # tau's rate parameter for the prior gamma distribution
    'tau_shape': 2,  # tau's shape parameter
}
rsr_hp = LogitRSRGibbs(Q, W, X, y, hparams=hypers, random_state=10)
rsrhp_samples = rsr_hp.sample(2000, burnin=1000, chains=2)
rsrhp_samples.summary
[14]:
mean sd hdi_3% hdi_97% mcse_mean mcse_sd ess_bulk ess_tail r_hat
alpha[0] -2.169 0.072 -2.315 -2.042 0.016 0.011 21.0 103.0 1.08
alpha[1] 1.592 0.064 1.467 1.705 0.014 0.010 21.0 252.0 1.08
alpha[2] 0.421 0.044 0.334 0.499 0.004 0.003 101.0 1203.0 1.03
beta[0] 31.860 11.925 10.092 50.254 7.436 6.006 3.0 19.0 2.13
beta[1] -40.554 9.686 -53.542 -20.947 5.832 4.661 3.0 12.0 1.63
beta[2] -19.367 4.297 -26.079 -10.843 2.021 1.533 5.0 13.0 1.35
tau 0.000 0.000 0.000 0.000 0.000 0.000 67.0 808.0 1.03

As we can see the MCMC chain did not converge in just 2000 samples with the provided hyper-parameter values. We can either improve the estimates by using a much longer chain or use better starting values in the sample method via the start parameter.

Visualizing posterior samples

rsr_samples instance allows for convenient visualization of posterior samples of the parameters of interest. This functionality uses arviz as a backend. We can plot the traces and densities as follows:

[15]:
rsr_samples.plot_trace()
[15]:
array([[<AxesSubplot:title={'center':'alpha'}>,
        <AxesSubplot:title={'center':'alpha'}>],
       [<AxesSubplot:title={'center':'beta'}>,
        <AxesSubplot:title={'center':'beta'}>],
       [<AxesSubplot:title={'center':'tau'}>,
        <AxesSubplot:title={'center':'tau'}>]], dtype=object)
_images/user_guide_29_1.png

Parameters can be passed into the plot_trace method to configure the output plot. See arviz’s API reference for valid input. Similarly, the Effective Sample Size (ESS) can be visualized as follows:

[16]:
rsr_samples.plot_ess()
[16]:
array([[<AxesSubplot:title={'center':'alpha\n0'}, xlabel='Quantile', ylabel='ESS for small intervals'>,
        <AxesSubplot:title={'center':'alpha\n1'}, xlabel='Quantile', ylabel='ESS for small intervals'>,
        <AxesSubplot:title={'center':'alpha\n2'}, xlabel='Quantile', ylabel='ESS for small intervals'>],
       [<AxesSubplot:title={'center':'beta\n0'}, xlabel='Quantile', ylabel='ESS for small intervals'>,
        <AxesSubplot:title={'center':'beta\n1'}, xlabel='Quantile', ylabel='ESS for small intervals'>,
        <AxesSubplot:title={'center':'beta\n2'}, xlabel='Quantile', ylabel='ESS for small intervals'>],
       [<AxesSubplot:title={'center':'tau'}, xlabel='Quantile', ylabel='ESS for small intervals'>,
        <AxesSubplot:>, <AxesSubplot:>]], dtype=object)
_images/user_guide_31_1.png

For more information about other available plots, see documentation of PosteriorParameter class.