2015-03-23 1 views
0

J'ai besoin d'un moyen efficace de calculer une matrice de distances entre une série de points. Le hic, c'est que vous pouvez seulement aller du point 'i' au point 'k' en passant par tous les points 'j' entre les deux. Par exemple, imaginez une île avec 5 plages et vous voulez calculer la distance entre toutes les plages le long de la côte car vous ne pouvez pas traverser l'île (y compris dans les deux sens: dans le sens des aiguilles d'une montre ou dans le sens inverse).Calculer la matrice des distances cumulées dans R

Voici quelques exemples de données. (Remarque: vous devez installer le paquet « géosphère » utiliser la fonction « Distm », qui calcule la distance entre les coordonnées GPS le long de la surface de la Terre)

library("geosphere") 

longitude = c(-119.003, -119.067, -119.121, -119.089, -119.003) 
latitude = c(33.503, 33.539, 33.485, 33.413, 33.440) 
long.lat.mat = as.matrix(cbind(longitude, latitude)) 

# Use "distm" to calculate Euclidean (straight-line) distances between sites (in km) 
euclid.dist.mat = distm(long.lat.mat)/1000 

# Create an empty matrix of alongshore distances (from "rows" to "columns") 
alongshore.dist.mat = matrix(ncol=dim(long.lat.mat)[1], nrow=dim(long.lat.mat)[1], data=NA) 

# Diagonal is zero. Adjacent sites are the same as Euclidean distance 
diag(alongshore.dist.mat) = 0 
diag(alongshore.dist.mat[,-1]) = diag(euclid.dist.mat[,-1]) 
alongshore.dist.mat[1,dim(long.lat.mat)[1]] = euclid.dist.mat[1,dim(long.lat.mat)[1]] 
alongshore.dist.mat[lower.tri(alongshore.dist.mat)] = t(alongshore.dist.mat)[lower.tri(t(alongshore.dist.mat))] 

# > alongshore.dist.mat 
#   [,1]  [,2]  [,3]  [,4]  [,5] 
# [1,] 0.0000000 7.1650632  NA  NA 7.0131279 
# [2,] 7.1650632 0.0000000 7.8265783  NA  NA 
# [3,]  NA 7.8265783 0.0000000 8.5483605  NA 
# [4,]  NA  NA 8.5483605 0.0000000 8.5365807 
# [5,] 7.0131279  NA  NA 8.5365807 0.0000000 

Maintenant, comment remplir cellules restantes? A titre d'exemple:

alongshore.dist.mat[1,3] = 7.1650632 + 7.8265783 = 14.991642 

... le site représentant 1 -> site 2 -> site 3. Par contre:

alongshore.dist.mat[3,1] = 8.5483605 + 8.5365807 + 7.0131279 = 24.098069 

... représentant le site 3 -> site 4 -> Site 5 -> site 1.

Je suppose que la fonction "cumsum" peut être utilisée efficacement, mais je ne sais pas exactement comment la configurer. J'espère une solution pour éviter les boucles, car je travaille en réalité avec des données contenant des dizaines de points.

+0

Si cela est une île , c'est-à-dire un «anneau» mathématique, vous avez une définition ambiguë puisque vous pouvez le contourner dans les deux sens. Le triangle inférieur devrait probablement être pour une direction et le triangle supérieur pour l'autre, c'est-à-dire pas vraiment une mesure de «distance» traditionnelle. –

+0

Je suis d'accord avec vous, c'est pourquoi je mentionne les deux directions ("dans le sens des aiguilles d'une montre" ou "sens inverse des aiguilles d'une montre"). Ce n'est pas une matrice symétrique; les triangles supérieur et inférieur sont différents. Il peut être utile de penser à déplacer "des" lignes de la matrice "vers" les colonnes de la matrice. – MCNC

Répondre

0

Vous pourriez d'abord construire une matrice de tous bords entre deux emplacements:

dists <- expand.grid(x=1:5, y=1:5) 
dists$weight <- alongshore.dist.mat[as.matrix(dists)] 
dists <- subset(dists, x != y & !is.na(weight)) 
dists 
# x y weight 
# 2 2 1 7.165063 
# 5 5 1 7.013128 
# 6 1 2 7.165063 
# 8 3 2 7.826578 
# 12 2 3 7.826578 
# 14 4 3 8.548360 
# 18 3 4 8.548360 
# 20 5 4 8.536581 
# 21 1 5 7.013128 
# 24 4 5 8.536581 

Maintenant vous pouvez construire un graphique et de calculer les toutes les paires de chemins les plus courts:

library(igraph) 
g <- graph.data.frame(dists, vertices=data.frame(x=1:5)) 
shortest.paths(g) 
#   1   2   3   4   5 
# 1 0.000000 7.165063 14.991642 15.549709 7.013128 
# 2 7.165063 0.000000 7.826578 16.374939 14.178191 
# 3 14.991642 7.826578 0.000000 8.548360 17.084941 
# 4 15.549709 16.374939 8.548360 0.000000 8.536581 
# 5 7.013128 14.178191 17.084941 8.536581 0.000000 
+0

Oui, cela fonctionnera pour calculer la distance minimale. Merci! – MCNC