4

In R, I'd like to calculate the straight-line distance between each capture of an animal in my dataset - no need to take into account the curvature of the earth. I have a dataset that looks like this:

record.nbr<- c(1:8)
individual<-  c(1,2,1,2,1,3,1,2)
x<-c(167685,167945,167685,153985,167685,158675,167645,167667)
y<-c(9876548,9879248,9876838,9596548,9926548,9878578,9876548,9166548)
julian.date<-c(125,126,127,127,128,129,130,130)
captures<-data.frame(cbind(record.nbr, individual, x, y, julian.date))

Here each "individual" represents a unique animal, and x/y points represent locations where the animals were captured. x/y points are UTM coordinates. Some individuals are caught many times, while other individuals are only captured once.

I'd like to calculate the distance (and the mean date) between recaptures by individual. In the output table, each row would summarize the distance between consecutive recaptures of an individual, plus the mean date between recaptures, like so:

individual first.rec  second.rec  distance  mean.date
1          1             3        V         126
1          3             5        W         127.5
1          5             7        X         129
2          2             4        Y         126.5
3          4             6        Z         128
6

One way to do this is using ddply from the plyr package:

require(plyr)
# split up captures by the unique individual id for processing
ddply(captures, "individual", function(df) {
  # single captures don't have any dist/time changes
  if(nrow(df)==1) {
    return(data.frame(start=NA,
                      end=NA,
                      dist=NA,
                      mean.time=NA))
  }

  # for each pair of consecutive displacement, calculate dist and mean time
  out <- sapply(1:(nrow(df)-1), function(i) {
    d <- dist(df[i:(i+1),3:4])
    t <- mean(df[i:(i+1),5])
    c(d,t)
  })
  out <- t(out)

  # reports results, adding the starting and ending record number
  # for each displacement
  data.frame(start=head(df$record.nbr,-1),
             end=tail(df$record.nbr, -1),
             dist=out[,1],
             mean.time=out[,2])
})

Which results in:

  individual start end      dist mean.time
1          1     1   3    290.00     126.0
2          1     3   5  49710.00     127.5
3          1     5   7  50000.02     129.0
4          2     2   4 283044.47     126.5
5          2     4   8 430217.62     128.5
6          3    NA  NA        NA        NA

The equivalent can be done using base tapply in R, however I generally find the ddply to be cleaner.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.