【问题标题】:Get subgraph of shortest path between n nodes获取n个节点之间最短路径的子图
【发布时间】:2017-09-01 13:49:08
【问题描述】:

我有一个未加权的图,我想得到一个子图,其中只有包含 n 个已知节点之间最短路径的节点和边。在这种情况下,3 个节点(11、29 和 13 是名称)。

问题

如何获得 R 中 n 个节点之间的最短路径子图?

MWE

library(ggraph)
library(igraph)

hs <- highschool[highschool$year == '1958',]
set.seed(11)
graph <- graph_from_data_frame(hs[sample.int(nrow(hs), 60),])


# plot using ggraph
ggraph(graph, layout = 'kk') + 
    geom_edge_fan() + 
    geom_node_text(aes(label = name)) 

期望的输出

所需的输出将是以下绿色子图(或关闭,我正在注视上面的图并直观地挑选出子图)忽略/删除其他节点和边缘。

【问题讨论】:

  • @Frank 我编辑并添加了所需子图输出的可视化表示
  • 哦,好的。这看起来有点复杂,不仅仅是成对最短路径的并集。我想答案会是这样的:获取诱导子图,然后在某种意义上“修剪”。
  • 我认为是一个简单的问题可能比我想象的要困难得多:math.stackexchange.com/questions/773324/…
  • 我也遇到过这个:stackoverflow.com/q/7685291
  • 这似乎不是最优解,你不需要节点41,你可以直接从节点33到36,这样就少了一个节点和边。另一方面,如果您想要所选节点之间的最短路径,那么它似乎是正确的,但是您错过了从节点 11 到 29 的路径。

标签: r algorithm igraph ggraph


【解决方案1】:

你找不到 n 个节点之间的最短路径。由于最短路径仅在两个节点之间定义。

我认为你想要从1 节点到其他n-1 节点的最短路径,你可以使用
igraph 库中的get_all_shortest_paths(v, to=None, mode=ALL)。

  • v - 计算路径的来源
  • to - 描述目标的顶点选择器 计算路径。这可以是单个顶点 ID,顶点列表 ID,单个顶点名称,顶点名称列表。 None 表示所有顶点。
  • mode - 路径的方向性。 IN 表示计算 输入路径,OUT 表示计算输出路径,ALL 表示计算两个路径。

返回:列表中从给定节点到图中每个其他可到达节点的所有最短路径。
get_all_shortest_paths

所以,现在您必须从最短路径列表中创建一个图表。

  1. 初始化一个空图,然后从列表中添加所有路径 路径
    adding path in graph

    或

  2. 为找到的每条最短路径制作一个图,然后将图合并。
    union igraph

【讨论】:

    【解决方案2】:

    您需要一个最短路径矩阵,然后使用属于这些路径的所有边的并集来创建子图。

    让 key vertices 成为您想要的子图出现的那些顶点。你说你有三个这样的关键顶点。

    考虑任何i 和j 之间的最短路径是unlist(shortest_paths(g, i, j, mode="all", weights=NULL)$vpath)。您想列出关键顶点的所有 ij 组合(在您的情况下为 1-2、1-3、2-3),然后列出出现在它们之间的路径 on 的所有顶点.有时,相同的顶点肯定会出现在不止一个 ij 对的最短路径上(参见 betweenness centrality)。您所需的子图应仅包含这些顶点,您可以将其提供给induced_subgraph()。

    然后出现另一个有趣的问题。并非您选择的顶点之间的所有边都是最短路径的一部分。我不确定您在子图中想要什么,但我假设您只想要作为最短路径一部分的顶点 和 边。 induced_subgraph() 的手册说 eids 也可以用来过滤边上的子图,但我没有让它起作用。如果有人破解它,欢迎对此发表评论。要在最短路径中实际上创建只有边和顶点的子图,必须删除一些多余的边。

    下面是一个随机选择一些关键顶点的例子,子图的剩余边问题被可视化,并生成了一个适当的仅短路径子图:

    library(igraph)
    N <- 40 # Number of vertices in a random network
    E <- 70 # Number of edges in a random network
    K <- 5  # Number of KEY vertices between which we are to calculate the
            # shortest paths and extract a sub-graph.
    
    # Make a random network
    g <- erdos.renyi.game(N, E, type="gnm", directed = FALSE, loops = FALSE)
    V(g)$label <- NA
    V(g)$color <- "white"
    V(g)$size <- 8
    E(g)$color <- "gray"
    
    # Choose some random verteces and mark them as KEY vertices
    key_vertices <- sample(1:N, 5)
    g <- g %>% set_vertex_attr("color", index=key_vertices, value="red")
    g <- g %>% set_vertex_attr("size", index=key_vertices, value=12)
    
    # Find shortest paths between two vertices in vector x:
    get_path <- function(x){
      # Get atomic vector of two key verteces and return their shortest path as vector.
      i <- x[1]; j <- x[2]
      # Check distance to see if any verticy is outside component. No possible
      # connection will return infinate distance:
      if(distances(g,i,j) == Inf){
        path <- c()
      } else {
        path <- unlist(shortest_paths(g, i, j, mode="all", weights=NULL)$vpath)
      }
    }
    
    # List pairs of key vertices between which we need the shortest path
    key_el <- expand.grid(key_vertices, key_vertices)
    key_el <- key_el[key_el$Var1 != key_el$Var2,]
    
    # Get all shortest paths between each pair of key_vertices:
    paths <- apply(key_el, 1, get_path)
    
    # These are the vertices BETWEEN key vertices - ON the shortest paths between them:
    path_vertices <- setdiff(unique(unlist(paths)), key_vertices)
    g <- g %>% set_vertex_attr("color", index=path_vertices, value="gray")
    
    
    # Mark all edges of a shortest path
    mark_edges <- function(path, edges=c()){
      # Get a vector of id:s of connected vertices, find edge-id:s of all edges between them.
      for(n in 1:(length(path)-1)){
        i <- path[n]
        j <- path[1+n]
        edge <- get.edge.ids(g, c(i,j), directed = TRUE, error=FALSE, multi=FALSE)
        edges <- c(edges, edge)
      }
      # Return all edges in this path
      (edges)
    }
    
    # Find all edges that are part of the shortest paths between key vertices
    key_edges <- lapply(paths, function(x) if(length(x) > 1){mark_edges(x)})
    key_edges <- unique(unlist(key_edges))
    g <- g %>% set_edge_attr("color", index=key_edges, value="green")
    
    # This now shoes the full graph and the sub-graph which will be created
    plot(g)
    
    # Create sub-graph:
    sg_vertices <- sort(union(key_vertices, path_vertices))
    unclean_sg <- induced_subgraph(g, sg_vertices)
    # Note that it is essential to provide both a verticy AND an edge-index for the
    # subgraph since edges between included vertices do not have to be part of the
    # calculated shortest path. I never used it before, but eids=key_edges given
    # to induced_subgraph() should work (even though it didn't for me just now).
    
    # See the problem here:
    plot(unclean_sg)
    
    # Kill edges of the sub-graph that were not part of shortest paths of the mother
    # graph:
    sg <- delete.edges(unclean_sg, which(E(unclean_sg)$color=="gray"))
    
    # Plot a comparison:
    l <-layout.auto(g)
    layout(matrix(c(1,1,2,3), 2, 2, byrow = TRUE))
    plot(g, layout=l)
    plot(unclean_sg, layout=l[sg_vertices,])  # cut l to keep same layout in subgraph
    plot(sg, layout=l[sg_vertices,])          # cut l to keep same layout in subgraph
    

    【讨论】:

      猜你喜欢
      • 2016-03-04
      • 2015-06-12
      • 1970-01-01
      • 1970-01-01
      • 2021-12-18
      • 1970-01-01
      • 1970-01-01
      • 2023-01-15
      • 2017-04-18
      相关资源
      最近更新 更多