Load some packages:
library(unmarked)
We use data from the paper Determining Occurrence Dynamics when False Positives Occur: Estimating the Range Dynamics of Wolves from Public Survey Data by Miller et al. published in Plos One and available at https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0065808.
Data are of 2 types. There are data from hunters who report whether they observed wolves while hunting for deer or elk. Other data come from observations made by state agency personnel based on collaring and relocation by radio telemetry. Covariates include the amount of hunter effort, habitat quality, and whether observations were by hunters or agency personnel. Static analysis uses data from the year 2010.
We thank David Miller for sharing the data.
In the figure below, we display the data. Cells were divided based on perceived habitat quality into low, medium, and high quality categories (A). Most certain observations of known packs made by state agency personnel and based on collaring and relocation by radio telemetry were concentrated in the western end of the study area where the higher quality habitat was located (B). While high frequency of observations by hunters also occurred in high-quality areas, they also reported a low frequency of wolf observations in the eastern portion of the study area, which we suspected were due to mis-identification (C).
Read in data:
<- read.csv("data/MTwolves.csv") wolves
Inspect data:
str(wolves)
## 'data.frame': 257 obs. of 52 variables:
## $ ID : int 1 2 3 4 5 6 7 8 9 10 ...
## $ X2007NA1: int 0 0 1 0 1 0 0 0 0 0 ...
## $ X2007NA2: int 0 0 0 0 0 1 0 0 0 0 ...
## $ X2007NA3: int 0 1 0 0 1 1 0 0 0 1 ...
## $ X2007NA4: int 0 0 1 0 0 1 1 0 0 1 ...
## $ X2007NA5: int 0 0 0 1 1 0 1 0 0 1 ...
## $ X2007NAK: int 0 0 0 0 0 0 0 0 0 2 ...
## $ X2008NA1: int 0 0 1 1 1 1 1 0 0 1 ...
## $ X2008NA2: int 0 0 1 0 1 1 0 1 0 1 ...
## $ X2008NA3: int 0 0 0 1 1 1 1 0 0 1 ...
## $ X2008NA4: int 0 0 0 1 1 1 1 0 0 1 ...
## $ X2008NA5: int 0 1 1 1 1 1 1 0 1 1 ...
## $ X2008NAK: int 0 0 0 0 2 0 2 0 0 0 ...
## $ X2009NA1: int 0 0 1 1 1 1 0 0 0 1 ...
## $ X2009NA2: int 0 0 1 1 1 1 1 0 0 1 ...
## $ X2009NA3: int 1 1 1 1 1 1 1 0 0 1 ...
## $ X2009NA4: int 0 0 1 1 1 0 0 0 0 1 ...
## $ X2009NA5: int 0 0 0 0 1 1 1 0 0 1 ...
## $ X2009NAK: int 0 0 0 0 2 0 2 0 2 2 ...
## $ X2010NA1: int 0 0 0 1 1 1 1 0 0 1 ...
## $ X2010NA2: int 0 0 1 1 1 1 1 1 0 1 ...
## $ X2010NA3: int 0 1 1 1 1 1 1 1 0 1 ...
## $ X2010NA4: int 0 0 0 1 1 1 1 0 0 1 ...
## $ X2010NA5: int 0 0 1 1 1 1 1 0 0 1 ...
## $ X2010NAK: int 0 0 0 0 2 2 2 0 2 2 ...
## $ High : int 1 1 1 1 1 0 1 1 1 1 ...
## $ Medium : int 0 0 0 0 0 1 0 0 0 0 ...
## $ Low : int 0 0 0 0 0 0 0 0 0 0 ...
## $ E07NA1 : num 14.4 21.9 22 21.4 16.8 ...
## $ E07NA2 : num 14.4 21.9 22 21.4 16.8 ...
## $ E07NA3 : num 14.4 21.9 22 21.4 16.8 ...
## $ E07NA4 : num 14.4 21.9 22 21.4 16.8 ...
## $ E07NA5 : num 14.4 21.9 22 21.4 16.8 ...
## $ E07NAK : num 0 0 0 0 0 0 0 0 0 0 ...
## $ E08NA1 : num 14.9 22 22.1 21.5 16.8 ...
## $ E08NA2 : num 14.9 22 22.1 21.5 16.8 ...
## $ E08NA3 : num 14.9 22 22.1 21.5 16.8 ...
## $ E08NA4 : num 14.9 22 22.1 21.5 16.8 ...
## $ E08NA5 : num 14.9 22 22.1 21.5 16.8 ...
## $ E08NAK : num 0 0 0 0 0 0 0 0 0 0 ...
## $ E09NA1 : num 16.2 20.5 20.5 19.7 13.7 ...
## $ E09NA2 : num 16.2 20.5 20.5 19.7 13.7 ...
## $ E09NA3 : num 16.2 20.5 20.5 19.7 13.7 ...
## $ E09NA4 : num 16.2 20.5 20.5 19.7 13.7 ...
## $ E09NA5 : num 16.2 20.5 20.5 19.7 13.7 ...
## $ E09NAK : num 0 0 0 0 0 0 0 0 0 0 ...
## $ E10NA1 : num 13.5 20.8 20.9 19.9 12.7 ...
## $ E10NA2 : num 13.5 20.8 20.9 19.9 12.7 ...
## $ E10NA3 : num 13.5 20.8 20.9 19.9 12.7 ...
## $ E10NA4 : num 13.5 20.8 20.9 19.9 12.7 ...
## $ E10NA5 : num 13.5 20.8 20.9 19.9 12.7 ...
## $ E10NAK : num 0 0 0 0 0 0 0 0 0 0 ...
Build list of covariate:
<- list(effort = wolves[,47:51]) oc
Organise data and covariates:
<- unmarkedFrameOccu(y = wolves[,20:24], obsCovs = oc) umf
Summarize data:
str(umf)
## Formal class 'unmarkedFrameOccu' [package "unmarked"] with 5 slots
## ..@ y : int [1:257, 1:5] 0 0 0 1 1 1 1 0 0 1 ...
## .. ..- attr(*, "dimnames")=List of 2
## .. .. ..$ : NULL
## .. .. ..$ : chr [1:5] "X2010NA1" "X2010NA2" "X2010NA3" "X2010NA4" ...
## ..@ obsCovs :'data.frame': 1285 obs. of 1 variable:
## .. ..$ effort: num [1:1285] 13.5 13.5 13.5 13.5 13.5 ...
## ..@ siteCovs: NULL
## ..@ mapInfo : NULL
## ..@ obsToY : num [1:5, 1:5] 1 0 0 0 0 0 1 0 0 0 ...
Fit model:
<- occu(~effort ~ 1, data = umf) fm1
Display model coefficients (parameters)
coef(fm1)
## psi(Int) p(Int) p(effort)
## 2.9393910 -2.5989479 0.3643864
Get occupancy probability estimate:
1/(1 + exp(-coef(fm1)[1]))
## psi(Int)
## 0.9497597
Or:
plogis(coef(fm1)[1])
## psi(Int)
## 0.9497597
Or:
backTransform(fm1, 'state')
## Backtransformed linear combination(s) of Occupancy estimate(s)
##
## Estimate SE LinComb (Intercept)
## 0.95 0.0354 2.94 1
##
## Transformation: logistic
Now let’s plot the detection probability for hunters as a function of effort:
<- seq(min(oc$effort), max(oc$effort), length = 100) # grid
effort_grid <- coef(fm1)[2] + coef(fm1)[3] * effort_grid # predictions on logit scale
logitp <- plogis(logitp) # back-transformation
p plot(effort_grid,
p, type = "l",
lwd = 3,
xlab = "effort",
ylab = "detection probability",
ylim = c(0,1))
Compare figure below with Figure 3 in Miller and colleagues’ paper.
Get covariates:
<- matrix(unlist(wolves[,47:51]), nrow(wolves), 5)
effort <- list(effort = effort) oc
Organise data and covariates using unmarkedFrameOccuFP
function. Note the extra argument type
which takes a vector
with 3 values designating the number of occasions where data is of type
1, type 2, and type 3. For type 1 data, false positive detections are
assumed not to occur. For type 2 data, both false negative and false
positive detection probabilities are estimated. Both p or p11 (the true
positive detection probability) and fp or p01 (the false positive
detection probability) are estimated for occasions when this data type
occurs. For type 3 data, observations are assumed to include both
certain detections (false positives assumed not to occur) and uncertain
detections that may include false positive detections. Let’s get to
it:
<- unmarkedFrameOccuFP(y = wolves[,20:24],
umfFP obsCovs = oc,
type = c(0,5,0)) # 5 columns are of type 2
Summarize data:
str(umfFP)
## Formal class 'unmarkedFrameOccuFP' [package "unmarked"] with 6 slots
## ..@ type : num [1:3] 0 5 0
## ..@ y : int [1:257, 1:5] 0 0 0 1 1 1 1 0 0 1 ...
## .. ..- attr(*, "dimnames")=List of 2
## .. .. ..$ : NULL
## .. .. ..$ : chr [1:5] "X2010NA1" "X2010NA2" "X2010NA3" "X2010NA4" ...
## ..@ obsCovs :'data.frame': 1285 obs. of 1 variable:
## .. ..$ effort: num [1:1285] 13.5 13.5 13.5 13.5 13.5 ...
## ..@ siteCovs: NULL
## ..@ mapInfo : NULL
## ..@ obsToY : num [1:5, 1:5] 1 0 0 0 0 0 1 0 0 0 ...
Fit model with effort on both detection and false positive detection probabilities:
<- occuFP(detformula = ~effort, # detection
fm2 FPformula = ~effort, # false positive detection
Bformula = ~1, # probability detections are certain
stateformula = ~1, # occupancy
starts = c(0, 0, 0, -5, 0), # initial values
data = umfFP)
Inspect estimates:
coef(fm2)
## psi(Int) p(Int) p(effort) fp(Int) fp(effort)
## -0.7651619 -1.4539025 0.1380600 -7.4198442 1.7210737
Get occupancy prob estimate:
backTransform(fm2, 'state')
## Backtransformed linear combination(s) of Occupancy estimate(s)
##
## Estimate SE LinComb (Intercept)
## 0.318 0.0621 -0.765 1
##
## Transformation: logistic
Build covariates:
<- matrix(unlist(wolves[,c(52,47:51)]), nrow(wolves), 6)
effort <- list(effort = effort) oc
Get detections and non-detections:
<- wolves[,c(25,20:24)]
y 1] <- y[,1] / 2 y[,
Organise data and covariates:
<- unmarkedFrameOccuFP(y = y,
umfFP obsCovs = oc,
type = c(1,5,0)) # first column of type 1, 5 columns of type 2
Summarize data:
str(umfFP)
## Formal class 'unmarkedFrameOccuFP' [package "unmarked"] with 6 slots
## ..@ type : num [1:3] 1 5 0
## ..@ y : num [1:257, 1:6] 0 0 0 0 1 1 1 0 1 1 ...
## .. ..- attr(*, "dimnames")=List of 2
## .. .. ..$ : NULL
## .. .. ..$ : chr [1:6] "X2010NAK" "X2010NA1" "X2010NA2" "X2010NA3" ...
## ..@ obsCovs :'data.frame': 1542 obs. of 1 variable:
## .. ..$ effort: num [1:1542] 0 13.5 13.5 13.5 13.5 ...
## ..@ siteCovs: NULL
## ..@ mapInfo : NULL
## ..@ obsToY : num [1:6, 1:6] 1 0 0 0 0 0 0 1 0 0 ...
Fit model:
<- occuFP(detformula = ~effort, # detection
fm3 FPformula = ~effort, # false positives detection
Bformula = ~1, # probability detections are certain
stateformula = ~1, # occupancy
starts = c(0, 0, 0, -5, 0), # initial values
data = umfFP)
Print results:
fm3
##
## Call:
## occuFP(detformula = ~effort, FPformula = ~effort, Bformula = ~1,
## stateformula = ~1, data = umfFP, starts = c(0, 0, 0, -5,
## 0))
##
## Occupancy:
## Estimate SE z P(>|z|)
## -0.63 0.187 -3.37 0.000742
##
## Detection:
## Estimate SE z P(>|z|)
## (Intercept) -0.126 0.2700 -0.468 6.40e-01
## effort 0.205 0.0304 6.761 1.37e-11
##
## false positive:
## Estimate SE z P(>|z|)
## (Intercept) -3.520 0.2385 -14.8 2.58e-49
## effort 0.303 0.0287 10.6 3.54e-26
##
## AIC: 1146.876
Get covariates:
<- matrix(unlist(wolves[,c(52,47:51)]), nrow(wolves), 6)
effort <- list(effort = effort) oc
Get detections and non-detections:
<- wolves[,c(25,20:24)]
y 1] <- y[,1] / 2 y[,
Organise data and covariates:
<- unmarkedFrameOccuFP(y = y,
umfFP siteCovs = wolves[,26:28],
obsCovs = oc,
type = c(1,5,0)) # first column of type 1, 5 columns of type 2
Summarize data:
str(umfFP)
## Formal class 'unmarkedFrameOccuFP' [package "unmarked"] with 6 slots
## ..@ type : num [1:3] 1 5 0
## ..@ y : num [1:257, 1:6] 0 0 0 0 1 1 1 0 1 1 ...
## .. ..- attr(*, "dimnames")=List of 2
## .. .. ..$ : NULL
## .. .. ..$ : chr [1:6] "X2010NAK" "X2010NA1" "X2010NA2" "X2010NA3" ...
## ..@ obsCovs :'data.frame': 1542 obs. of 1 variable:
## .. ..$ effort: num [1:1542] 0 13.5 13.5 13.5 13.5 ...
## ..@ siteCovs:'data.frame': 257 obs. of 3 variables:
## .. ..$ High : int [1:257] 1 1 1 1 1 0 1 1 1 1 ...
## .. ..$ Medium: int [1:257] 0 0 0 0 0 1 0 0 0 0 ...
## .. ..$ Low : int [1:257] 0 0 0 0 0 0 0 0 0 0 ...
## ..@ mapInfo : NULL
## ..@ obsToY : num [1:6, 1:6] 1 0 0 0 0 0 0 1 0 0 ...
Fit model:
<- occuFP(detformula = ~effort, # detection
fm4 FPformula = ~effort, # false positives detection
Bformula = ~1, # probability detections are certain
stateformula = ~High + Medium + Low - 1, # occupancy
starts = c(0, 0, 0, 0, 0, -5, 0), # initial values
data = umfFP)
Occupancy estimates for each level of habitat quality, starting by high:
<- linearComb(fm4, c(1, 0, 0), type="state") # occ on the logit scale when high
lc <- backTransform(lc) psi_high
Then medium:
<- linearComb(fm4, c(0, 1, 0), type="state") # occ on the logit scale when medium
lc <- backTransform(lc) psi_medium
Eventually low:
<- linearComb(fm4, c(0, 0, 1), type="state") # occ on the logit scale when low
lc <- backTransform(lc) psi_low
Compare the following estimates with Figure 4, upper left panel:
@estimate psi_high
## [1] 0.8347993
@estimate psi_medium
## [1] 0.9040658
@estimate psi_low
## [1] 0.03511551
Get detection estimates as a function of effort:
<- seq(min(oc$effort), max(oc$effort), length = 100)
effort_grid <- plogis(coef(fm4)[4] + coef(fm4)[5] * effort_grid) # detection
p11 <- plogis(coef(fm4)[6] + coef(fm4)[7] * effort_grid) # false positives detection p01
Compare figure below with Figure 3:
plot(effort_grid,
p11, type = "l",
lwd = 3,
xlab = "effort",
ylab = "detection probability",
col = "red",
ylim = c(0,1))
lines(effort_grid,
p01,lwd = 3,
col = "blue")
legend("bottomright", legend = c("true positive det prob (p11)",
"false positive det prob (p01)"),
col = c("red", "blue"),
lwd = 3)
Both the true positive (p11) and false positive (p01) detection probabilities increase as hunter effort increases (Figure 3). False positive probabilities are greater than 0.5 in areas with the greatest hunting effort.