In R, I need to calculate the grand mean of distance between all the relocations of the same individual.
I have a dataset similar to this:

individual<-  c(a,b,a,b,a,c,a,b)

In which each "individual" represents a different animal, and x/y points represent locations where the animals were observed. Some individuals were relocated many times, while other individuals were only relocated once.

I'd need to calculate the mean distance between every observation and all the other observations of the same animal, iterating the process for every observation of the animal. Finally these distances should be averaged by getting a single value of "spread of relocations" for each individual. The animals which were observed only once should get "NA" in this variable.

In the output table, each row would summarize the spread of recaptures of an individual, like so:

individual  spread 

a           34        
b           56       
c           NA   

1 Answer 1


Here is a brute force approach that uses a distance matrix to pull means of pairwise distances. In the case of group "c" with only one observation, the mean distance would be zero (but can easily be changed to NA in the code).

Here we coerce your data into a SpatialPointsDataFrame object

d <- data.frame(individual = c('a','b','a','b','a','c','a','b'),
               x = c(167685,167945,167685,153985,167685,158675,167645,167667),
               y = c(9876548,9879248,9876838,9596548,9926548,9878578,9876548,9166548))
coordinates(d) <- ~x+y             

We can then calculate a distance matrix and assign the group names to each row/column of the distance matrix. To omit self-distance values (zero distance) we set the diagonal of the matrix to NA.

dmat <- spDists(d)
  rownames(dmat) <- d$individual 
  colnames(dmat) <- d$individual 
  diag(dmat) <- NA

Here is the brute force part where a for loop is used to iterate through a index to subset the matrix and calculate the mean distance for each group. The result is a vector of mean distance with the associated group names.

group.means <- vector()
  for( i in unique(colnames(dmat)) ) {
      idx <- which( colnames(dmat) %in% i )
      if( length(idx) > 1) {
        dmean <- mean(dmat[idx,][,idx], na.rm=TRUE)
      } else {
        dmean <- 0
      group.means <- append(group.means, dmean)
names(group.means) <- unique(colnames(dmat)) 

Using R, there are always many ways to skin the proverbial cat. I am sure that there is a much more efficient way to do this but, this is a start.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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