我在p
中存储了一组 2D 点:
x <- c(0, 1, 2, 3, 4)
y <- c(0, 1, 2, 3, 4)
p <- cbind(x,y)
我需要计算每个连续点之间的距离,我计算距离的函数是hypotenuse
(实际上我的问题有点不同,因为我有一个经度、纬度值的列表,我需要使用 geosphere
包中的distVincentyEllipsoid
)。
hypotenuse <- function(p1,p2)
{
sqrt((p1[1]-p2[1])^2+(p1[2]-p2[2])^2)
}
我想使用diff
但在我看来,我无法将自定义"差分"函数传递给diff
函数,因此到目前为止我的解决方案如下:
distances <- c()
for(i in 2:nrow(p))
{
distances <- c(distances,hypotenuse(p[i,],p[i-1,]))
}
我读了这个问题 类似于 R 中的 diff 的迭代和滞后函数,但不仅仅是差异? 我尝试以这种方式使用 zoo
包中的 rollapply
函数:
library(zoo)
rollapply(p,width=1,FUN=hypotenuse)
但我收到错误
FUN(data[posns], ...) 中的错误:
缺少参数"P2",没有 违约
所以在我看来,FUN 不能是一个二进制函数。
是否可以使用 rollapply
函数来解决我的问题?
以下是一些方法:
> # 1a
> sqrt(rowSums(diff(p)^2))
[1] 1.414214 1.414214 1.414214 1.414214
> # 1b
> sqrt(diff(p[, 1])^2 + diff(p[, 2])^2)
[1] 1.414214 1.414214 1.414214 1.414214
> # 2a
> library(zoo)
> rollapply(p, 2, dist, by.column = FALSE)
[1] 1.414214 1.414214 1.414214 1.414214
> # 2b
> rollapply(p, 2, function(x) unname(hypotenuse(x[1, ], x[2, ])), by.column = FALSE)
[1] 1.414214 1.414214 1.414214 1.414214
> # 2c
> rollapply(p, 2, function(x) sqrt(sum(diff(x)^2)), by.column = FALSE)
[1] 1.414214 1.414214 1.414214 1.414214
增加:重新排列并添加到解决方案中。
由于这似乎是一个可接受的替代方案,因此您可以对整个计算进行矢量化:
sqrt((p[2:5,1] - p[1:4,1])^2 + (p[2:5,2] - p[1:4,2])^2)
你可以使用 head
和 tail
来概括索引,或者如果你愿意,也可以使用负索引。例如
sqrt((p[-1,1] - p[-nrow(p),1])^2 + (p[-1,2] - p[-nrow(p),2])^2)
我认为这个选项更干净一些,因为您可以将函数分开并且不需要修改函数,如果它是一个复杂的函数,或者如果用户没有直接访问它,这可能会很烦人(就像他感兴趣的实际函数一样):
p.list <- unname(split(p, row(p))) # `p` is as produced in question
mapply(hypotenuse, head(p.list, -1L), tail(p.list, -1L))
# [1] 1.414214 1.414214 1.414214 1.414214
使用与问题海报相同的hypotenuse
。 这里的关键是将原始 p 矩阵转换为包含 x-y 坐标对的列表,然后允许我们使用 mapply
.