具有非零对角线值的R距离矩阵(rdist.earth)

4

空间距离矩阵的对角线条目应为零,因为它们表示每个位置与自身之间的距离。但是,来自fields R包rdist.earth()函数有时会在对角线上给出非零值:

> # Set number of decimals of output display
> options(digits=8)
> # Some longitude, latitude data
> LLdat
     lon      lat
 1 -105.85878 43.65797
 2 -105.81812 43.57009
 3 -105.80796 43.57748
 > 
 > # Create distance matrix
 > library(fields)
 > distmat <- rdist.earth(LLdat,LLdat)
 > distmat
      1              2          3
1 0.0000000 6.410948951394 6.12184338
2 6.4109490 0.000059058368 0.72150586
3 6.1218434 0.721505863563 0.00000000

在上面的距离矩阵中,对角线上的第二个条目为0.000059058368(默认单位为英里),而另外两个条目为0.0000000。首先,为什么第二列的条目显示了更多的数字?其次,为什么第二条对角线上的条目不像其他条目一样有8位小数为零?这种差异似乎不足以归因于浮点舍入误差。
现在将rdist.earth()的输出与另一个包geosphere和函数distGeo()的输出进行比较,后者计算两点之间的距离(不是完整的距离矩阵)。在这里,我们计算每个点与其自身之间的距离。输出向量单位为米:
> library(geosphere)
> distmat2 <- distGeo(LLdat,LLdat)
> distmat2
[1] 0 0 0

使用distGeo()方法计算的所有三种距离度量均相符且为零。

我是否遗漏了什么?还是这表明rdist.earth()存在问题?

2个回答

3

很遗憾,这是一个四舍五入的错误。

如果您查看源代码,可以复制该问题:

x1 <- LLdat

R <- 3963.34
coslat1 <- cos((x1[, 2] * pi)/180)
sinlat1 <- sin((x1[, 2] * pi)/180)
coslon1 <- cos((x1[, 1] * pi)/180)
sinlon1 <- sin((x1[, 1] * pi)/180)

pp <- cbind(coslat1 * coslon1, coslat1 * sinlon1, sinlat1) %*% 
    t(cbind(coslat1 * coslon1, coslat1 * sinlon1, sinlat1))
return_val = (R * acos(ifelse(abs(pp) > 1, 1 * sign(pp), pp)))

该函数首先计算一个中间矩阵pp:
print (pp)

             [,1]         [,2]         [,3]
[1,] 1.0000000000 0.9999986917 0.9999988071
[2,] 0.9999986917 1.0000000000 0.9999999834
[3,] 0.9999988071 0.9999999834 1.0000000000

似乎对角线都是一样的。但是:
print(pp, digits=22)
                         [,1]                     [,2]                     [,3]
[1,] 1.0000000000000000000000 0.9999986917465573110775 0.9999988070789928018556
[2,] 0.9999986917465573110775 0.9999999999999998889777 0.9999999834298258782894
[3,] 0.9999988070789928018556 0.9999999834298258782894 1.0000000000000000000000


> acos(0.9999999999999998889777) * R
[1] 5.905836821e-05
> acos(1.0000000000000000000000) * R
[1] 0

2
如@thc所解释的那样,这确实是一个数字问题,显然与公式选择有关。特别地,请注意在使用acos之前,所有值都非常接近1。acos在x处的导数为-(1-x^2)^(-1/2),当x趋近于1时发散到-Inf,因此公式很容易受到影响。
要处理这个问题,您可以实现维基百科页面中提出的其他稳定解决方案之一,使用geosphere,因为它们似乎有更加谨慎的实现,或者当然也可以将diag(M) <- 0。但是,后者可能不可取,因为当点在空间中非常接近时,这些数字问题可能仍存在于非对角线项中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接