# File name: FindARS.txt # Find the change points (shift to area restricted search) # x = a trip data file (e.g. TID###.RData) with latitude # and longitude as the 2nd and 3rd columns and the # date/time as the first column. # thresh = the window for finding local max/min # Algorithm based on # Knell, A. (2011) Identifying Behavioural Changes in # Movement Path Data. Unpublished doctoral dissertation, # Department of Mathematical Sciences, University of Essex. # Knell A, Codling E (2012) Classifying area-restricted # search (ARS) using a partial sum approach. # Theoretical Ecology 5: 325-339. # FindARS <- function(x, thresh=900){ # Missing values for distance indicate a time gap # in the original data (missing seconds of data). # Replace missing values with distance/time (seconds) to # provide an estimate of the speed over the gap. miss <- which(is.na(x$Dist)) if (length(miss)>0){ require(geosphere) distH <- distHaversine(x[miss,3:2], x[miss-1, 3:2]) distT <- difftime(x[miss,1], x[miss-1, 1]) x$Dist[miss] <- distH/as.numeric(distT) } # Cumulative sum of centered data (C-tau) ZDist <- cumsum(scale(x$Dist, scale=FALSE)) # count increases until threshhold is reached count <- 1 # idx stores index of candidate Max/Min idx <- 1 # ZOpt stores current candidate for Max/Min ZOpt <- ZDist[1] # opttbl is a data.frame containing the results opttbl <- data.frame() # Are we looking for a min or a max at the start? if (ZDist[1] < median(ZDist[2:120])) { sg <- "Max" } else {sg <- "Min" } # Use sg to switch between Max/Min i <- 1 while (i < length(ZDist)) { i <- i + 1 # Is next value greater (Max) or less (Min) if(sg=="Min"){ test <- (ZOpt > ZDist[i]) } else { test <- (ZOpt < ZDist[i]) } # If so, replace ZOpt if (test) { ZOpt <- ZDist[i] idx <- i count <- 1 # if not, continue } else { count <- count + 1 } # if threshhold reached, copy current Max/Min # and set i back to idx so that we start from the # last Max/Min if (count > thresh) { count <- 0 opttbl <- rbind(opttbl, data.frame(idx, ZOpt, sg)) i <- idx if (sg=="Min") { sg <- "Max" } else { sg <- "Min" } } } # Once at the end of the array, add the current Max/Min # and return the data.table return(rbind(opttbl, data.frame(idx, ZOpt, sg))) }