![](/img/trans.png)
[英]Calculating the distance between two long/lat points in the same data.frame
[英]How to add a column to my data frame that calculates the distance between lat/long points between the previous point with matching IDs
我有一個單獨的動物數據框,具有唯一 ID、發現它們的緯度/經度以及找到它們的日期。 數據庫經常返回同一個人。 我有超過2000個人。 我想在我的數據框中添加一列來計算當前位置和先前位置之間的歐幾里得距離。 我想添加第二列來告訴我每個人的計算編號。 數據框已經按順序日期組織。 我試圖在 R 中解決這個問題。
事件 | ID | 緯度 | 長 |
---|---|---|---|
1個 | 1個 | 31.89 | -80.98 |
2個 | 2個 | 31.54 | -80.12 |
3個 | 1個 | 31.45 | -81.92 |
4個 | 1個 | 31.64 | -81.82 |
5個 | 2個 | 31.23 | -80.98 |
添加一列,現在看起來像
事件 | ID | 緯度 | 長 | 區 | 計算 # |
---|---|---|---|---|---|
1個 | 1個 | 31.89 | -80.98 | - | 0 |
2個 | 2個 | 31.54 | -80.12 | - | 0 |
3個 | 1個 | 31.45 | -81.92 | 事件 1 和 3 之間的距離 | 1個 |
4個 | 1個 | 31.64 | -81.82 | 事件 3 和 4 之間的距離 | 2個 |
5個 | 2個 | 31.23 | -80.98 | 事件 2 和 5 之間的距離 | 1個 |
如果沒有 for 循環,有沒有更快的方法來做到這一點? 我被困在從哪里開始。 我知道我可以使用距地理空間 package 的距離 function 一次,我對 uniqueID 進行了排序,但我無法遍歷我的數據。
這是一個依賴於sf
package 和dplyr
的選項。 function sf::st_distance
計算點對之間的距離, dplyr::lag
可用於查看“落后一排”。 您需要確認您的坐標系,我猜這里是WGS84
/ 4326
。
library(dplyr)
library(sf)
dat <- read.table(text = " Event ID Lat Long
1 1 31.89 -80.98
2 2 31.54 -80.12
3 1 31.45 -81.92
4 1 31.64 -81.82
5 2 31.23 -80.98", h = T)
dat_sf <- st_as_sf(dat, coords = c('Long', 'Lat'), crs = 4326)
dat_sf %>%
arrange(ID) %>%
group_by(ID) %>%
mutate(distance = as.numeric(st_distance(geometry, lag(geometry), by_element = TRUE)),
calculation = row_number() - 1)
#> Simple feature collection with 5 features and 4 fields
#> Geometry type: POINT
#> Dimension: XY
#> Bounding box: xmin: -81.92 ymin: 31.23 xmax: -80.12 ymax: 31.89
#> Geodetic CRS: WGS 84
#> # A tibble: 5 x 5
#> # Groups: ID [2]
#> Event ID geometry distance calculation
#> * <int> <int> <POINT [°]> <dbl> <dbl>
#> 1 1 1 (-80.98 31.89) NA 0
#> 2 3 1 (-81.92 31.45) 101524. 1
#> 3 4 1 (-81.82 31.64) 23155. 2
#> 4 2 2 (-80.12 31.54) NA 0
#> 5 5 2 (-80.98 31.23) 88615. 1
由reprex package (v2.0.0) 創建於 2022-11-14
嘗試這個:
library(geosphere)
df <- data.frame(
event = seq(5),
id = c(1, 2, 1, 1, 2),
lat = c(31.89, 31.54, 31.45, 31.64, 31.23),
long = c(-80.98, -80.12, -81.92, -81.82, -80.98)
)
keys <- df$id %>% unique
df %<>% dplyr::arrange(id, event)
df <- keys %>% lapply(
function(key){
tmp <- df[df$id == key, ]
tmp$last_lat <- tmp$lat
tmp$last_long <- tmp$long
tmp[2:nrow(tmp), ]$last_lat <- tmp[1:nrow(tmp) - 1, ]$lat
tmp[2:nrow(tmp), ]$last_long <- tmp[1:nrow(tmp) - 1, ]$long
tmp %>% return
}
) %>% do.call(rbind, .)
df %<>% mutate(dist = distHaversine(cbind(long, lat), cbind(last_long, last_lat)))
既然你說你需要速度,下面是與上面相同但並行運行的代碼:
library(tictoc)
library(parallel)
tic()
clust <- makeCluster(detectCores() - 1)
df <- data.frame(
event = seq(5),
id = c(1, 2, 1, 1, 2),
lat = c(31.89, 31.54, 31.45, 31.64, 31.23),
long = c(-80.98, -80.12, -81.92, -81.82, -80.98)
)
keys <- df$id %>% unique
df %<>% dplyr::arrange(id, event)
clusterExport(clust, "df")
clusterEvalQ(clust, library(magrittr))
df <- keys %>% parLapply(
clust, .,
function(key){
tmp <- df[df$id == key, ]
tmp$last_lat <- tmp$lat
tmp$last_long <- tmp$long
tmp[2:nrow(tmp), ]$last_lat <- tmp[1:nrow(tmp) - 1, ]$lat
tmp[2:nrow(tmp), ]$last_long <- tmp[1:nrow(tmp) - 1, ]$long
tmp %>% return
}
) %>% do.call(rbind, .)
df %<>% mutate(dist = distHaversine(cbind(long, lat), cbind(last_long, last_lat)))
toc()
上面, tictoc
只是記錄了執行時間。 我剛剛創建了一個集群,你的 cpu 核心數減 1,並將lapply
部分更改為parLapply
如果你有一個小數據集,第二個版本將比第一個版本慢(由於設置並行計算的開銷)。 但是如果你有一個大數據集,第二個版本會快得多。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.