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:
wolves <- read.csv("data/MTwolves.csv")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:
oc <- list(effort = wolves[,47:51])Organise data and covariates:
umf <- unmarkedFrameOccu(y = wolves[,20:24], obsCovs = oc)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:
fm1 <- occu(~effort ~ 1, data = umf)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:
effort_grid <- seq(min(oc$effort), max(oc$effort), length = 100) # grid
logitp <- coef(fm1)[2] + coef(fm1)[3] * effort_grid # predictions on logit scale
p <- plogis(logitp) # back-transformation
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:
effort <- matrix(unlist(wolves[,47:51]), nrow(wolves), 5)
oc <- list(effort = effort)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:
umfFP <- unmarkedFrameOccuFP(y = wolves[,20:24],
obsCovs = oc,
type = c(0,5,0)) # 5 columns are of type 2Summarize 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:
fm2 <- occuFP(detformula = ~effort, # detection
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:
effort <- matrix(unlist(wolves[,c(52,47:51)]), nrow(wolves), 6)
oc <- list(effort = effort)Get detections and non-detections:
y <- wolves[,c(25,20:24)]
y[,1] <- y[,1] / 2Organise data and covariates:
umfFP <- unmarkedFrameOccuFP(y = y,
obsCovs = oc,
type = c(1,5,0)) # first column of type 1, 5 columns of type 2Summarize 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:
fm3 <- occuFP(detformula = ~effort, # detection
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:
effort <- matrix(unlist(wolves[,c(52,47:51)]), nrow(wolves), 6)
oc <- list(effort = effort)Get detections and non-detections:
y <- wolves[,c(25,20:24)]
y[,1] <- y[,1] / 2Organise data and covariates:
umfFP <- unmarkedFrameOccuFP(y = y,
siteCovs = wolves[,26:28],
obsCovs = oc,
type = c(1,5,0)) # first column of type 1, 5 columns of type 2Summarize 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:
fm4 <- occuFP(detformula = ~effort, # detection
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:
lc <- linearComb(fm4, c(1, 0, 0), type="state") # occ on the logit scale when high
psi_high <- backTransform(lc)Then medium:
lc <- linearComb(fm4, c(0, 1, 0), type="state") # occ on the logit scale when medium
psi_medium <- backTransform(lc)Eventually low:
lc <- linearComb(fm4, c(0, 0, 1), type="state") # occ on the logit scale when low
psi_low <- backTransform(lc)Compare the following estimates with Figure 4, upper left panel:
psi_high@estimate## [1] 0.8347993
psi_medium@estimate## [1] 0.9040658
psi_low@estimate## [1] 0.03511551
Get detection estimates as a function of effort:
effort_grid <- seq(min(oc$effort), max(oc$effort), length = 100)
p11 <- plogis(coef(fm4)[4] + coef(fm4)[5] * effort_grid) # detection
p01 <- plogis(coef(fm4)[6] + coef(fm4)[7] * effort_grid) # false positives detectionCompare 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.