Multi-scale (Multi-method) detection histories

141 views
Skip to first unread message

Matt Dyson

unread,
Apr 1, 2020, 5:22:41 PM4/1/20
to camtrapR
Hi, 

I would like to run a similar analysis to Nichols et al. 2008 and more recently Evans et al. 2019 where you account for the dependence between sampling devices at a site where you have more than 1 device. In my case, I have 2 cameras at each site that are separated to maximize my probability of detection at each site.

I would like to create a detection history that I can then use in RPresence (to my knowledge, you cannot implement multi-scale occupancy models in unmarked). As an example, if I have 2 cameras per site and 2 occasions then my detection history needs to be coded as: 01 00, where on occasion 1, the species was only detected by camera 2 and on occasion 2, the species was not detected by either camera. Currently, I have used the bycamera option to get rows for each camera for each site and occasions across the columns. I can probably figure out how to get the second camera into a row using some data wrangling, but curious if there is an option I am missing in CamTrap R to easily produce this.

Thanks in advance for any insight anyone might have.

Matt

Juergen Niedballa

unread,
Apr 2, 2020, 4:08:31 PM4/2/20
to camtrapR
Hi Matt, 
unfortunately, camtrapR doesn't have any functions or arguments that you could tweak to get the desired output out of the box. So as you said, for now you'd need to do some data wrangling to achieve the desired data format (after using detectionHistory with byCamera = TRUE). 
And you are right, what camtrapR would support is setting byCamera = TRUE. You could then use camera-specific covariates to model differences in detection probabilities between cameras (if your cameras differ systematically, e.g. different camera models, or set up on different types of trails / roads). 

Did anyone else miss this feature, input for multi-scale/method occupancy models? 

Best regards,
Jürgen

Matt Dyson

unread,
Apr 2, 2020, 4:30:32 PM4/2/20
to camtrapR
Thanks Jürgen, 

I appreciate the response. Almost made it through a work around I think.

Keep well, 

Matt

Juergen Niedballa

unread,
Apr 4, 2020, 8:54:40 AM4/4/20
to camtrapR
Great. If you want, feel free to share your workaround here for anyone else who might be interested.
Stay safe,
Jürgen

Eric Van Dam

unread,
Nov 8, 2020, 11:42:07 PM11/8/20
to camtrapR
Hi Matt,

I'm running into the same issue as you with how I can wrangle two cameras from one station into the same row but two distinct columns. If you did find a workaround, I'd love to hear it!

All the best,
Eric

Matt Dyson

unread,
Nov 9, 2020, 1:34:05 PM11/9/20
to camtrapR
Hi Evan, 

I ended up just manipulating the data frame to produce what I needed. Here is some example code of what I did to convert the standard output from camtrapR (where each camera was a row) into something I could use for RPresence. First, I added a column to the camtrapR operations dataframe output (cameraOperation function) that numbered the cameras per site by grouping by site year and using the row_numbers function. So if there were 3 cameras at a site, then they would get numbered 1, 2, 3 etc. Then I subset that frame to just include the site id and number of cameras. Then I joined that to the detection history data frame based on the site id column. Hopefully you can follow the rest of the pasted code below? As a disclaimer, I suspect there are much more efficient ways to do this, but this is what worked for me.

#Attach the camera number info to the detection history data frame

dh_pred_10 <-
  dh_pred_10 %>% 
  rownames_to_column(var = "year_site_camid") %>% 
  left_join(., cam_num, by="year_site_camid")

#now subset the data by cam number to set up the wide data frame by "method"
#I had up to 4 cameras per site, so if you only had 2 then you would just need the first 2 chunks etc....

dh_pred_10_1 <-
  dh_pred_10 %>% 
  filter(cam_num == 1)

dh_pred_10_2 <-
  dh_pred_10 %>% 
  filter(cam_num == 2)

dh_pred_10_3 <-
  dh_pred_10 %>% 
  filter(cam_num == 3)

dh_pred_10_4 <-
  dh_pred_10 %>% 
  filter(cam_num == 4)

#now join the data frames back together in wide form and add a suffix to the respective observations

df_pred_10 <-
  dh_pred_10_1 %>% 
  left_join(.,dh_pred_10_2, by=c("year_site"), suffix=c("","_cam2")) %>% 
  left_join(., dh_pred_10_3, by=c("year_site"), suffix=c("","_cam3")) %>% 
  left_join(., dh_pred_10_4, by=c("year_site"), suffix=c("","_cam4"))

