Question

I have a set of 2D points store in p:

x <- c(0, 1, 2, 3, 4)
y <- c(0, 1, 2, 3, 4)
p <- cbind(x,y)

I need to compute the distances between each consecutive point, my function to compute the distance is hypotenuse (actually my problem is a bit different because I have a list of longitude,latitude values and I need to use distVincentyEllipsoid from the geosphere package).

hypotenuse <- function(p1,p2)
{
  sqrt((p1[1]-p2[1])^2+(p1[2]-p2[2])^2)
}

I would like to use diff but it seems to me that I can't pass to the diff function a custom "difference" function, so my solution till now is the following:

distances <- c()
for(i in 2:nrow(p))
{
  distances <- c(distances,hypotenuse(p[i,],p[i-1,]))
}

I read the question A iterative and lagging function similar to diff in R, but not just difference? and I tried to use the rollapply function from the zoo package in this way:

library(zoo)
rollapply(p,width=1,FUN=hypotenuse)

but I get the error

Error in FUN(data[posns], ...) :
argument "p2" is missing, with no default

and so it seems to me that FUN can't be a binary function.

Is it possible to use the rollapply function to solve my problem?

Was it helpful?

Solution 3

I think this option is a little cleaner, since you can keep the function separate and doesn't require modification of the function, which could be annoying if it is a complex function, or if the user doesn't have direct access to it (as may be the case here with the actual function he is interested in):

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

Using the same hypotenuse question poster used. The key here is converting your original p matrix into a list containing x-y coordinate pairs, which then allows us to use mapply.

OTHER TIPS

Here are some approaches:

> # 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

ADDED: Rearranged and added to solutions.

Since this seems to be an acceptable alternative, you can vectorize that whole computation:

sqrt((p[2:5,1] - p[1:4,1])^2 + (p[2:5,2] - p[1:4,2])^2)

and you could generalize the indexing a little more using head and tail, or negative indexing if you like. For instance,

sqrt((p[-1,1] - p[-nrow(p),1])^2 + (p[-1,2] - p[-nrow(p),2])^2)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top