Как я могу сгруппировать график в Python?

Пусть G — граф. Итак, G — это множество узлов и множество связей. Мне нужно найти быстрый способ разбить граф. Граф, над которым я сейчас работаю, имеет только 120*160 узлов, но, возможно, вскоре я буду работать над эквивалентной задачей в другом контексте (не в медицине, а в разработке веб-сайтов) с миллионами узлов.

Итак, что я сделал, так это сохранил все ссылки в матрице графа:

M=numpy.mat(numpy.zeros((len(data.keys()),len(data.keys()))))

Теперь M содержит 1 в позиции s,t, если узел s соединен с узлом t. Я удостоверяюсь, что M симметричен M[s,t]=M[t,s] и каждый узел связан с самим собой M[s,s]=1.

Если я хорошо помню, если я умножу M на M, результатом будет матрица, представляющая граф, соединяющий вершины, достигнутые за два шага.

Поэтому я продолжаю умножать М на себя, пока количество нулей в матрице больше не будет уменьшаться. Теперь у меня есть список подключенных компонентов. И теперь мне нужно кластеризовать эту матрицу.

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

По сути, мне нужно разбить этот граф на связанные компоненты.

Я могу просмотреть все узлы и посмотреть, к чему они подключены.

А как насчет сортировки матрицы по переупорядочиванию строк. Но я не знаю, возможно ли это сделать.

Далее следует код:

def findzeros(M):
    nZeros=0
    for t in M.flat:
        if not t:
            nZeros+=1
    return nZeros

M=numpy.mat(numpy.zeros((len(data.keys()),len(data.keys()))))    
for s in data.keys():
    MatrixCells[s,s]=1
    for t in data.keys():
        if t<s:
            if (scipy.corrcoef(data[t],data[s])[0,1])>threashold:
                M[s,t]=1
                M[t,s]=1

nZeros=findzeros(M)
M2=M*M
nZeros2=findzeros(M2)

while (nZeros-nZeros2):
    nZeros=nZeros2
    M=M2
    M2=M*M
    nZeros2=findzeros(M2)

Редактировать:

Было предложено использовать разложение SVD. Вот простой пример задачи на графе 5х5. Мы будем использовать это, так как с квадратной матрицей 19200x19200 не так просто увидеть кластеры.

import numpy
import scipy

M=numpy.mat(numpy.zeros((5,5)))

M[1,3]=1
M[3,1]=1
M[1,1]=1
M[2,2]=1
M[3,3]=1
M[4,4]=1
M[0,0]=1

print M

u,s,vh = numpy.linalg.linalg.svd(M)
print u
print s
print vh

По сути, здесь 4 кластера: (0), (1,3), (2), (4). Но я все еще не понимаю, как svn может помочь в этом контексте.


person Pietro Speroni    schedule 17.03.2009    source источник
comment
Не могли бы вы уточнить свой вопрос. Я нашел, возможно ли это (на который всегда отвечают «да», так что это не может быть вашим настоящим вопросом) и я не вижу, как SVD может помочь, что не является настоящим вопросом. Каков твой вопрос?   -  person S.Lott    schedule 17.03.2009
comment
Здравствуйте, спасибо, что уделили время моему вопросу. Возникает явный вопрос: как мне определить подключенные компоненты? Я думал, ты это понял, а где просто невинное развлечение.   -  person Pietro Speroni    schedule 17.03.2009
comment
@Pietro Speroni: Попробуйте переписать свой вопрос, чтобы сделать его более простым, целенаправленным и ясным. Долгое обсуждение трудно уследить. Примеры короткого кода и очень очевидный вопрос лучше. Вы предоставляете какой-то код, поэтому спрашиваете, как мне определить..? не кажется правильным.   -  person S.Lott    schedule 17.03.2009
comment
Спасибо, но поскольку я получил ответ, который искал, и поскольку другие пользователи, похоже, достаточно хорошо поняли вопрос, я думаю, что буду придерживаться этого. С уважением, Пьетро   -  person Pietro Speroni    schedule 18.03.2009


Ответы (8)


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

РЕДАКТИРОВАТЬ: NetworkX кажется, что это может быть лучший выбор, чем python-graph; его документация (здесь для функции подключенных компонентов) конечно есть.

person kquinn    schedule 17.03.2009
comment
Благодарю вас! Похоже, отличный ресурс. Я тщательно расследую это. - person Pietro Speroni; 17.03.2009

В SciPy вы можете использовать разреженные матрицы. Также обратите внимание, что существуют более эффективные способы умножения матрицы на саму себя. В любом случае, то, что вы пытаетесь сделать, может быть выполнено путем разложения SVD.

Введение с полезными ссылками.

person vartec    schedule 17.03.2009
comment
Спасибо. Я посмотрел ресурс, но, честно говоря, не вижу, чем он может помочь. Я обновил вопрос простым примером, и как SVN des, похоже, не решает его. Или тогда, может быть, я использую его неправильно? Но как тогда? Спасибо в любом случае :) - person Pietro Speroni; 17.03.2009
comment
Это SVD (разложение по единственному значению). В основном для чего-то такого большого, как миллионы узлов, вам понадобится алгоритм приближения, а не точный (кластеризация графа является NP-полной). В статье есть ссылки на статьи, объясняющие такие алгоритмы. - person vartec; 17.03.2009
comment
КСТАТИ. вы пытаетесь заново изобрести PageRank или HITS? - person vartec; 17.03.2009
comment
Не совсем. Сейчас просто сортирую, какие данные принадлежат какой биологической клетке. В будущем у меня есть аналогичная проблема, которая в конечном итоге сгенерирует поисковую систему. Но не на страницах. И не используя ссылки. (Не могу сказать больше на данном этапе :)). В любом случае поздравляю! Хорошо подмечено, лол. - person Pietro Speroni; 17.03.2009
comment
Скрытый семантический анализ? ;-) Ладно, не буду тянуть тебя за язык. Просто имейте в виду, что то, что возможно в малых масштабах, становится очень сложным в больших. Большинство графовых алгоритмов имеют высокую полиномиальную сложность, поэтому их сложно использовать на 1 миллионе узлов. - person vartec; 17.03.2009

