unmarked
Facilited by proliferation of passive detector data (e.g. cameras)
Activity pattern analysis (e.g. Ridout and Linkie 2009, overlap
R package)
Doesn't necessarily test if species are typically found in the same locations
Multispecies occupancy models
Don't necessary test if species are active at the same time
$f_1$: Term associated with occupancy of species 1 by itself
$f_2$: Term associated with occupancy of species 2 by itself
$f_{12}$: Interaction term between the two species
If $f_{12}$ is positive, presence of one species increases occupancy probability of the other
If $f_{12}$ is negative, presence of one species decreases occupancy probability of the other
Each element of $\mathbf{\psi}$ is a function of the natural parameters $f$.
$$ \begin{align} \psi_{11} & \propto exp(f_{1} + f_{2} + f_{12}) \\ \psi_{10} & \propto exp(f_{1}) \\ \psi_{01} & \propto exp(f_{2}) \\ \psi_{00} & \propto exp(0) = 1 \end{align} $$Making sure $\mathbf{\psi}$ sums to 1:
$$ \psi_{11} = \frac{exp(f_{1} + f_{2} + f_{12})}{1 + exp(f_{1}) + exp(f_{2}) + exp(f_{1} + f_{2} + f_{12})} $$$$ \psi_{10} = \frac{exp(f_{1})}{1 + exp(f_{1}) + exp(f_{2}) + exp(f_{1} + f_{2} + f_{12})} $$$$ \psi_{01} = \frac{exp(f_{2})}{1 + exp(f_{1}) + exp(f_{2}) + exp(f_{1} + f_{2} + f_{12})} $$$$ \psi_{00} = \frac{1}{1 + exp(f_{1}) + exp(f_{2}) + exp(f_{1} + f_{2} + f_{12})} $$For example, detection/nondetection of species 1 at site $i$ and occasion $j$ can be modeled as
$ y_{1,ij} \sim \mathrm{Bernoulli}(p_{1} * z_{1,i}) $
where $z_{1,i}$ is the element 1 of $Z_i$ (i.e., latent presence/absence of species 1 at site $i$) and $p_{1}$ is the species 1 detection probability
Look at the data
library(unmarked)
data(MesoCarnivores)
lapply(MesoCarnivores, head) # look at raw data
X1 | X2 | X3 |
---|---|---|
0 | 0 | 0 |
0 | 0 | 0 |
0 | 0 | 0 |
0 | 0 | 0 |
0 | 0 | 0 |
0 | 0 | 0 |
X1 | X2 | X3 |
---|---|---|
0 | 0 | 0 |
0 | 0 | 0 |
0 | 0 | 0 |
0 | 0 | 0 |
0 | 0 | 0 |
0 | 0 | 0 |
X1 | X2 | X3 |
---|---|---|
0 | 0 | 0 |
0 | 0 | 0 |
0 | 0 | 1 |
0 | 0 | 0 |
0 | 0 | 0 |
1 | 1 | 1 |
Dist_5km | HDens_5km | Latitude | Longitude | People_site | Trail | |
---|---|---|---|---|---|---|
<dbl> | <dbl> | <dbl> | <dbl> | <dbl> | <int> | |
1 | 0.04 | 9.345258 | 0.3899441 | -0.7723958 | 0.857 | 1 |
2 | 0.03 | 9.499197 | 0.3899250 | -0.7723920 | 0.002 | 0 |
3 | 0.03 | 9.647173 | 0.3899111 | -0.7723954 | 0.387 | 1 |
4 | 0.03 | 9.598066 | 0.3899166 | -0.7723972 | 0.003 | 0 |
5 | 0.03 | 9.607825 | 0.3899179 | -0.7724004 | 0.000 | 0 |
6 | 0.03 | 9.748791 | 0.3899058 | -0.7724046 | 0.443 | 1 |
For now, we will fit a 2-species model (coyote and red fox) with no covariates
jags_data <- list(
y_coy = MesoCarnivores$coyote, # coyote matrix
y_fox = MesoCarnivores$redfox, # red fox matrix
N = nrow(MesoCarnivores$coyote), # num sites
J = ncol(MesoCarnivores$coyote) # num samples
)
In BUGS code:
Z[i] ~ dcat(Psi[1:4]) # Takes on values 1-4
In BUGS code:
Psi[1] <- exp(f1 + f2 + f12) # {11}
Psi[2] <- exp(f1) # {10}
Psi[3] <- exp(f2) # {01}
Psi[4] <- 1 # {00}
# Priors on natural parameters
f1 ~ dnorm(0, 0.01)
f2 ~ dnorm(0, 0.01)
f12 ~ dnorm(0, 0.01)
JAGS dcat
automatically divides Psi
by sum(Psi)
to make sure Psi
sums to 1
In BUGS code:
for (i in 1:N){
z1[i] <- (Z[i] == 1) + (Z[i] == 2) # is coyote present?
z2[i] <- (Z[i] == 1) + (Z[i] == 3) # is red fox present?
for (j in 1:J){
y_coy[i, j] ~ dbern(z1[i] * p1)
y_fox[i, j] ~ dbern(z2[i] * p2)
}
}
p1 ~ dunif(0, 1)
p2 ~ dunif(0, 1)
cat(file="jags_multispecies_null.txt", "
model {
# State process
for (i in 1:N){
# latent occupancy state
Z[i] ~ dcat(Psi[1:4]) # Takes on values 1-4
}
# Occupancy probabilities / multinomial logit
Psi[1] <- exp(f1 + f2 + f12) # {11}
Psi[2] <- exp(f1) # {10}
Psi[3] <- exp(f2) # {01}
Psi[4] <- 1 # {00}
# Priors on natural parameters
f1 ~ dnorm(0, 0.01)
f2 ~ dnorm(0, 0.01)
f12 ~ dnorm(0, 0.01)
# Detection process
for (i in 1:N){
z1[i] <- (Z[i] == 1) + (Z[i] == 2) # is coyote present?
z2[i] <- (Z[i] == 1) + (Z[i] == 3) # is red fox present?
for (j in 1:J){
y_coy[i, j] ~ dbern(z1[i] * p1)
y_fox[i, j] ~ dbern(z2[i] * p2)
}
}
# Priors on p
p1 ~ dunif(0, 1)
p2 ~ dunif(0, 1)
}
")
library(jagsUI)
inits <- function(){
list(Z = rep(1, jags_data$N))
}
params <- c("f1", "f2", "f12", "p1", "p2")
fit <- jags(data = jags_data, inits = inits, parameters.to.save = params,
model.file = 'jags_multispecies_null.txt', n.chains = 3, n.iter = 1000,
n.burnin = 500, n.thin = 1, parallel = TRUE)
Processing function input....... Done. Beginning parallel processing using 3 cores. Console output will be suppressed. Parallel processing completed. Calculating statistics....... Done.
fit
traceplot(fit)
JAGS output for model 'jags_multispecies_null.txt', generated by jagsUI. Estimates based on 3 chains of 1000 iterations, adaptation = 100 iterations (sufficient), burn-in = 500 iterations and thin rate = 1, yielding 1500 total samples from the joint posterior. MCMC ran in parallel for 0.399 minutes at time 2023-07-18 11:52:54.207778. mean sd 2.5% 50% 97.5% overlap0 f Rhat n.eff f1 -0.791 0.080 -0.952 -0.790 -0.629 FALSE 1 1.044 51 f2 -2.321 0.149 -2.601 -2.318 -2.035 FALSE 1 1.006 342 f12 1.094 0.212 0.658 1.090 1.495 FALSE 1 1.010 194 p1 0.417 0.018 0.381 0.417 0.452 FALSE 1 1.031 76 p2 0.435 0.029 0.380 0.434 0.492 FALSE 1 1.008 813 deviance 2851.580 63.369 2736.060 2848.895 2983.615 FALSE 1 1.026 97 Successful convergence based on Rhat values (all < 1.1). Rhat is the potential scale reduction factor (at convergence, Rhat=1). For each parameter, n.eff is a crude measure of effective sample size. overlap0 checks if 0 falls in the parameter's 95% credible interval. f is the proportion of the posterior with the same sign as the mean; i.e., our confidence that the parameter is positive or negative. DIC info: (pD = var(deviance)/2) pD = 1968.7 and DIC = 4820.273 DIC is an estimate of expected predictive error (lower is better).
We now need to index Psi
and the natural parameters f
by site, i
.
for (i in 1:N){
Z[i] ~ dcat(Psi[i, 1:4]) # Takes on values 1-4
Psi[i,1] <- exp(f1[i] + f2[i] + f12[i]) # {11}
Psi[i,2] <- exp(f1[i]) # {10}
Psi[i,3] <- exp(f2[i]) # {01}
Psi[i,4] <- 1 # {00}
# ... truncated
}
In BUGS code:
for (i in 1:N){
# ... truncated
f1[i] <- alpha_f1 + beta_f1 * hdens[i]
f2[i] <- alpha_f2 + beta_f2 * hdens[i]
f12[i] <- alpha_f12
}
cat(file="jags_multispecies_covs.txt", "
model {
# State process
for (i in 1:N){
# latent occupancy state
Z[i] ~ dcat(Psi[i, 1:4]) # Takes on values 1-4
# Occupancy probabilities / multinomial logit
Psi[i,1] <- exp(f1[i] + f2[i] + f12[i]) # {11}
Psi[i,2] <- exp(f1[i]) # {10}
Psi[i,3] <- exp(f2[i]) # {01}
Psi[i,4] <- 1 # {00}
# Natural parameters
f1[i] <- alpha_f1 + beta_f1 * hdens[i]
f2[i] <- alpha_f2 + beta_f2 * hdens[i]
f12[i] <- alpha_f12
}
# Priors on state parameters
alpha_f1 ~ dunif(-5, 5)
beta_f1 ~ dnorm(0, 0.01)
alpha_f2 ~ dunif(-5, 5)
beta_f2 ~ dnorm(0, 0.01)
alpha_f12 ~ dunif(-5, 5)
# Detection process
for (i in 1:N){
z1[i] <- (Z[i] == 1) + (Z[i] == 2) # is coyote present?
z2[i] <- (Z[i] == 1) + (Z[i] == 3) # is red fox present?
for (j in 1:J){
y_coy[i, j] ~ dbern(z1[i] * p1)
y_fox[i, j] ~ dbern(z2[i] * p2)
}
}
# Priors on p
p1 ~ dunif(0,1)
p2 ~ dunif(0,1)
}
")
jags_data <- list(
y_coy = MesoCarnivores$coyote, # coyote matrix
y_fox = MesoCarnivores$redfox, # red fox matrix
hdens = as.numeric(scale(MesoCarnivores$sitecovs$HDens_5km)), # covariate
N = nrow(MesoCarnivores$coyote), # num sites
J = ncol(MesoCarnivores$coyote) # num samples
)
inits <- function(){
list(Z = rep(1, jags_data$N))
}
params <- c("alpha_f1", "beta_f1", "alpha_f2", "beta_f2",
"alpha_f12", "p1", "p2")
fit <- jags(data = jags_data, inits = inits, parameters.to.save = params,
model.file = 'jags_multispecies_covs.txt', n.chains = 3, n.iter = 100,
n.burnin = 50, n.thin = 1, parallel = TRUE)
fit
Processing function input....... Done. Beginning parallel processing using 3 cores. Console output will be suppressed. Parallel processing completed. Calculating statistics....... Done.
JAGS output for model 'jags_multispecies_covs.txt', generated by jagsUI. Estimates based on 3 chains of 100 iterations, adaptation = 100 iterations (sufficient), burn-in = 50 iterations and thin rate = 1, yielding 150 total samples from the joint posterior. MCMC ran in parallel for 0.285 minutes at time 2023-07-18 11:57:12.867507. mean sd 2.5% 50% 97.5% overlap0 f Rhat n.eff alpha_f1 -0.776 0.084 -0.942 -0.776 -0.629 FALSE 1.00 1.171 15 beta_f1 0.006 0.063 -0.121 0.005 0.114 TRUE 0.54 1.025 150 alpha_f2 -2.341 0.171 -2.762 -2.333 -2.066 FALSE 1.00 1.095 45 beta_f2 0.549 0.108 0.371 0.524 0.778 FALSE 1.00 1.090 30 alpha_f12 0.989 0.215 0.601 0.977 1.486 FALSE 1.00 1.121 114 p1 0.421 0.021 0.382 0.419 0.460 FALSE 1.00 1.142 19 p2 0.433 0.037 0.362 0.430 0.497 FALSE 1.00 1.026 80 deviance 2849.594 69.478 2715.173 2850.116 2981.134 FALSE 1.00 1.120 27 **WARNING** Rhat values indicate convergence failure. Rhat is the potential scale reduction factor (at convergence, Rhat=1). For each parameter, n.eff is a crude measure of effective sample size. overlap0 checks if 0 falls in the parameter's 95% credible interval. f is the proportion of the posterior with the same sign as the mean; i.e., our confidence that the parameter is positive or negative. DIC info: (pD = var(deviance)/2) pD = 2257 and DIC = 5106.6 DIC is an estimate of expected predictive error (lower is better).
JAGS output for model 'jags_multispecies_covs.txt', generated by jagsUI.
Estimates based on 3 chains of 10000 iterations,
adaptation = 100 iterations (sufficient),
burn-in = 8000 iterations and thin rate = 5,
yielding 1200 total samples from the joint posterior.
MCMC ran in parallel for 12.987 minutes at time 2023-07-07 08:57:50.122961.
mean sd 2.5% 50% 97.5% overlap0 f Rhat n.eff
alpha_f1 -0.783 0.083 -0.947 -0.782 -0.617 FALSE 1.000 1.002 1200
beta_f1 -0.001 0.074 -0.153 -0.003 0.150 TRUE 0.508 1.003 621
alpha_f2 -2.399 0.158 -2.720 -2.395 -2.105 FALSE 1.000 1.002 711
beta_f2 0.529 0.092 0.365 0.523 0.728 FALSE 1.000 1.000 1200
alpha_f12 1.075 0.230 0.643 1.066 1.534 FALSE 1.000 1.001 996
deviance 2856.690 62.011 2738.322 2855.443 2975.947 FALSE 1.000 1.001 1200
Successful convergence based on Rhat values (all < 1.1).
Rhat is the potential scale reduction factor (at convergence, Rhat=1).
For each parameter, n.eff is a crude measure of effective sample size.
overlap0 checks if 0 falls in the parameter's 95% credible interval.
f is the proportion of the posterior with the same sign as the mean;
i.e., our confidence that the parameter is positive or negative.
DIC info: (pD = var(deviance)/2)
pD = 1924.6 and DIC = 4781.304
DIC is an estimate of expected predictive error (lower is better).
mean sd 2.5% 50% 97.5% overlap0 f Rhat n.eff
beta_f1 -0.001 0.074 -0.153 -0.003 0.150 TRUE 0.508 1.003 621
No evidence housing density affects coyote occupancy (remember, species 1 = coyote)
mean sd 2.5% 50% 97.5% overlap0 f Rhat n.eff
beta_f2 0.529 0.092 0.365 0.523 0.728 FALSE 1.000 1.000 1200
Positive relationship between housing density and red fox occupancy
mean sd 2.5% 50% 97.5% overlap0 f Rhat n.eff
alpha_f12 1.075 0.230 0.643 1.066 1.534 FALSE 1.000 1.001 996
Positive interaction between coyote and red fox occupancy; that is, if coyote is present occupancy of red fox is higher (and vice-versa)
What if we force $f_{12} = 0$?
$$ \begin{align} \psi_{11} & \propto exp(f_{1} + f_{2}) \\ \psi_{10} & \propto exp(f_{1}) \\ \psi_{01} & \propto exp(f_{2}) \\ \psi_{00} & \propto 1 \end{align} $$This is equivalent to fitting two separate occupancy models. I'll show this later.
unmarked
makes things easier to scalelibrary(unmarked)
data(MesoCarnivores)
lapply(MesoCarnivores, head) # look at raw data
X1 | X2 | X3 |
---|---|---|
0 | 0 | 0 |
0 | 0 | 0 |
0 | 0 | 0 |
0 | 0 | 0 |
0 | 0 | 0 |
0 | 0 | 0 |
X1 | X2 | X3 |
---|---|---|
0 | 0 | 0 |
0 | 0 | 0 |
0 | 0 | 0 |
0 | 0 | 0 |
0 | 0 | 0 |
0 | 0 | 0 |
X1 | X2 | X3 |
---|---|---|
0 | 0 | 0 |
0 | 0 | 0 |
0 | 0 | 1 |
0 | 0 | 0 |
0 | 0 | 0 |
1 | 1 | 1 |
Dist_5km | HDens_5km | Latitude | Longitude | People_site | Trail | |
---|---|---|---|---|---|---|
<dbl> | <dbl> | <dbl> | <dbl> | <dbl> | <int> | |
1 | 0.04 | 9.345258 | 0.3899441 | -0.7723958 | 0.857 | 1 |
2 | 0.03 | 9.499197 | 0.3899250 | -0.7723920 | 0.002 | 0 |
3 | 0.03 | 9.647173 | 0.3899111 | -0.7723954 | 0.387 | 1 |
4 | 0.03 | 9.598066 | 0.3899166 | -0.7723972 | 0.003 | 0 |
5 | 0.03 | 9.607825 | 0.3899179 | -0.7724004 | 0.000 | 0 |
6 | 0.03 | 9.748791 | 0.3899058 | -0.7724046 | 0.443 | 1 |
We will create an unmarkedFrameOccuMulti
.
The main difference from unmarkedFrameOccu
is that you have >1 matrix of observations: we now have one y
per species.
Get some more detail by looking at the help file for unmarkedFrameOccuMulti
:
?unmarkedFrameOccuMulti
The first three elements of MesoCarnivores
are the y-matrices. To keep things simple, we'll just use coyote and red fox.
Notice that the resulting list is named: this is important!
ylist <- MesoCarnivores[c(2:3)]
lapply(ylist, head) # look at first few rows
X1 | X2 | X3 |
---|---|---|
0 | 0 | 0 |
0 | 0 | 0 |
0 | 0 | 0 |
0 | 0 | 0 |
0 | 0 | 0 |
0 | 0 | 0 |
X1 | X2 | X3 |
---|---|---|
0 | 0 | 0 |
0 | 0 | 0 |
0 | 0 | 1 |
0 | 0 | 0 |
0 | 0 | 0 |
1 | 1 | 1 |
The last element of the MesoCarnivores
list is a data frame of site covariates:
site_covs <- MesoCarnivores$sitecovs
head(site_covs)
Dist_5km | HDens_5km | Latitude | Longitude | People_site | Trail | |
---|---|---|---|---|---|---|
<dbl> | <dbl> | <dbl> | <dbl> | <dbl> | <int> | |
1 | 0.04 | 9.345258 | 0.3899441 | -0.7723958 | 0.857 | 1 |
2 | 0.03 | 9.499197 | 0.3899250 | -0.7723920 | 0.002 | 0 |
3 | 0.03 | 9.647173 | 0.3899111 | -0.7723954 | 0.387 | 1 |
4 | 0.03 | 9.598066 | 0.3899166 | -0.7723972 | 0.003 | 0 |
5 | 0.03 | 9.607825 | 0.3899179 | -0.7724004 | 0.000 | 0 |
6 | 0.03 | 9.748791 | 0.3899058 | -0.7724046 | 0.443 | 1 |
umf <- unmarkedFrameOccuMulti(y=ylist, siteCovs=site_covs)
head(umf)
Data frame representation of unmarkedFrame object. Only showing observation matrix for species 1. y.1 y.2 y.3 Dist_5km HDens_5km Latitude Longitude People_site Trail 1 0 0 0 0.04 9.345258 0.3899441 -0.7723958 0.857 1 2 0 0 0 0.03 9.499197 0.3899250 -0.7723920 0.002 0 3 0 0 0 0.03 9.647173 0.3899111 -0.7723954 0.387 1 4 0 0 0 0.03 9.598066 0.3899166 -0.7723972 0.003 0 5 0 0 0 0.03 9.607825 0.3899179 -0.7724004 0.000 0 6 0 0 0 0.03 9.748791 0.3899058 -0.7724046 0.443 1 7 0 0 0 0.03 9.715359 0.3899097 -0.7724065 0.000 0 8 0 0 0 0.03 9.685091 0.3899135 -0.7724103 0.000 0 9 0 0 0 0.04 9.051558 0.3899955 -0.7724561 0.002 0 10 0 0 0 0.04 9.031836 0.3899971 -0.7724504 0.000 0
summary(umf)
unmarkedFrame Object 1437 sites 2 species: coyote redfox Maximum number of observations per site: 3 Mean number of observations per site: coyote: 3 redfox: 3 Sites with at least one detection: coyote: 401 redfox: 161 Tabulation of y observations: coyote: 0 1 3685 626 redfox: 0 1 4054 257 Site-level covariates: Dist_5km HDens_5km Latitude Longitude Min. :0.00000 Min. : 0.0000 Min. :0.3454 Min. :-0.8539 1st Qu.:0.00000 1st Qu.: 0.2073 1st Qu.:0.3567 1st Qu.:-0.8009 Median :0.00000 Median : 0.7310 Median :0.3753 Median :-0.7940 Mean :0.01419 Mean : 8.4532 Mean :0.3726 Mean :-0.7969 3rd Qu.:0.02000 3rd Qu.: 3.0219 3rd Qu.:0.3863 3rd Qu.:-0.7801 Max. :0.13000 Max. :186.6694 Max. :0.3967 Max. :-0.7690 People_site Trail Min. :0.00000 Min. :0.0000 1st Qu.:0.00000 1st Qu.:0.0000 Median :0.00000 Median :0.0000 Mean :0.05807 Mean :0.3229 3rd Qu.:0.00900 3rd Qu.:1.0000 Max. :2.44100 Max. :1.0000
plot(umf)
While occu
had a single formula for occupancy, occuMulti
requires one formula per natural parameter $f$, organized into a stateformulas
vector.
Similarly, each species has its own detection probability formula organized into a detformulas
vector.
stateformulas
¶It can be hard to keep track of how many natural parameters there are and what each one represents.
It can be helpful to look at the $f$-design matrix, which is generated by unmarkedFrameOccuMulti
.
umf@fDesign
f1[coyote] | f2[redfox] | f3[coyote:redfox] | |
---|---|---|---|
psi[11] | 1 | 1 | 1 |
psi[10] | 1 | 0 | 0 |
psi[01] | 0 | 1 | 0 |
psi[00] | 0 | 0 | 0 |
The number and order of the formulas in the stateformulas
vector should match the column names of this matrix.
Therefore we'll need 3 formulas total.
For this model we'll set the 1st-order $f$ parameters to be a function of (standardized) housing density. The interaction term will be intercept-only.
Our stateformulas
should look like this:
stateformulas <- c("~scale(HDens_5km)","~scale(HDens_5km)","~1")
stateformulas
Notice that the formulas are strings (each wrapped in ""
). This is required and is just working around some R limitations.
detformulas
¶This one is easier, there is just one formula per species, so there should be 2 total.
detformulas <- c("~1","~1")
detformulas
occuMulti
¶?occuMulti
We now have all the pieces we need (unmarkedFrameOccuMulti
, stateformulas
, detformulas
) needed to run a model.
mod_hdens <- occuMulti(detformulas=detformulas, stateformulas=stateformulas, data=umf)
mod_hdens
Call: occuMulti(detformulas = detformulas, stateformulas = stateformulas, data = umf, maxOrder = 2L) Occupancy: Estimate SE z P(>|z|) [coyote] (Intercept) -0.786370 0.0815 -9.64306 5.26e-22 [coyote] scale(HDens_5km) -0.000668 0.0691 -0.00966 9.92e-01 [redfox] (Intercept) -2.391812 0.1598 -14.96684 1.21e-50 [redfox] scale(HDens_5km) 0.504456 0.0813 6.20113 5.61e-10 [coyote:redfox] (Intercept) 1.062921 0.2322 4.57859 4.68e-06 Detection: Estimate SE z P(>|z|) [coyote] (Intercept) -0.333 0.0764 -4.36 1.31e-05 [redfox] (Intercept) -0.251 0.1180 -2.13 3.34e-02 AIC: 4800.859
To get the expected probability $\boldsymbol\psi$ for each occupancy state at each site, use predict
.
This gives you the probabilities along with standard errors and a 95% CI.
occ_prob <- predict(mod_hdens, type="state")
lapply(occ_prob, head)
Bootstrapping confidence intervals with 100 samples
psi[11] | psi[10] | psi[01] | psi[00] |
---|---|---|---|
0.07332333 | 0.2725955 | 0.05560920 | 0.5984720 |
0.07349727 | 0.2724991 | 0.05574131 | 0.5982624 |
0.07366480 | 0.2724062 | 0.05586856 | 0.5980605 |
0.07360916 | 0.2724370 | 0.05582630 | 0.5981275 |
0.07362022 | 0.2724309 | 0.05583470 | 0.5981142 |
0.07378003 | 0.2723423 | 0.05595609 | 0.5979216 |
psi[11] | psi[10] | psi[01] | psi[00] |
---|---|---|---|
0.009299954 | 0.01372185 | 0.008239449 | 0.01640244 |
0.009318341 | 0.01372988 | 0.008250701 | 0.01641179 |
0.009336111 | 0.01373803 | 0.008261590 | 0.01642111 |
0.009330204 | 0.01373527 | 0.008257969 | 0.01641798 |
0.009331377 | 0.01373582 | 0.008258688 | 0.01641860 |
0.009348368 | 0.01374387 | 0.008269109 | 0.01642771 |
psi[11] | psi[10] | psi[01] | psi[00] |
---|---|---|---|
0.05842006 | 0.2492798 | 0.04196283 | 0.5677498 |
0.05855664 | 0.2491984 | 0.04205732 | 0.5674990 |
0.05868817 | 0.2491199 | 0.04214834 | 0.5672575 |
0.05864450 | 0.2491460 | 0.04211811 | 0.5673377 |
0.05865317 | 0.2491408 | 0.04212412 | 0.5673218 |
0.05877864 | 0.2490659 | 0.04221094 | 0.5670914 |
psi[11] | psi[10] | psi[01] | psi[00] |
---|---|---|---|
0.09231603 | 0.2957022 | 0.07049045 | 0.6261836 |
0.09252915 | 0.2955471 | 0.07064506 | 0.6260361 |
0.09273439 | 0.2953979 | 0.07079535 | 0.6258938 |
0.09266624 | 0.2954474 | 0.07074545 | 0.6259411 |
0.09267978 | 0.2954376 | 0.07075537 | 0.6259317 |
0.09287556 | 0.2952953 | 0.07089872 | 0.6257959 |
head(apply(occ_prob$Predicted, 1, sum))
It's often more interesting to look at individual species. For example, you might want to know the marginal occupancy of species 2 (red fox) at a site, which is the probability of red fox occupancy regardless of the occupancy states of other species.
This is calculated by summing all $\psi$ states in which red fox is present:
$$ \psi_{marg,i2} = \psi_{11}+\psi_{01} $$You can do this by specifying the species
argument in predict
.
redfox_marginal <- predict(mod_hdens, type="state", species="redfox")
head(redfox_marginal)
Bootstrapping confidence intervals with 100 samples
Predicted | SE | lower | upper | |
---|---|---|---|---|
<dbl> | <dbl> | <dbl> | <dbl> | |
1 | 0.1289325 | 0.01032871 | 0.1090829 | 0.1505733 |
2 | 0.1292386 | 0.01035021 | 0.1093578 | 0.1509186 |
3 | 0.1295334 | 0.01037112 | 0.1096227 | 0.1512512 |
4 | 0.1294355 | 0.01036416 | 0.1095347 | 0.1511407 |
5 | 0.1294549 | 0.01036554 | 0.1095522 | 0.1511627 |
6 | 0.1297361 | 0.01038561 | 0.1098049 | 0.1514799 |
Compare across species with a plot:
coy_marginal <- predict(mod_hdens, type='state', species="coyote") # get coyote
marg_plot_dat <- rbind(redfox_marginal[1,], coy_marginal[1,])
marg_plot_dat$Species <- c("Red fox", "Coyote")
marg_plot_dat
Bootstrapping confidence intervals with 100 samples
Predicted | SE | lower | upper | Species |
---|---|---|---|---|
<dbl> | <dbl> | <dbl> | <dbl> | <chr> |
0.1289325 | 0.01032871 | 0.1090829 | 0.1505733 | Red fox |
0.3459189 | 0.01633198 | 0.3107790 | 0.3757660 | Coyote |
plot(1:2, marg_plot_dat$Predicted, ylim=c(0.1,0.4),
xlim=c(0.5,2.5), pch=19, cex=1.5, xaxt='n',
xlab="", ylab="Marginal occupancy and 95% CI")
axis(1, at=1:2, labels=marg_plot_dat$Species)
# CIs
top <- 0.1
for (i in 1:2){
segments(i, marg_plot_dat$lower[i], i, marg_plot_dat$upper[i])
segments(i-top, marg_plot_dat$lower[i], i+top)
segments(i-top, marg_plot_dat$upper[i], i+top)
}
Alternatively, you might want to know the probability of occupancy of one species, conditional on the presence of another.
For example, the probability of red fox occupancy, conditional on coyote presence:
$$ \psi_{i, fox, coy} = \frac{\psi_{i{11}}}{\psi_{i{10}} + \psi_{i{11}}}$$And on coyote absence:
$$ \psi_{i, fox, -coy} = \frac{\psi_{i{01}}}{\psi_{i{01}} + \psi_{i{00}}}$$With predict
, use the species
and cond
arguments together for this.
redfox_coy <- predict(mod_hdens, type="state", species="redfox", cond="coyote")
head(redfox_coy)
Bootstrapping confidence intervals with 100 samples
Predicted | SE | lower | upper | |
---|---|---|---|---|
<dbl> | <dbl> | <dbl> | <dbl> | |
1 | 0.2119669 | 0.02406226 | 0.1689318 | 0.2612879 |
2 | 0.2124221 | 0.02410983 | 0.1692723 | 0.2618617 |
3 | 0.2128604 | 0.02415575 | 0.1696001 | 0.2624140 |
4 | 0.2127149 | 0.02414049 | 0.1694913 | 0.2622307 |
5 | 0.2127438 | 0.02414352 | 0.1695129 | 0.2622671 |
6 | 0.2131617 | 0.02418739 | 0.1698255 | 0.2627938 |
What about conditional on coyote absence?
redfox_nocoy <- predict(mod_hdens, type="state", species="redfox", cond="-coyote")
head(redfox_nocoy)
Bootstrapping confidence intervals with 100 samples
Predicted | SE | lower | upper | |
---|---|---|---|---|
<dbl> | <dbl> | <dbl> | <dbl> | |
1 | 0.08501880 | 0.01172126 | 0.06439961 | 0.1066717 |
2 | 0.08523088 | 0.01174802 | 0.06457354 | 0.1068801 |
3 | 0.08543520 | 0.01177391 | 0.06474114 | 0.1070808 |
4 | 0.08536735 | 0.01176530 | 0.06468548 | 0.1070142 |
5 | 0.08538083 | 0.01176701 | 0.06469654 | 0.1070274 |
6 | 0.08557577 | 0.01179178 | 0.06485647 | 0.1072196 |
You can use this output from predict
to generate comparison plots.
plot_data <- rbind(redfox_coy[1,], redfox_nocoy[1,])
plot_data$Coyote_status <- c("Present","Absent")
head(plot_data)
Predicted | SE | lower | upper | Coyote_status | |
---|---|---|---|---|---|
<dbl> | <dbl> | <dbl> | <dbl> | <chr> | |
1 | 0.2119669 | 0.02406226 | 0.16893179 | 0.2612879 | Present |
2 | 0.0850188 | 0.01172126 | 0.06439961 | 0.1066717 | Absent |
plot(1:2, plot_data$Predicted, ylim=c(0, 0.3),
xlim=c(0.5,2.5), pch=19, cex=1.5, xaxt='n',
xlab="Coyote status", ylab="Fox conditional occupancy and 95% CI")
axis(1, at=1:2, labels=plot_data$Coyote_status)
# CIs
top <- 0.1
for (i in 1:2){
segments(i, plot_data$lower[i], i, plot_data$upper[i])
segments(i-top, plot_data$lower[i], i+top)
segments(i-top, plot_data$upper[i], i+top)
}
To plot the effect of housing density on marginal occupancy, we again use predict
.
Hdens_5km
values for X-axis.hdens_range <- range(siteCovs(umf)$HDens_5km)
hdens_range
hdens_seq <- seq(hdens_range[1], hdens_range[2], length.out=100)
predict
occupancy at each value of Hdens_5km
along our sequence. Supply the sequence as a data.frame
to the newdata
argument.nd <- data.frame(HDens_5km = hdens_seq)
occ_hdens_coy <- predict(mod_hdens, type="state", species="coyote", newdata=nd)
occ_hdens_fox <- predict(mod_hdens, type="state", species="redfox", newdata=nd)
head(occ_hdens_coy)
dim(occ_hdens_coy)
Bootstrapping confidence intervals with 100 samples Bootstrapping confidence intervals with 100 samples
Predicted | SE | lower | upper | |
---|---|---|---|---|
<dbl> | <dbl> | <dbl> | <dbl> | |
1 | 0.3415035 | 0.01779357 | 0.3115242 | 0.3717624 |
2 | 0.3423496 | 0.01755841 | 0.3129794 | 0.3727728 |
3 | 0.3432180 | 0.01736981 | 0.3144531 | 0.3738033 |
4 | 0.3441090 | 0.01722933 | 0.3159458 | 0.3748543 |
5 | 0.3450230 | 0.01713821 | 0.3174575 | 0.3763669 |
6 | 0.3459604 | 0.01709731 | 0.3186015 | 0.3779619 |
plot(hdens_seq, occ_hdens_coy$Predicted, type = 'l', col = 'red',
xlab = "Housing density", ylab = "Marginal occupancy", ylim = c(0,0.8))
lines(hdens_seq, occ_hdens_fox$Predicted, col = "blue")
legend("bottomright", col=c("red", "blue"), lty=1, legend=c("coyote", "red fox"))
stateformulas <- c("~scale(HDens_5km)", "~scale(HDens_5km)")
mod_noint <- occuMulti(detformulas=detformulas, stateformulas=stateformulas, data=umf, maxOrder=1)
mod_noint
Call: occuMulti(detformulas = detformulas, stateformulas = stateformulas, data = umf, maxOrder = 1) Occupancy: Estimate SE z P(>|z|) [coyote] (Intercept) -0.631 0.0745 -8.47 2.49e-17 [coyote] scale(HDens_5km) 0.108 0.0628 1.72 8.50e-02 [redfox] (Intercept) -1.921 0.0998 -19.25 1.52e-82 [redfox] scale(HDens_5km) 0.514 0.0811 6.34 2.27e-10 Detection: Estimate SE z P(>|z|) [coyote] (Intercept) -0.332 0.0763 -4.36 1.33e-05 [redfox] (Intercept) -0.261 0.1195 -2.19 2.87e-02 AIC: 4822.196
umf_coy <- unmarkedFrameOccu(y=ylist$coyote, siteCovs=site_covs)
occu(~1~scale(HDens_5km), umf_coy)
Call: occu(formula = ~1 ~ scale(HDens_5km), data = umf_coy) Occupancy: Estimate SE z P(>|z|) (Intercept) -0.631 0.0745 -8.47 2.51e-17 scale(HDens_5km) 0.108 0.0628 1.72 8.49e-02 Detection: Estimate SE z P(>|z|) -0.332 0.0763 -4.36 1.32e-05 AIC: 3245.169
MesoCarnivores
dataset (i.e., add bobcat)unmarked
unmarked
hints: set maxOrder
argument to occuMulti
to 2. stateformulas
: for f1, f2, f3, f12, f13, f23
cat(file="jags_multispecies_3.txt", "
model {
# State process
for (i in 1:N){
# latent occupancy state
Z[i] ~ dcat(Psi[i, 1:8]) # Takes on values 1-8
# Occupancy probabilities
Psi[i, 1] <- exp(f1[i] + f2[i] + f3[i] + f12[i] + f13[i] + f23[i]) # {111}
Psi[i, 2] <- exp(f1[i] + f2[i] + f12[i]) # {110}
Psi[i, 3] <- exp(f1[i] + f3[i] + f13[i]) # {101}
Psi[i, 4] <- exp(f2[i] + f3[i] + f23[i]) # {011}
Psi[i, 5] <- exp(f1[i]) # {100}
Psi[i, 6] <- exp(f2[i]) # {010}
Psi[i, 7] <- exp(f3[i]) # {001}
Psi[i, 8] <- 1 # {000}
# Natural parameters
f1[i] <- alpha_f1 + beta_f1 * hdens[i]
f2[i] <- alpha_f2 + beta_f2 * hdens[i]
f3[i] <- alpha_f3 + beta_f3 * hdens[i]
f12[i] <- alpha_f12
f13[i] <- alpha_f13
f23[i] <- alpha_f23
}
# State priors
alpha_f1 ~ dunif(-5, 5)
beta_f1 ~ dnorm(0, 0.01)
alpha_f2 ~ dunif(-5, 5)
beta_f2 ~ dnorm(0, 0.01)
alpha_f3 ~ dunif(-5, 5)
beta_f3 ~ dnorm(0, 0.01)
alpha_f12 ~ dunif(-5,5)
alpha_f13 ~ dunif(-5,5)
alpha_f23 ~ dunif(-5,5)
# Detection process
for (i in 1:N){
z1[i] <- (Z[i] == 1) + (Z[i] == 2) + (Z[i] == 3) + (Z[i] == 5) # is coyote present?
z2[i] <- (Z[i] == 1) + (Z[i] == 2) + (Z[i] == 4) + (Z[i] == 6) # is red fox present?
z3[i] <- (Z[i] == 1) + (Z[i] == 3) + (Z[i] == 4) + (Z[i] == 7) # is bobcat present?
for (j in 1:J){
y_coy[i, j] ~ dbern(z1[i] * p1)
y_fox[i, j] ~ dbern(z2[i] * p2)
y_bob[i, j] ~ dbern(z3[i] * p3)
}
}
# Detection priors
p1 ~ dunif(0,1)
p2 ~ dunif(0,1)
p3 ~ dunif(0,1)
}
")
unmarked
code¶ylist <- MesoCarnivores[c(1:3)]
umf <- unmarkedFrameOccuMulti(y=ylist, siteCovs=site_covs)
stateformulas <- c("~scale(HDens_5km)","~scale(HDens_5km)","~scale(HDens_5km)","~1","~1","~1")
detformulas <- rep("~1", 3)
(mod_3species <- occuMulti(detformulas=detformulas, stateformulas=stateformulas, data=umf, maxOrder = 2))
Call: occuMulti(detformulas = detformulas, stateformulas = stateformulas, data = umf, maxOrder = 2) Occupancy: Estimate SE z P(>|z|) [bobcat] (Intercept) -2.5364 0.2842 -8.92 4.53e-19 [bobcat] scale(HDens_5km) -3.6008 0.9191 -3.92 8.94e-05 [coyote] (Intercept) -1.3439 0.1470 -9.14 6.04e-20 [coyote] scale(HDens_5km) 0.0884 0.0742 1.19 2.34e-01 [redfox] (Intercept) -2.2555 0.1566 -14.41 4.65e-47 [redfox] scale(HDens_5km) 0.4392 0.0831 5.29 1.24e-07 [bobcat:coyote] (Intercept) 1.8173 0.2714 6.70 2.16e-11 [bobcat:redfox] (Intercept) -1.3385 0.3869 -3.46 5.42e-04 [coyote:redfox] (Intercept) 1.3740 0.2597 5.29 1.22e-07 Detection: Estimate SE z P(>|z|) [bobcat] (Intercept) -1.139 0.1421 -8.02 1.07e-15 [coyote] (Intercept) -0.328 0.0759 -4.32 1.53e-05 [redfox] (Intercept) -0.252 0.1179 -2.14 3.26e-02 AIC: 6530.476
state_complex <- c(rep("~scale(Dist_5km)+scale(HDens_5km)", 6), 0)
det_complex <- rep("~Trail",3)
mod_complex <- occuMulti(stateformulas=state_complex, detformulas=det_complex, umf)
mod_complex
Call: occuMulti(detformulas = det_complex, stateformulas = state_complex, data = umf, maxOrder = 3L) Occupancy: Estimate SE z P(>|z|) [bobcat] (Intercept) -23.0171 5.787 -3.977 6.97e-05 [bobcat] scale(Dist_5km) -2.4249 0.689 -3.518 4.34e-04 [bobcat] scale(HDens_5km) -82.3836 19.799 -4.161 3.17e-05 [coyote] (Intercept) -0.6789 0.225 -3.017 2.55e-03 [coyote] scale(Dist_5km) -0.0176 0.139 -0.127 8.99e-01 [coyote] scale(HDens_5km) -0.5534 0.748 -0.740 4.59e-01 [redfox] (Intercept) -1.3946 0.257 -5.425 5.79e-08 [redfox] scale(Dist_5km) -0.5293 0.250 -2.114 3.45e-02 [redfox] scale(HDens_5km) 0.2108 0.261 0.808 4.19e-01 [bobcat:coyote] (Intercept) 6.7598 6.390 1.058 2.90e-01 [bobcat:coyote] scale(Dist_5km) 1.6979 0.695 2.444 1.45e-02 [bobcat:coyote] scale(HDens_5km) 17.9202 21.460 0.835 4.04e-01 [bobcat:redfox] (Intercept) 15.3983 3.461 4.449 8.64e-06 [bobcat:redfox] scale(Dist_5km) 0.8836 0.439 2.014 4.40e-02 [bobcat:redfox] scale(HDens_5km) 64.1330 12.375 5.182 2.19e-07 [coyote:redfox] (Intercept) 1.1084 0.363 3.050 2.29e-03 [coyote:redfox] scale(Dist_5km) 0.1149 0.340 0.338 7.35e-01 [coyote:redfox] scale(HDens_5km) 0.9046 0.781 1.159 2.47e-01 Detection: Estimate SE z P(>|z|) [bobcat] (Intercept) -2.83 0.1419 -19.91 3.12e-88 [bobcat] Trail 1.74 0.1542 11.26 2.10e-29 [coyote] (Intercept) -1.96 0.0984 -19.88 5.90e-88 [coyote] Trail 2.17 0.1220 17.75 1.63e-70 [redfox] (Intercept) -1.59 0.1601 -9.93 2.97e-23 [redfox] Trail 1.78 0.1997 8.93 4.12e-19 AIC: 5958.196
optimizePenalty
function (Clipp et al. 2021)"Bayes-inspired" penalty (Hutchinson et al. 2015):
$$ -\lambda\frac{1}{2}\sum_i{}\theta_i^2 $$Where $\theta$ is the vector of parameter estimates.
Size of penalty increases as values of $\theta$ increase.
Tradeoff:
mod_penalty <- occuMulti(stateformulas=state_complex, detformulas=det_complex, umf, penalty=1)
mod_penalty
Bootstraping covariance matrix
Call:
occuMulti(detformulas = det_complex, stateformulas = state_complex,
data = umf, penalty = 1, maxOrder = 3L)
Occupancy:
Estimate SE z P(>|z|)
[bobcat] (Intercept) -1.7810 0.269 -6.627 3.43e-11
[bobcat] scale(Dist_5km) -1.3143 0.293 -4.491 7.08e-06
[bobcat] scale(HDens_5km) -2.8200 0.539 -5.230 1.70e-07
[coyote] (Intercept) -0.6049 0.214 -2.830 4.66e-03
[coyote] scale(Dist_5km) 0.0285 0.106 0.270 7.87e-01
[coyote] scale(HDens_5km) -1.0908 0.378 -2.887 3.88e-03
[redfox] (Intercept) -1.5659 0.305 -5.140 2.75e-07
[redfox] scale(Dist_5km) -0.3068 0.157 -1.958 5.02e-02
[redfox] scale(HDens_5km) 0.4730 0.546 0.867 3.86e-01
[bobcat:coyote] (Intercept) 1.1871 0.434 2.736 6.22e-03
[bobcat:coyote] scale(Dist_5km) 0.9347 0.346 2.705 6.84e-03
[bobcat:coyote] scale(HDens_5km) -0.3218 1.008 -0.319 7.50e-01
[bobcat:redfox] (Intercept) -0.8831 0.347 -2.545 1.09e-02
[bobcat:redfox] scale(Dist_5km) 0.0364 0.305 0.119 9.05e-01
[bobcat:redfox] scale(HDens_5km) 2.5609 1.074 2.384 1.71e-02
[coyote:redfox] (Intercept) 1.0001 0.310 3.227 1.25e-03
[coyote:redfox] scale(Dist_5km) 0.0236 0.167 0.141 8.87e-01
[coyote:redfox] scale(HDens_5km) 1.3920 0.345 4.030 5.57e-05
Detection:
Estimate SE z P(>|z|)
[bobcat] (Intercept) -2.44 0.1755 -13.89 7.63e-44
[bobcat] Trail 1.74 0.1966 8.87 7.25e-19
[coyote] (Intercept) -1.89 0.0926 -20.45 5.64e-93
[coyote] Trail 2.10 0.1179 17.84 3.31e-71
[redfox] (Intercept) -1.49 0.1782 -8.35 6.64e-17
[redfox] Trail 1.72 0.1714 10.04 9.73e-24
AIC: 6135.555
How to choose penalty value? optimizePenalty()
function.
mod_penalty <- optimizePenalty(mod_complex, penalties=c(0.5,1))
Clipp, H.L., Evans, A.L., Kessinger, B.E., Kellner, K. and Rota, C.T. (2021). A penalized likelihood for multispecies occupancy models improves predictions of species interactions. Ecology, p.e03520.
MacKenzie, D. I., Bailey, L. L., & Nichols, J. D. (2004). Investigating species co‐occurrence patterns when species are detected imperfectly. Journal of Animal Ecology, 73(3), 546-555.
Richmond, O.M., Hines, J.E. and Beissinger, S.R. (2010). Two‐species occupancy models: a new parameterization applied to co‐occurrence of secretive rails. Ecological Applications, 20(7), pp.2036-2046.
Ridout, M. S., & Linkie, M. (2009). Estimating overlap of daily activity patterns from camera trap data. Journal of Agricultural, Biological, and Environmental Statistics, 14, 322-337.
Rota, C.T., Ferreira, M.A., Kays, R.W., Forrester, T.D., Kalies, E.L., McShea, W.J., Parsons, A.W. and Millspaugh, J.J. (2016). A multispecies occupancy model for two or more interacting species. Methods in Ecology and Evolution, 7(10), pp.1164-1173.
Waddle, J.H., Dorazio, R.M., Walls, S.C., Rice, K.G., Beauchamp, J., Schuman, M.J. and Mazzotti, F.J. (2010). A new parameterization for estimating co‐occurrence of interacting species. Ecological Applications, 20(5), pp.1467-1475.