Author: Anthony Miyaguchi Last Modified: 2022-12-14
This website demonstrates the results of building birdcall distribution maps with Bayesian modeling methods. I completed this project for the IYSE 6420: Bayesian Statistics course as part of my Fall 2022 semester in Georgia Tech’s OMSCS program. See the project report and source on GitHub for more details.
We use the geographic metadata from the BirdCLEF 2022 competition dataset to build a map to show the location of birdcall recordings. We fit the data to a Poisson Generalized Linear Model (GLM) to estimate covariate or random effects.
We split each region into a grid (or regular lattice) and summarized birdcall recording observations into each grid cell. We define the grid in degrees of latitude or longitude. These discrete cells help fit a Bayesian model to the data and allow us to incorporate external geographical information derived from Google Earth Engine. The cells are small enough to be computationally tractable but large enough to capture the spatial variation in the data. See the Earth Engine Plots page for more information about the data we use from Google Earth Engine.
The posterior predictive is the estimated point prediction for the number of observations in each grid cell derived from the posterior distribution of the model parameters.
Find more information about the Black-crowned Night-Heron on its eBird page.
One key component of Bayesian analysis is the ability to quantify uncertainty in the model predictions. We do this by sampling from the posterior distribution of the model parameters. These samples form a trace. We can summarize these traces into credible intervals, which describes how often a sample falls within a particular range.
We take advantage of this uncertainty to classify whether a particular parameter in the model is significant. We say that a parameter in the model is significant if it’s credible interval does not include zero (i.e. an analogy to rejecting the null hypothesis in a frequentist analysis).
This table contains posterior estimates for hyper-parameters for the CAR distribution such as and , as well as the intercept and slope parameters for the linear regression.
index | mean | sd | hdi_2.5% | hdi_97.5% |
---|---|---|---|---|
intercept | -12.859 | 2.875 | -18.526 | -7.842 |
betas[LST_Day_1km_p5] | 8.218 | 4.002 | 0.464 | 16.194 |
betas[land_cover_08_woody_savannas] | -2.178 | 1.072 | -4.322 | -0.129 |
betas[land_cover_09_savannas] | 5.372 | 1.815 | 2.058 | 9.124 |
betas[land_cover_10_grasslands] | -1.95 | 0.95 | -3.912 | -0.182 |
alpha | 0.811 | 0.143 | 0.531 | 0.999 |
tau_phi | 0.052 | 0.032 | 0.01 | 0.114 |
Note that the land cover classification features often change from species to species. We can infer types of habits or environmental preferences from the significant features in the model.
This measures random spatial variation across grid cells. The prior is drawn from the CAR distribution i.e. .
index | mean | sd | hdi_2.5% | hdi_97.5% |
---|---|---|---|---|
phi[129.0] | 2.549 | 1.321 | 0.091 | 5.275 |
Observe how the random effects explain more of the variance in the simpler intercept_car
model than in the more complex intercept_car_spatial
model.
The prior is the rate parameter, which controls the expected number of observations in each grid cell. Note there are some notational inconsistencies here; this is the same as our parameter in the model definitions, and is properly known as in the Poisson distribution.
index | mean | sd | hdi_2.5% | hdi_97.5% |
---|---|---|---|---|
mu[0] | 4.582 | 2.09 | 1.044 | 8.659 |
mu[2] | 0.766 | 0.764 | 0.003 | 2.28 |
mu[14] | 1.363 | 1.108 | 0.01 | 3.55 |
mu[27] | 1.359 | 1.102 | 0.016 | 3.535 |
mu[42] | 2.549 | 1.548 | 0.171 | 5.564 |
mu[53] | 6.146 | 2.459 | 1.936 | 11.053 |
mu[64] | 2.687 | 1.599 | 0.256 | 5.807 |
mu[125] | 1.806 | 1.286 | 0.075 | 4.334 |
mu[129] | 4.168 | 2.005 | 0.984 | 8.228 |
mu[130] | 0.651 | 0.708 | 0.001 | 2.077 |
Data for this project can be found in the gs://iyse6420-birdcall-distribution
bucket.
Here are the direct links to source data:
You can load this data directly into a Python session using pandas
and pyarrow
:
>>> import pandas as pd
>>> df = pd.read_parquet("https://storage.googleapis.com/iyse6420-birdcall-distribution/ee_v3_ca_1.parquet")
>>> df.head()
name region grid_size population_density ... land_cover_14 land_cover_15 land_cover_16 land_cover_17
0 -125_39 ca 1 7.639377 ... 0 0 0 117
1 -125_40 ca 1 172360.641191 ... 0 0 2 1032
2 -125_41 ca 1 48910.677999 ... 0 0 0 1386
3 -125_42 ca 1 39462.664024 ... 0 0 0 1436
4 -124_38 ca 1 32485.186359 ... 0 0 3 1348
[5 rows x 30 columns]
>>> df.shape
(68, 30)