如何从 long/lat 获取数据集中多个样本的距离

How to get distance from long/lat for multiple samples in a dataset in r

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

数据示例:

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

谢谢。

你可以这样做:

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

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

您可以使用连接和 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)]

这是另一个使用 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

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