Обрезка больших графов блуждающих узлов - PullRequest
5 голосов
/ 09 сентября 2011

У меня есть график, состоящий из около 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 и оболочки, но я думаю, что мне нужен лучший подход.Разве может быть уже есть инструменты для этого?Данные представлены в графическом формате, но я не видел в этом наборе инструментов, относящихся к данной задаче.

О, и если есть простой способ сделать что-то подобное, я открыт для предложений -- это не должно быть именно той задачей, которую я предложил.Я просто ищу способ удалить большую часть шума, окружающего большие сгустки (которые редки и в основном это всего лишь несколько пересекающихся цепей).

Ответы [ 3 ]

5 голосов
/ 09 сентября 2011

Инструмент gvpr , входящий в состав graphviz tools , позволяет применять правила к графу и выводить измененный граф.

Из описания:

Копирует входные графы в свой вывод, возможно преобразовывая их структуру и атрибуты, создавая новые графы, ...

Похоже, вы хотите удалить все узлы, имеющие степень0 и имеющие только связанные узлы (преемники) со степенью 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. Цикл по всем ребрам один время и заполнение двух списков:

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

    Так что же добавляется в какой список?

    • Любые два узла, соединенные друг с другом, гдехвостовой узел не имеет никаких входящих ребер, а головной узел не имеет никаких исходящих ребер, образует цепочку только из 2 узлов и поэтому кандидатов подлежит удалению;то есть, если одни и те же узлы не являются частью другой цепочки длиннее двух узлов:
    • Хвостовой узел без каких-либо входящих ребер, но связанный с головным узлом, который сам имеет исходящие ребра, является хранителем
    • Головной узел без каких-либо исходящих ребер, но связанный с хвостовым узлом, который сам имеет входящие ребра, также является хранителем .
  2. Удалить все кандидатов не в хранителях

Это решение является не общим и работает только для проблемы, указанной в вопросе, чтодержит только цепочки длиной не менее 3 узлов.Он также не удалит короткие циклы (два узла соединены друг с другом).

Вы можете вызвать это, используя следующую строку:

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

Вывод с использованием вашего примера диаграммы:

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

Обратите внимание, что это мой первый скрипт gvpr - возможно, есть лучшие способы написать это, и я не уверен, как он обрабатывает 35000 узлов, хотя я уверен, что этого не должно бытьбольшое дело.


См. также Graphviz / Dot - как пометить все листья в дереве отличительным цветом? для более простого примера преобразования графа.

2 голосов
/ 09 сентября 2011

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

Ниже приведен простой алгоритм O (N + E).для всех графов N узлов и E ребер по критерию длины пути-3.Этот алгоритм может быть легко реализован на 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) элемента, который читается в: Если (S [p] == 3) или (S [q] == 3) выходной фронт (p, q).

Чтобы расширить этот метод до длины пути K, отличной от 3, сохраните список ребер в памяти, сохраните 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 ребра в массив 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= Н [я] .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.}

Этот метод может ошибаться, если graph не является DAG и содержит короткие петлевые пути.Например, если ребра графа включают в себя (1,2) и (2,1) и никакие другие узлы не связаны с узлами 1 или 2, то ни одно из этих ребер не должно выводиться;но мы получим K + 2 для cc [] и pc [] этих узлов, поэтому они все равно получат вывод.

2 голосов
/ 09 сентября 2011

Gephi - отличный графический инструмент с открытым исходным кодом для визуализации и управления графиками, и вы, вероятно, сможете найти там какой-то фильтр для такого рода вещей ... Может быть, фильтр степеней будет делать: он будет удалять узлы, которые имеют только один край. Вы также можете фильтровать по степени, по степени, вычислять PageRank и т. Д. Он также имеет некоторые действительно хорошие параметры размера / метки / цвета и его легко увеличивать / уменьшать.

...