如何在r中的数据集中获得多个样本的long / lat的距离

时间:2016-05-12 01:56:09

标签: r geospatial

我正在尝试计算并保存一个输出文件,该文件给出了与R中多个样本相关的长/纬坐标的所有距离。

数据示例:

Sample     Latitude     Longitude
A          70           141
B          72           142
C          71           143
D          69           141

我目前正在使用r中的geosphere包,特别是distVincentyEllipsoid函数。您可以像这样使用它:

distVincentyEllipsoid(p1 = c(141,70), p2 = c(142,72)) 

但是这只能在两个样本之间给你一个距离,我需要在15个样本中获得所有样本之间的距离,并将它们写入列出样本和相关距离的输出文件。

示例输出:

Samples     Distance(m)
A-B             8
A-C             26
B-C             13
A-D             20

感谢。

3 个答案:

答案 0 :(得分:4)

您可以这样做:

sample_names <- data$Sample

nrow_data <- nrow(data)

test <- function(x){
    return (list(Sample = paste(sample_names[x[1]],sample_names[x[2]],sep='-'),
        Distance.m = distVincentyEllipsoid(p1 = data[x[1],3:2], p2 = data[x[2],3:2])))
}

ans <- combn(1:nrow_data,2,test)

ans_df <- data.frame(Sample = unlist(ans[1,]),Distance.m = unlist(ans[2,]))

##  Sample Distance.m
##1    A-B   226082.2
##2    A-C   134163.1
##3    A-D   111555.6
##4    B-C   117066.1
##5    B-D   336761.1
##6    C-D   235802.0

答案 1 :(得分:4)

以下是outer函数的另一种解决方案。

library(geosphere)
myList <- setNames(split(df[,c(3,2)], seq_len(nrow(df))), df$Sample)
distMat <- outer(myList, myList, Vectorize(distVincentyEllipsoid))

这给出了距离矩阵,其距离由distVincentyEllipsoid定义。结果如下:

> distMat
         A        B        C        D
A      0.0 226082.2 134163.1 111555.6
B 226082.2      0.0 117066.1 336761.1
C 134163.1 117066.1      0.0 235802.0
D 111555.6 336761.1 235802.0      0.0

将其转换为您想要的格式。

library(tidyr); library(dplyr)
distMat[lower.tri(distMat)] <- 0
distDf <- data.frame(distMat)
distDf$P1 <- row.names(distDf)
gather(distDf, P2, Distance, -P1) %>% filter(Distance != 0) %>% 
      mutate(Sample = paste(P1, P2, sep = "-")) %>% select(Sample, Distance)
  Sample Distance
1    A-B 226082.2
2    A-C 134163.1
3    B-C 117066.1
4    A-D 111555.6
5    B-D 336761.1
6    C-D 235802.0

注意:没有时间比较效率,但由于此解决方案避免了原始数据帧中的高级采样数据。它应该相对较快。

答案 2 :(得分:3)

所以你想要的是两个位置的每个组合,然后是相关的位置,

您可以使用联接和data.table

来执行此操作
library(data.table)
library(geosphere)
testdata <- data.table(Sample = LETTERS[1:4],
                   Latitude = c(70,72,71,69),
                   Longitude = c(141,142,143,141))

# Create each pair of combinations with combn
combTable <- rbindlist(combn(testdata$Sample,2,simplify = FALSE,FUN = as.list))

# Join on the first column
setkey(testdata,Sample)
setkey(combTable,V1)

combTable <- testdata[combTable]

#Join on the second column
setkey(combTable,V2)

combTable <- testdata[combTable]

# Mapply to fit the function's requirements of two vectors for each call
combTable[,.(dist = mapply(function(Lat1, Lon1, Lat2, Lon2) 
                          distVincentyEllipsoid(c(Lon1, Lat1), c(Lon2, Lat2)),
                          Latitude,
                          Longitude,
                          i.Latitude,
                          i.Longitude,
                          SIMPLIFY =FALSE ),
         Sample,
         i.Sample)]
编辑:一步完成此操作而不存储中间变量,并按@ Arun的注释(并使用magrittr语法):

 library(magrittr)
 combTable <- 
   testdata[combTable, on = c('Sample' = 'V1')] %>% 
   testdata[., on = c(`Sample` = 'V2')] %>%
   .[,.(dist = mapply(function(Lat1, Lon1, Lat2, Lon2) 
                      distVincentyEllipsoid(c(Lon1, Lat1),c(Lon2, Lat2)),
                      Latitude,
                      Longitude,
                      i.Latitude,
                      i.Longitude,
                      SIMPLIFY = FALSE),
      Sample,
      i.Sample)]