Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculating geographic distances to data points with dplyr::mutate

I am trying to use R with the tidyverse packages and having trouble applying a function to my data. My data includes lat/long coordinates, and I want to calculate the distance from every location (row of my data frame) to a reference location. I am trying to use the geosphere::distm function.

library(tidyverse)
library(geosphere)

my_long <- 172
my_lat <- -43

data <- data %>%  rowwise() %>% mutate(
  dist = distm(c(myLong, myLat), c(long, lat), fun=distHaversine) # this works
)

I got it working using the rowwise() function, as above, but this is deprecated, so I want to know how to do it with modern tidyverse, i.e., dplyr or purrr, I think, for example the closest I have got is using map2:

my_distm <- function(long1, lat1, long2, lat2)
  distm(c(long1, lat1), c(long2, lat2), fun=distHaversine)

data <- data %>%  mutate(
  dist = map2(long, lat, my_distm, my_long, my_lat) # this doesn't
)

So far I have failed.

like image 277
Simon Woodward Avatar asked Dec 02 '22 11:12

Simon Woodward


2 Answers

You could use distHaversine instead of distm, and cbind:

data %>%  mutate(dist = distHaversine(cbind(myLong, myLat), cbind(long, lat)))

Example data:

myLong = 172
myLat = -43 
long = c(180,179,179)
lat = c(-40,-41,-40)
data = data.frame(myLong,myLat,long,lat)

Which gives as result:

  myLong myLat long lat     dist
1    172   -43  180 -40 745481.0
2    172   -43  179 -41 620164.8
3    172   -43  179 -40 672076.2
like image 56
Lamia Avatar answered Dec 03 '22 23:12

Lamia


You can use mutate with mapply:

library(tidyverse)
library(geosphere)

my_long <- 172
my_lat <- -43

df <- data.frame(long = c(170, 180), lat = c(-43, 43))
df %>% rowwise() %>% mutate(
  dist = distm(c(my_long, my_lat), c(long, lat), fun=distHaversine) # this works
)

#Source: local data frame [2 x 3]
#Groups: <by row>

# A tibble: 2 x 3
#   long   lat    dist
#  <dbl> <dbl>   <dbl>
#1   170   -43  162824
#2   180    43 9606752

df %>% mutate(
    dist = mapply(function(lg, lt) distm(c(my_long, my_lat), c(lg, lt), fun=distHaversine), long, lat)
)

#  long lat    dist
#1  170 -43  162824
#2  180  43 9606752

Update on using map2:

df %>% 
    mutate(dist = map2(long, lat, ~distm(c(my_long, my_lat), c(.x, .y), fun=distHaversine)))
# here .x stands for a value from long column, and .y stands for a value from lat column
#  long lat    dist
#1  170 -43  162824
#2  180  43 9606752

To use my_distm:

my_distm <- function(long1, lat1, long2, lat2)
    distm(c(long1, lat1), c(long2, lat2), fun=distHaversine)

df %>% mutate(dist = map2(long, lat, ~my_distm(my_long, my_lat, .x, .y)))
#  long lat    dist
#1  170 -43  162824
#2  180  43 9606752
like image 40
Psidom Avatar answered Dec 03 '22 23:12

Psidom