-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathMarkedAnalysis.R
More file actions
309 lines (281 loc) · 11.4 KB
/
MarkedAnalysis.R
File metadata and controls
309 lines (281 loc) · 11.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
#######################################################################
#######################################################################
## This script was created by Dr. Jen Cruz as part of ##
## the Applied Population Ecology Class ###
## ##
## Here we import our cleaned data for single season capture- ##
# recapture analysis for Piute ground squirrels at the NCA. ##
## ##
## We start with analysis in unmarked. We will run 3 model options ##
## M[0] = intercept only model for detection. #
# M[t] = survey-varying detection model ##
# M[b] = behavior-effect on detection. To allow for trap-happiness or #
# trap-shyness following initial capture. #
#######################################################################
##### Set up your workspace and load relevant packages -----------
# install packages
install.packages( "AHMbook" )
#Now load relevant packages:
library( tidyverse )
library( unmarked )
library( AHMbook ) #contains data and functions from book
## end of package load ###############
###################################################################
#### Load or create data -----------------------------------------
# Clean your workspace to reset your R environment. #
rm( list = ls() )
# Check that you are in the right project folder
getwd()
# load workspace with clean data
load( "MarkPrepWorkspace.RData")
#### End of data load -------------
####################################################################
##### Ready data for analysis --------------
# We need to custom build cell probability functions for each model type.
# We start with M[t]
# Remember that custom crPiFun can only take a single argument p, which must be#
# the I x J matrix of detection probabilities.
# we define the probabilities for each possible capture history:
crPiFun.t <- function(p) {
p1 <- p[,1] #detection for J survey 1
p2 <- p[,2] #detection for J survey 2
p3 <- p[,3] #detection for J survey 3
cbind("001" = (1-p1) * (1-p2) * p3,
"010" = (1-p1) * p2 * (1-p3),
"011" = (1-p1) * p2 * p3,
"100" = p1 * (1-p2) * (1-p3),
"101" = p1 * (1-p2) * p3,
"110" = p1 * p2 * (1-p3),
"111" = p1 * p2 * p3)
}
# When providing a user defined piFun we also need information on how #
# to handle missing values by supplying a matrix of zeros (if not sampled) and ones (if sampled) #
# with rows = J (repeat surveys) and cols = observed capture histories (ch):
o2y <- matrix( data = 1, nrow = J, ncol = CH )
# For the M[t] and M[0] models we can use our observations pooled #
# by capture histories.
# A restriction of unmarked is that we cannot include #
# sites with all zero captures. i.e. sites where we trapped but #
# we caught no animals. We therefore work out which rows from our #
# dataframes we need to keep
keep <- which( rowSums(y_ik ) > 0 )
#define unmarked dataframe for M[t] and M[o] for single season
umf.Mt <- unmarkedFrameGMM( y = y_ik[ keep, ],
#define abundance covariates
siteCovs = as.data.frame( ik_sc[keep,] ),
#define observation covariates:
obsCovs = list( wind = ij_wide[keep,widx],
temp = ij_wide[keep,tidx],
effort = ij_wide[keep,eidx] ),
#we use the pifun we defined for M[t]:
obsToY = o2y, piFun = "crPiFun.t",
numPrimary = 1 )
#What does it look like?
summary(umf.Mt)
#Now define cell probabilities for the behavioral model M[b]:
#note this model assumes that on first capture, the animals are 'naive' #
# to the capture process. However, after being captured once, their #
# reaction to the capture process changes.
crPiFun.b <- function(p) {
pNaive <- p[,1]
pWise <- p[,2]
cbind("001" = (1-pNaive) * (1-pNaive) * pNaive,
"010" = (1-pNaive) * pNaive * (1-pWise),
"011" = (1-pNaive) * pNaive * pWise,
"100" = pNaive * (1-pWise) * (1-pWise),
"101" = pNaive * (1-pWise) * pWise,
"110" = pNaive * pWise * (1-pWise),
"111" = pNaive * pWise * pWise)
}
### For the M[b] model we create a behavior dummy variable
bMat <- matrix( c("Naive", "Wise", "Wise"), dim(y_ik[keep,])[1],
J, byrow = TRUE )
# Remember that there are limitations to the models that you can fit #
# for example, you cannot fit an M[b,t] model
#define unmarked dataframe for M[b]
umf.Mb <- unmarkedFrameGMM( y = y_ik[keep,],
#define abundance covariates
siteCovs = as.data.frame(ik_sc[keep,]),
#define observation covariates:
obsCovs = list( behavior = bMat ),
obsToY = o2y, piFun = "crPiFun.b",
numPrimary = 1 )
#check
summary(umf.Mb)
### end data prep -----------
#######################################################################
### Analyze data ------------------------------------------
# We are now ready to perform our analysis.
# For a single season: ######################
# We start with M[o] intercept only model to check it all runs: -------
M0.P <- gmultmix( #first function is abundance model.
#Second is availability. Third is detection.
#we start with intercept only models
~1, ~1, ~1,
#we can provide the Mt dataframe
umf.Mt, engine="R")
#Did it work?
M0.P
# We adjust to a Negative Binomial:
M0.NB <- gmultmix( ~1, ~1, ~1,
umf.Mt,
mixture = "NB",
engine="R" )
#Did it work?
M0.NB
#Now we run the full Mt model including also abundance predictors:
Mt.full.P <- gmultmix( ~ 1 + shrub + annual + perennial,
~ 1 ,
~ 1 + wind + temp + effort,
umf.Mt,
mixture = "P",
engine="R" )
#Did it work?
Mt.full.P
#What do results say at first glance?
#Answer:
#
# We test whether the Negative Binomial as an alternative distribution
Mt.full.NB <- gmultmix( ~ 1 + shrub + annual + perennial,
~ 1 ,
~ 1 + wind + temp + effort,
umf.Mt,
mixture = "NB",
engine="R" )
#check
Mt.full.NB
# We compare against the two full behavioral models
#The first uses the Poisson distribution:
Mb.full.P <- gmultmix( ~ 1 + shrub + annual + perennial,
~ 1 ,
~ 1 + behavior,
umf.Mb,
mixture = "P",
engine="R" )
Mb.full.P
#The second full model uses the Negative Binomial:
Mb.full.NB <- gmultmix( ~ 1 + shrub + annual + perennial,
~ 1 ,
~ 1 + behavior,
umf.Mb,
mixture = "NB",
engine="R" )
Mb.full.NB
# We therefore move on and try to see which of our Mt, Mo or Mb models #
# provided a better fit for our data:
#Create model list:
Mtmodels <- fitList( "M0.NB" = M0.NB,
"Mt.P" = Mt.full.P,
"Mt.NB" = Mt.full.NB
)
#compare
modSel( Mtmodels )
# Which is our top model?
# Answer:
#
# What does it suggest:
# Answer:
#
#Now repeat for Mb models
Mbmodels <- fitList(
"Mb.P" = Mb.full.P,
"Mb.NB" = Mb.full.NB
)
modSel( Mbmodels )
##########################################################################
# Model fit and evaluation -----------------------------------------------
# We rely on unmarked options for boostrap goodness-of-fit option in #
# combination with custom built function fitstats, from Kery and Royle's
# Hierarchical modelling book, Chpt 7 pg 333. Also see example in ?parboot.
# The function computes error sum-of-squares, standard Chi-square and the #
# Freeman-Tukey statistic:
# Function returning three fit-statistics.
# fitstats <- function(fm) {
# observed <- getY(fm@data)
# expected <- fitted(fm)
# resids <- residuals(fm)
# sse <- sum(resids^2)
# chisq <- sum((observed - expected)^2 / expected)
# freeTuke <- sum((sqrt(observed) - sqrt(expected))^2)
# out <- c(SSE=sse, Chisq=chisq, freemanTukey=freeTuke)
# return(out)
# }
# the fitstats function is also available via the AHMbook package
# so we use that:
(gof.Mt.full.NB <- parboot( Mt.full.NB, fitstats2, nsim = 100) )
(gof.Mt.full.P <- parboot( Mt.full.P, fitstats2, nsim = 100) )
(gof.Mb.full.NB <- parboot( Mb.full.NB, fitstats2, nsim = 100) )
(gof.Mb.full.P <- parboot( Mb.full.P, fitstats2, nsim = 100) )
# What do these results suggest?
# Answer:
#
#########################################################################
##### Summarizing model output ##############
# Select model to use
fm <- Mt.full.P
#Extract abundance estimates from top model
#start by creating a dataframe to hold results
outdf <- ik_df %>% select( idno, id, SiteID, year ) %>%
dplyr::filter( idno %in% rownames(y_ik[keep,]) )
#now calculate the mean and 95%CIs using the ranef function
outdf <- cbind( outdf, bup(ranef( fm)),confint( ranef( fm)))
colnames(outdf)[5:7] <- c( "Mean", "Lower", "Upper")
#Add raw counts
outdf$rawtrap <- as.vector(rowSums( y_ik[keep,] ))
#check
head(outdf)
#plot
ggplot( outdf, aes( x = as.factor(SiteID), y = Mean ) ) +
theme_classic(base_size = 15) +
geom_point( size = 3 ) +
# add confidence intervals
geom_errorbar( aes(ymin = Lower, ymax = Upper ),
size = 1.5, width = 0.3 ) +
facet_wrap( ~year, ncol = 1 )
# Estimate partial prediction plots for predictors with 95% CIs not overlapping zero:
# how many values do we use:
n <- 100
# Use the observed values to define our range:
shrub <- seq( min( ik_df[,"shrub"]), max( ik_df[,"shrub"]),
length.out = n )
#scale
shrub.std <- scale( shrub )
#combine standardized predictors into anew dataframe to predict partial relationship
# for abundance submodel:
abundData <- data.frame( shrub = shrub.std, annual = 0,
perennial = 0 )
#predict partial relationship:
pred.shrub <- predict( fm, type = "lambda", newdata = abundData,
appendData = TRUE )
#view
head( pred.shrub ); dim( pred.shrub )
# create plot for ecological submodel:
shrubp <- cbind( pred.shrub[,c("Predicted", "lower", "upper") ], shrub ) %>%
# define x and y values
ggplot(., aes( x = shrub, y = Predicted ) ) +
#choose preset look
theme_bw( base_size = 15 ) +
# add labels
labs( x = "Shrub cover (%)", y = "Relative abundance" ) +
# add band of confidence intervals
geom_smooth( aes(ymin = lower, ymax = upper ),
stat = "identity",
size = 1.5, alpha = 0.5, color = "grey" ) +
# add mean line on top
geom_line( size = 2 )
#view
shrubp
# How do you interpret this relationship?
# Answer:
#Compare abundance and partial prediction plot for the
# model with the NB distribution instead. #
# What differences do you see? What distribution would you
# choose moving forward? #
# Answer:
###################################################################
############################################################################
################## Save your data and workspace ###################
# Save workspace:
save.image( "MarkedResults.RData" )
########## End of saving section ##################################
############# END OF SCRIPT #####################################