In R, I need to calculate the nearest neighbour index between the relocations of a single animal, for several different individuals. I want to determine whether the relocations of certain individuals are more randomly or regularly distributed than those of other animals.

I have a dataset similar to this:

ID<-  c(a,a,a,a,a,b,b,b,b,b,c,c,c,c,c,c,d,d,d,d,d, etc)
E<-c(167685,167945,167685,153985,167685,158675,167645,167667, etc)
N<-c(9876548,9879248,9876838,9596548,9926548,9878578,9876548,9166548, etc)

In which each "ID" represents a different animal, and E/N points represent locations where the animals were observed. The data frame, consisting of 120 observations of 6 individuals with 20 observations each is called "cor".

I know I can use the "nni" function in the "spatialEco" package to obtain the NNI, the problem is I need to sequentially subset the original data frame in order to calculate NNI for each individual in the sample:

a<-subset(cor, ID=="a")
coordinates(a) <- ~E+N 
nni(a, win = "hull")

Being this the output:

 [1] 1.942733
 [1] 8.065562
 [1] 7.289959e-16
 [1] 0.1731123
 [1] 0.336311

I would like to create a loop of some kind which would do this set of commands for each individual (ID). In the output table, each row would summarize the NNI and the rest of parameters fr each individual, like so:

ID          NNI     z.score     etc

a           0.87     2.34       -
b           1.45     3.12       -
c           2.13     4.05       -

The easiest result is to use a for loop, but maybe isn't the fastest way:

ID<-  rep(c('a','b'),each=4)

cor = data.frame(ID,E,N)

nni_result <- list()

for(i in unique(cor$ID)){
  nni_result[[i]] <- nni(cor[cor$ID == i,], win = "hull")

nni_summary <- as.data.frame(matrix(unlist(nni_result), nrow = length(unique(cor$ID)), byrow = T))

names(nni_summary) <- c('NNI','z.score','p','expected.mean.distance','observed.mean.distance')

The result is:

       NNI   z.score p expected.mean.distance observed.mean.distance
1 63.46895 239.01497 0               1116.053               70834.74
2 13.28334  46.99779 0              14627.389              194300.62

In a similar vein to @aldo_tapia's answer, you can just unlist the results in the for loop and then use do.call to rbind the results.


  coordinates(meuse) <- ~x+y

nni.list <- list()
  for( i in 1:length(unique(meuse$soil)) ) {
    nni.list[[i]] <- unlist(nni(meuse[meuse$soil == unique(meuse$soil)[i] ,], 
                            win = "hull"))
( dat.nni <- do.call("rbind", nni.list) )

FYI, the reason that I iterate 1:length(unique()) is that in certain cases piping a character into an empty list object can go horribly wrong. Whereas, a numeric index will always work. Even if it results in a NULL, there is still an element in the list and the code will not fail.


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.