简体   繁体   中英

Distance Matrix from second variable using get.shortest.paths()

I would like to go one step further with this question ( Find total of second variable related to the distance of route from get.shortest.paths() ). How does one get the matrix of distances between nodes, when the 'shortest' path is found using the newcost variable?

(My experience with igraph is very limited).

      df2 = rbind(c(234,235,21.6,75),
      c(234,326,11.0,35),
      c(235,241,14.5,78),
      c(326,241,8.2,98),
      c(241,245,15.3,75),
      c(234,245,38.46,65))

      df2 = as.data.frame(df2)
      names(df2) = c("start_id","end_id","newcost","distance")

      require(igraph)
      g2 <- graph.data.frame(df2, directed=FALSE)
      tmp2 = shortest.paths(g2,weights=E(g2)$newcost)
      tmp2 #this gives the matrix of newcost-weighted shortest distances

Where I could use help is how to find all paths, say using optimal.path <- get.shortest.paths , and using sum(E(g2, path = optimal.path)$distance) to create the matrix of distances

what I would really like is an edgelist of distances for all node pairs, like:

      startid endid shortestdist
      234     235     75
      234     245     208

What is tricky about this problem is that newcost is used to find the shortest paths, but what I want is the sum of another variable - the distance variable on each shortest path between node pairs.

Ok, first let me make it clear that I am not an igraph user myself. Nevertheless I thought the question was interesting so I thought I'd take a look. And I too could find no easy solution to the problem you are having. I ended up making some helper functions to make the process possible. There is a good chance that i've re-coded the functionality inside igraph already but I could not find it.

Let me first define get.shortest.paths.for.all which will not just return the shortest path lengths for a given attribute, but will also return the shortest path themselves for all vertices in the graph. Here's that code

get.shortest.paths.for.all<-function(graph, attr) {
    paths<-lapply(1:(vcount(graph)-1), function(i) {
        get.all.shortest.paths(
            graph, 
            weights=get.edge.attribute(g2,attr),
            from = V(graph)[i],
            to = V(graph)[(i+1):vcount(graph)]
        )$res
    })
    unsplit(paths, rep.int(seq_along(paths), sapply(paths, length)))
}

Now let me define get.path.dist.matrix will takes a graph and a list of paths (like the one returned by get.shortest.paths.for.all ) and will calculate the distance for a given attribute between each of those paths

get.path.dist.matrix<-function(graph, path, attr) {
    dd<-get.adjacency(graph, attr=attr)
    uniqs <- numeric(0)
    if (is.list(path)) {
        starts<-sapply(path, head, 1)
        ends<-sapply(path, tail, 1)
        uniqs <- unique(sort(c(starts,ends)))
    } else {
        uniqs <- c(head(path,1), tail(path,1))
    }
    m<-matrix(0, nrow=length(uniqs), ncol=length(uniqs),
        dimnames=list(V(graph)$name[uniqs],V(graph)$name[uniqs]))
    for(pp in path) {
        m[pp[1], pp[length(pp)]]<-sum(dd[embed(pp,2)])
    }
    m+t(m)
}

Using your sample data, I use them like this

paths <- get.shortest.paths.for.all(g2, "newcost")
get.path.dist.matrix(g2, paths,"distance")

#     234 235 326 241 245
# 234   0  75  35 133 208
# 235  75   0 176  78 153
# 326  35 176   0  98 173
# 241 133  78  98   0  75
# 245 208 153 173  75   0

Which seems reasonable and distinct from shortest.paths(g2,weights=E(g2)$distance) . To try to test my functions, I see that

all(tmp2==get.path.dist.matrix(g2, paths,"newcost"))

So feel free to try these out and let me know if you see any problems or possible improvements.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM