Назначение сетевой поездки с igraph - PullRequest
0 голосов
/ 03 апреля 2020

Моя проблема:

У меня есть сеть улиц (df. net) и список, содержащий происхождение и пункты назначения поездок (df.trips).

Мне нужно найти поток по всем ссылкам?

library(dplyr)

df.net = tribble(~from, ~to, ~weight,1,2,1,2,1,1,1,9,3,9,1,2,2,10,1,10,2,2,9,10,8,10,9,15,9,8,1,8,9,2,7,8,2,12,7,3,9,12,10,12,9,9,12,6,2,6,12,5,11,12,3,12,11,3,5,6,1,11,5,4,5,11,3,11,4,3,4,3,5,3,10,4,10,11,10)

df.trips = tribble(~from, ~to, ~N,1,2,45,1,4,24,1,5,66,1,9,12,1,11,54,2,3,63,2,4,22,2,7,88,2,12,44,3,2,6,3,8,43,3,10,20,3,11,4,4,1,9,4,5,7,4,6,35,4,9,1,5,7,55,5,8,21,5,1,23,5,7,12,5,2,18,6,2,31,6,3,6,6,5,15,6,8,19,7,1,78,7,2,48,7,3,92,7,6,6,8,2,77,8,4,5,8,5,35,8,6,63,8,7,22)

Это мое решение:

library(igraph)

# I construct a directed igraph network:
graph = igraph::graph_from_data_frame(d=df.net, directed=T)
plot(graph)

# I make a vector of edge_ids:
edges = paste0(df.net$from,":",df.net$to)

# and an empty vector of same length to fill with the flow afterwards:
N = integer(length(edges))

# I loop through all Origin-Destination-pairs:
for(i in 1:nrow(df.trips)){

  # provides one shortest path between one Origin & one Destination:
  path = shortest_paths(graph = graph, 
                         from = as.character(df.trips$from[i]), 
                         to = as.character(df.trips$to[i]), 
                         mode = "out", 
                         weights = NULL)

  # Extract the names of vetices on the path:
  a = names(path$vpath[[1]])

  # Make a vector of the edge_ids:  
  a2 = a[2:length(a)]
  a = a[1:(length(a)-1)]
  a = paste0(a,":",a2)  

  # and fill the vector with the trips
  v = integer(length(edges))
  v[edges %in% a] = pull(df.trips[i,3])

  # adding the trips of this iteration to the sum
  N = N + v

}

# attach vector to network-dataframe:
df.net = data.frame(df.net, N)

Теоретически это работает. Это займет ок. 8 часов для моей реальной сети до конечной sh (около 500 000 пар источника-назначения в сети с чуть менее 50 000 ссылок).

Я почти уверен, что для -l oop виновник.

Итак, мои вопросы, касающиеся оптимизации:

1) Есть ли функция igraph, которая просто делает то, что я хочу сделать? Я не смог его найти ...

2) Может, есть другой пакет, более подходящий для моих нужд, на который я не наткнулся?

3) Если нет, то мне go для улучшения производительности l oop, переписав его с помощью пакета R cpp?

В любом случае, я благодарен за любую помощь, которую вы можете оказать мне. Заранее спасибо!

1 Ответ

1 голос
/ 03 апреля 2020

У меня есть, как я надеюсь, более быстрое решение, хотя я получаю от вас немного другие результаты.

Этот подход предусматривает многопоточность с data.table, вызовы igraph::shorest_paths только один раз для каждой вершины и избегание использования имена атрибутов графа до последнего тривиального шага.

library(igraph)
library(tibble)
library(data.table)
library(zoo)
library(purrr)
df.net = tribble(~from, ~to, ~weight,1,2,1,2,1,1,1,9,3,9,1,2,2,10,1,10,2,2,9,10,8,10,9,15,9,8,1,8,9,2,7,8,2,12,7,3,9,12,10,12,9,9,12,6,2,6,12,5,11,12,3,12,11,3,5,6,1,11,5,4,5,11,3,11,4,3,4,3,5,3,10,4,10,11,10)
graph = igraph::graph_from_data_frame(d=df.net, directed=T)
df.trips = tribble(~from, ~to, ~N,1,2,45,1,4,24,1,5,66,1,9,12,1,11,54,2,3,63,2,4,22,2,7,88,2,12,44,3,2,6,3,8,43,3,10,20,3,11,4,4,1,9,4,5,7,4,6,35,4,9,1,5,7,55,5,8,21,5,1,23,5,7,12,5,2,18,6,2,31,6,3,6,6,5,15,6,8,19,7,1,78,7,2,48,7,3,92,7,6,6,8,2,77,8,4,5,8,5,35,8,6,63,8,7,22)
l.trips <- split(df.trips,1:nrow(df.trips))


setDT(df.trips)
Result <- df.trips[,setnames(lapply(shortest_paths(graph = graph,from= from,to = to,weights=NULL,mode = "out")$vpath,
                 function(x){zoo::rollapply(x,width=2,c)}) %>% map2(.,N,~ {.x %x% rep(1,.y)} %>% as.data.frame) %>%
           rbindlist %>% .[,.N,by = c("V1","V2")],c("new.from","new.to","N")),by=from][,sum(N),by = c("new.from","new.to")]
Result[,`:=`(new.from = V(graph)$name[Result$new.from],
             new.to = V(graph)$name[Result$new.to])]
#   new.from new.to  V1
# 1:        1      2 320
# 2:        2     10 161
# 3:        1      9 224
# 4:        9      8  73
# 5:       10     11 146
# 6:       11      4 102
# 7:        2      1 167
# 8:        9     12 262
# 9:        4      3  44
#10:        9      1 286
#11:       12      6  83
#12:       12     11  24
#13:       11      5  20
#14:       10      2  16
#15:       11     12  35
#16:       12      7 439
#17:        8      9 485
#18:        7      8 406
#19:        6     12 202
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...