#now organize the data frames so the occasions are all together, this depends on how many occasions you have but will sort them the way you need them for Presence
dh_pred_10 <-
  df_pred_10 %>%
  dplyr::select(o1, starts_with("o1_"),o2, starts_with("o2_"),o3, starts_with("o3_"), 
                o4, starts_with("o4_"), o5, starts_with("o5_"), o6, starts_with("o6_"),
                o7, starts_with("o7_"), o8, starts_with("o8_"), o9, starts_with("o9_"),
                everything())

#subset to replace dots with NAs in the detection history
dh_pred_10_subset <- dh_pred_10[1:36] #grabs only the detection history data, will vary depending on the number of observations and cameras in your data

dh_pred_10_subset <- data.matrix(dh_pred_10_subset)

Hopefully this helpful.

Matt

Juergen Niedballa

unread,
Nov 10, 2020, 1:49:59 PM11/10/20
to camtrapR
Hi Matt & Evan,
thank you for sharing your thoughts and the solution. I didn't get to check the code you shared yet and don't use Presence either, but here is a very simplistic idea (my apoligies for shortcomings or misunderstandings. 

mat1 and mat2 represent the detection histories for camera 1 and camera 2 of each station respectively (one needs to so some data wrangling first to run detectionHistory for individual cameras instead of both: subsetting the camera trap data frame etc.).  The values below are nonsense and only for illustration of which cell goes where.

mat1 <- matrix(c(1,2,3,4), nrow = 2, byrow = TRUE)
mat2 <- matrix(c(5,6,7,8), nrow = 2, byrow = TRUE)
> mat1
     [,1] [,2]
[1,]    1    2
[2,]    3    4
> mat2
     [,1] [,2]
[1,]    5    6
[2,]    7    8


They can then be combined

mat_comb <- matrix(paste0(mat1, mat2), nrow = 2)
out <-matrix(apply(mat_comb, MARGIN = 1, FUN = paste, collapse = " "))
> out
     [,1]   
[1,] "15 26"
[2,] "37 48"


I don't know if a matrix is the correct output. One could also easily convert it to a text file with line breaks with something like:

cat(paste(apply(mat_comb, MARGIN = 1, FUN = paste, collapse = " "), collapse = "\n"))
15 26
37 48

That could be combined with sink() to get a text file.
Best regards,
Jürgen

Eric Van Dam

unread,
Nov 12, 2020, 4:00:35 PM11/12/20
to camtrapR
Thanks Matt and Jürgen for your detailed responses! Both were very useful for writing my own script that got the detection history in the form that works for Presence. 

In my case, I'm looking at camera pairs where one is placed on-trail and the other off-trail, so I just had two methods that I'm comparing. As you suggested, I had my camera operation (camOp) dataframe output structured so that every camera had its own row. Using the stationCol and cameraCol arguments, I could identify in my camOp output what station each camera belongs to and whether it was "on" or "off" trail. Making sure that my capture event dataset also had a matching stationCol column for the detectionHistory function, this gave me detection histories also with detection/nondetection data per camera. From there I took a page out of Matt's book and used the script below to separate cameras by "on" and "off" trail placements, combine them into one row while still maintaining method-specific survey columns, and then reordering them so that on and off-trail occasions were organized by survey:

#Isolate detection histories (det_hist) into on and off trail dataframes

det_hist_on <- det_hist[grepl("on", rownames(det_hist)), ]
det_hist_off <- det_hist[grepl("off", rownames(det_hist)), ]

#Add a suffix to the "off" trail dataframe to differentiate occasions
colnames(det_hist_off) <- paste(colnames(det_hist_off), "off", sep = "_")

#Join the dataframes back together as one row (note that this only works if you have the same # and order of cameras by method, i.e 50 cameras from method A, 50 cameras from method B, etc.)
det_hist_2methods <- cbind(det_hist_on, det_hist_off)

#Reorder occasions by survey (o1, o1_off, o2, o2_off, etc.)

det_hist_2methods <-
  det_hist_2methods %>%
  dplyr::select(o1, starts_with("o1_"),o2, starts_with("o2_"),o3, starts_with("o3_"), 
                o4, starts_with("o4_"), o5, starts_with("o5_"), o6, starts_with("o6_"),
                o7, starts_with("o7_"), o8, starts_with("o8_"), o9, starts_with("o9_"),
                o10, starts_with("o10_"),o11, starts_with("o11_")...)


I'm also sure that there are much more elegant ways to do this, but this did the trick for me. And thanks again to Matt and Jürgen! This thread really helped me move forward with my analysis. 

Eric

Reply all
Reply to author
Forward
0 new messages