簡體   English   中英

如何使用 osrm 加速找到兩組點之間最短行駛時間的代碼

[英]How to speed up code that finds shortest driving time between two sets of points using osrm

假設我有兩組坐標,A 和 B。我的目標是,對於 A 的每個元素,找到 B 中行駛時間最短的元素(保留 B 的索引、行駛時間和距離)。 根據@Ben 在這個問題( 計算 R 中多個坐標的距離)中的回答,我想出了下面的代碼。 我的問題是如何讓它更快。

library(osrm)
library(sf)

apotheke.df <- st_read(system.file("gpkg/apotheke.gpkg", package = "osrm"),
                       quiet = TRUE)

points <- data.frame(
    id = 1:3,
    longitude = c(13.4, 13.5, 13.3),
    latitude = c(52.4, 52.5, 52.3)
)

route <- list()

#overall goal: for each point, find distance to nearest apotheke

#find distance from each of the 3 points to the first apotheke
for (x in 1:nrow(points)) {
    route[[x]] <- osrmRoute(src = c(points$longitude[x], points$latitude[x]),
                            dst = apotheke.df[1,],
                            overview = FALSE, osrm.profile = "car")
    #add index
    route[[x]][3] <- 1
}

#replace if duration is less than the lowest one
for (x in 1:nrow(points)) {
    for(y in 2:nrow(apotheke.df)) {
        temp <- osrmRoute(src = c(points$longitude[x], points$latitude[x]),
                          dst = apotheke.df[y,],
                          overview = FALSE, osrm.profile = "car")
        temp[3] <- y
        
        print(y)
        print(temp)
        if(temp[2] < route[[x]][2])  route[[x]] <- temp
    }
}

do.call(rbind, route)

結果:

     duration distance   
[1,]     3.52     1.84 18
[2,]     2.05     1.00 14
[3,]    17.10    17.76 76

在我的實際應用中,一組點有150個左右,另一組有幾千幾千。 這需要很長時間才能完成。 這引出了我的問題——我怎樣才能加快上面的代碼?

我最好的猜測是使用並行處理(盡管代碼的其他方面可能很慢),但我不擅長弄清楚如何做到這一點。 它可能與這些問題有關:1) 在 R (OSRM) 中並行化 API和 2) 如何將 osrm function 應用於 dataframe 的每一行

這是一個可重現的例子,詳細說明了我的評論。

1.定義sample sourcedest數據:

這只是為了回答的目的。

library(osrm)

source <- data.frame(
    id = 1:3,
    longitude = c(13.4, 13.5, 13.3),
    latitude = c(52.4, 52.5, 52.3)
)

dest <- data.frame(
    id = 4:5,
    longitude = c(13.9, 13.6),
    latitude = c(52.2, 52.4)
)

2.計算距離

使用osrmTable()而不是循環遍歷數據並每次調用osrmRoute()將節省大量時間。 如果您使用的是遠程服務器而不是托管您自己的服務器,則尤其如此,因為每個請求都通過 inte.net 傳輸。 使用osrmTable()向服務器發出對整個表的一次請求,而不是對每一對坐標的請求。

distances <- osrmTable(
    src = source[c("longitude", "latitude")],
    dst = dest[c("longitude", "latitude")],
    osrm.profile = "car"
)

distances[["durations"]]

#      1    2
# 1 60.6 25.7
# 2 71.4 25.4
# 3 55.7 25.3

即使只有 100 個源坐標和 100 個目的地,R 也需要解釋一個命令,發出一個 .network 請求並執行一個高級分配 ( <- ) 操作,而不是 10,000 個,如果您單獨迭代每個操作。

3.找到離每個源頭最近的目的地

同樣,如果您跳過循環,它會更快。 我將在示例中使用data.table ,因為它很快。 首先,將距離matrix變為data.table並使用melt()將其變為長格式:

library(data.table)

distances_dt <- data.table(
    source = source$id,
    distances[["durations"]],
    key = "source"
) |>
    setnames(
        seq_len(nrow(dest)) + 1,
        as.character(dest$id)
    ) |>
    melt(
        id.vars = "source",
        variable.name = "dest",
        value.name = "distance"
    )

#    source   dest distance
#     <int> <fctr>    <num>
# 1:      1      4     60.6
# 2:      2      4     71.4
# 3:      3      4     55.7
# 4:      1      5     25.7
# 5:      2      5     25.4
# 6:      3      5     25.3

然后我們可以簡單地找到每個源的最小距離:

distances_dt[,
    .(min_distance = min(distance)),
    by = source
]

#    source min_distance
#     <int>        <num>
# 1:      1         25.7
# 2:      2         25.4
# 3:      3         25.3

4. 設置你自己的osrm-backend實例

我可以預見的唯一問題是,如果您使用默認的 R osrm package 服務器,而不是本地服務器,您將收到速率限制錯誤。 根據 R osrm package文檔

OSRM 演示服務器不允許大型查詢(超過 10000 個距離或持續時間)。

如果您不確定您是否在托管自己的服務器,那么您可能不是。 您可以通過運行getOption("osrm.server")檢查 R session 中的默認服務器。 默認值為"https://routing.openstreetmap.de/"

如果您在正在使用的服務器上發出大於 max-table-size 參數的請求,您將收到以下響應:

{"code":"TooBig","message":"Too many table coordinates"}

如果是這種情況,那么如果可行的話,您可以將數據分解成更小的塊。

或者,您可以運行自己的 osrm-backend 實例。 如果您打算定期計算距離,或者一次計算很多距離,我建議您這樣做。 有兩種方法:

一種。 安裝 osrm-backend 並更改max-table-size參數 (Linux/Mac)

是我幾年前遵循的教程,我認為這是一個很好的方法。 這些說明適用於 Ubuntu,但只需進行少量更改即可在其他流行的 Linux 版本或 MacOS 上安裝。

您需要更改教程中的一行。 而不是運行:

osrm-routed map.xml.osrm

你可以運行:

osrm-routed map.xml.osrm --max-table-size 100000

(或者任何足夠大的數字。)

b. 在 Docker 圖像中公開 API (Windows/Linux/Mac)

或者,如果您正在運行 Windows,或者您對 Docker 感到滿意,那么使用Docker 圖像可能更容易。 即使您以前沒有使用過 Docker, 也是一套很好的說明。

如果您在 Docker 容器中運行 osrm-backend 實例,您可以通過將其傳遞給docker run來更改max-table-size參數,按照此處所述運行,其語法類似於:

docker run -t -i -p 5000:5000 -v "${PWD}:/data" osrm/osrm-backend osrm-routed --algorithm mld --max-table-size 10000 /data/berlin-latest.osrm

在任何一種情況下,一旦您設置了自己的 osrm 路由實例,就需要告訴 R osrm package 使用它。 如果它在你的localhost的端口 5000 上運行,你可以這樣做:

options(osrm.server = "http://127.0.0.1:5000/")

您可以在此處查看將本地 osrm 路由實例與 R osrm package 集成的示例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM