繁体   English   中英

修剪杂散节点的大图

[英]Pruning large graphs of stray nodes

我有一个图表,包含大约35,000个以纯文本表示的节点:

node1 -> node35000
node29420 -> node35000
node2334 -> node4116
...

我想通过删除不属于链的节点至少三个长来修剪它。 所以,如果我只有

1 -> 2;
2 -> 3;
3 -> 4;
0 -> 4;

我想保留1,2,3和4(因为1 -> 2 -> 3 -> 4是四个节点长)但丢弃0,即删除0 -> 4

有没有想过这样做的好方法? 我尝试了Perl和shell函数的组合,但我认为我需要一个更好的方法。 除非有工具可以做到这一点? 数据采用graphviz格式,但我没有看到该套件中的任何工具与手头的任务相关。

哦,如果有一种简单的方法可以做这样的事情,我会接受建议 - 它不一定是我建议的任务。 我只是想找到一种方法来消除大块周围的大部分噪音(这种情况很少见,而且大部分只是一些相交的链条)。

作为graphviz工具一部分的工具gvpr允许将规则应用于图形并输出修改后的图形。

从描述:

它将输入图复制到其输出,可能转换其结构和属性,创建新图,...

看起来您想要删除所有具有0的indegree并且仅具有outdegree为0的链接节点(后继者)的节点。

这是我的gvpr脚本版本nostraynodes.gv

BEGIN {node_t n; int candidates[]; int keepers[];}
E{
  if (tail.indegree == 0 && head.outdegree == 0)
  {
    candidates[tail] = 1;
    candidates[head] = 1;
  }
  else if (tail.indegree == 0)
  {
    keepers[tail] = 1;
  }
  else if (head.outdegree == 0)
  {
    keepers[head] = 1;
  }
}

END_G {
  for (candidates[n]){
    if (n in keepers == 0)
    {
       delete(NULL, n);
    }
  }
}

这是脚本的作用:

  1. 遍历所有边一个时间和填充两个列表:

    • 候选人 - 可能必须删除的节点列表,以及
    • keepers - 节点列表,可能最终出现在候选者中但不应被删除。

    那么什么被添加到哪个列表?

    • 任何两个节点彼此连接,其中尾节点没有任何进入边缘,并且头节点没有任何输出边缘,形成仅2个节点的链,因此是要删除的候选节点; 也就是说,除非相同的节点是长于2个节点的另一个链的一部分:
    • 没有任何入射边缘但连接到自身具有输出边缘的头节点的尾节点是保持器 ;
    • 没有任何输出边缘但连接到尾节点的头节点也是一个保持器 ,该节点本身具有输入边缘。
  2. 删除所有不在饲养员中的 候选人

此解决方案不是通用的,仅适用于问题中所述的问题,即仅保留链长度至少为3个节点。 它也不会删除短循环(两个节点相互连接)。

您可以使用以下行调用它:

gvpr -c -f .\nostraynodes.gv .\graph.dot

使用示例图表的输出是:

digraph g {
    1 -> 2;
    2 -> 3;
    3 -> 4;
}

请注意,这是我的第一个gvpr脚本 - 可能有更好的方法来编写它,我不知道它如何处理35000个节点,但我相信这不应该是一个大问题。


另请参见Graphviz / Dot - 如何用独特的颜色标记树中的所有叶子? 有关图变换的简单示例。

Gephi是一个出色的开源GUI工具,用于可视化和操作图形,你可能会在那里找到某种类型的过滤器......也许一个度过滤器会这样做:它会删除只有的节点有一个优势。 您还可以过滤度数,度数,可以计算PageRank等。它还有一些非常好的尺寸/标签/颜色选项,并且易于放大/缩小。

假设任何给定节点可以具有任意多个前驱或后继节点,则节点的度数和出度与解决问题无关。

以下是针对路径长度为3的标准的N个节点和E边缘的所有图的简单O(N + E)算法。 该算法可以在Perl或C中轻松实现。该方法基于定义和断言:将“制造节点”定义为具有父节点和子节点(前导节点和后继节点节点)的任何节点。 将保留的每个节点都是一个节点,或者是一个节点的父节点或子节点。

  1. 将状态数组S [Nmax]初始化为全零。 Nmax是最大节点数。 如果一开始就不知道Nmax,请读取所有数据并找出它。

  2. 读入给定的边缘列表。 每个输入项指定从节点p到节点q的有向边(p,q)。 对于读入的每个(p,q)项:将S [p]设置为S [p] | 1表示p具有子节点,并将S [q]设置为S [q] | 2表示q有父母。 (在此步骤之后,每个节点n都有S [n] == 3.)

  3. 再次阅读边缘列表。 对于读入的每个(p,q)项:If(S [p] == 3)或(S [q] == 3)输出边(p,q)。

要将此方法扩展到3以外的路径长度K,请将边列表保留在内存中,使用父链和子链的长度维护Sp []和Sc [],并执行K / 2次额外通过。 可能在时间O(N + K * E)做。 该问题没有指定图是否是DAG(有向无环图),但给出的示例是DAG。 对于K> 3,它可能会有所不同。

更新1这里是K> 3算法的更精确的陈述,其中H [i] .p和H [i] .q是边缘#i的端点,并且pc [j],cc [j]是前身的长度和关于节点j的后继链。 另外,设E =边缘数; N =节点数; 和K =保持边缘所需的最小链长。

  1. 将E edge数据条目读入H []数组。 将所有pc [j],cc [j]条目设置为0。

  2. 对于i = 1到E,设置cc [H [i] .p] = 1并且pc [H [i] .q] = 1。

  3. 对于j = 1至K + 1,{i = 1至E,{令p = H [i] .p且q = H [i] .q。 设定cc [p] = max(cc [p],1 + cc [q])和pc [q] = max(pc [q],1 + pc [p])。 }}

  4. 对于i = 1到E,{令p = H [i] .p并且q = H [i] .q。 输出边沿(p,q)如果pc [p] + cc [p] +1> = K且pc [q] + cc [q] +1> = K.}

如果图形不是DAG并且包含短循环路径,则此方法可能会出错。 例如,如果图形边缘包括(1,2)和(2,1)并且没有其他节点链接到节点1或2,则不应输出这些边缘; 但是我们最终得到了那些节点的cc []和pc []的K + 2,所以无论如何它们都得到输出。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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