Также есть graph_tool и networkit, которые имеют эффективные процедуры для подключенных компонентов и эффективно сохраняют сеть. Если вы собираетесь работать с миллионами узлов, networkx, вероятно, будет недостаточно (на самом деле это чистый python). Оба этих инструмента написаны на C++, поэтому могут выполнять анализ больших графов с разумным временем выполнения.

Как указывает Фил, ваш метод будет иметь ужасно долгое время вычислений для больших графов (мы говорим о днях, неделях, месяцах...), а вашему представлению графа из миллиона узлов потребуется около миллиона гигабайт памяти. !

person drevicko    schedule 26.04.2015

Поиск оптимального разбиения графа — это NP-сложная задача, поэтому каким бы ни был алгоритм, это будет приближение или эвристика. Неудивительно, что разные алгоритмы кластеризации дают (сильно) разные результаты.

Реализация алгоритма модульности Ньюмана на Python: модульность

Также: MCL, MCODE, CFinder, NeMo, clusterONE

person lynxoid    schedule 21.09.2011

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


import sys
from operator import gt, lt

class Graph(object):
    def __init__(self):
        self.nodes = set()
        self.edges = {}
        self.cluster_lookup = {}
        self.no_link = {}

    def add_edge(self, n1, n2, w):
        self.nodes.add(n1)
        self.nodes.add(n2)
        self.edges.setdefault(n1, {}).update({n2: w})
        self.edges.setdefault(n2, {}).update({n1: w})

    def connected_components(self, threshold=0.9, op=lt):
        nodes = set(self.nodes)
        components, visited = [], set()
        while len(nodes) > 0:
            connected, visited = self.dfs(nodes.pop(), visited, threshold, op)
            connected = set(connected)
            for node in connected:
                if node in nodes:
                    nodes.remove(node)

            subgraph = Graph()
            subgraph.nodes = connected
            subgraph.no_link = self.no_link
            for s in subgraph.nodes:
                for k, v in self.edges.get(s, {}).iteritems():
                    if k in subgraph.nodes:
                        subgraph.edges.setdefault(s, {}).update({k: v})
                if s in self.cluster_lookup:
                    subgraph.cluster_lookup[s] = self.cluster_lookup[s]

            components.append(subgraph)
        return components

    def dfs(self, v, visited, threshold, op=lt, first=None):
        aux = [v]
        visited.add(v)
        if first is None:
            first = v
        for i in (n for n, w in self.edges.get(v, {}).iteritems()
                  if op(w, threshold) and n not in visited):
            x, y = self.dfs(i, visited, threshold, op, first)
            aux.extend(x)
            visited = visited.union(y)
        return aux, visited

def main(args):
    graph = Graph()
    # first component
    graph.add_edge(0, 1, 1.0)
    graph.add_edge(1, 2, 1.0)
    graph.add_edge(2, 0, 1.0)

    # second component
    graph.add_edge(3, 4, 1.0)
    graph.add_edge(4, 5, 1.0)
    graph.add_edge(5, 3, 1.0)

    first, second = graph.connected_components(op=gt)
    print first.nodes
    print second.nodes

if __name__ == '__main__':
    main(sys.argv)
person Community    schedule 17.03.2009

Как отмечали другие, не нужно изобретать велосипед. Много внимания было уделено оптимальным методам кластеризации. Вот одна известная программа кластеризации.

person RexE    schedule 18.03.2009

Похоже, существует библиотека PyMetis, которая разделит ваш граф, учитывая список ссылки. Должно быть довольно легко извлечь список ссылок из вашего графика, передав ему исходный список связанных узлов (а не матрично-умноженный).

Многократное выполнение M' = MM не будет эффективным для больших порядков M. Полное умножение матриц для матриц порядка N будет стоить N умножений и N-1 сложений на элемент, из которых N2, то есть O(N3) операций. Если вы масштабируете это до «миллионов узлов», это будет O (1018) операций на умножение матрицы на матрицу, из которых вы хотите сделать несколько.

Короче говоря, вы не хотите делать это таким образом. предложение SVD от Vartec будет единственным подходящим выбором. Ваш лучший вариант — просто использовать PyMetis, а не пытаться заново изобретать графовое разбиение.

person Phil H    schedule 17.03.2009
comment
Спасибо. Я признаю, что предложение СВД полностью вылетело у меня из головы. Я знаю, что разбиение графа — хорошо изученная проблема, поэтому я надеялся получить хорошие идеи, когда писал здесь. Но я также хотел написать то, что знал, показать свою добрую волю :-) - person Pietro Speroni; 17.03.2009
comment
Я думаю, ключ в том, чтобы решить, хотите ли вы узнать о разбиении достаточно, чтобы переписать на нем программное обеспечение (вероятно, нет), или вы просто хотите разбить граф. Если вы решили просто использовать существующие решения, выберите библиотеку и используйте ее. Стремитесь решить ее на высшем уровне. - person Phil H; 17.03.2009
comment
Я попытался установить PyMetis, но мне кажется, что установка затруднена. Файла конфигурации вроде нет. В поисках самого простого выхода я вместо этого установлю networkx. Спасибо, Пьетро - person Pietro Speroni; 03.04.2009

Алгоритм SVD здесь неприменим, но в остальном прав Фил Х.

person Community    schedule 18.03.2009