Построить граф NetworkX из фрейма данных Pandas

Я хотел бы создать некоторые графики NetworkX из простого фрейма данных Pandas:

        Loc 1   Loc 2   Loc 3   Loc 4   Loc 5   Loc 6   Loc 7
Foo     0       0       1       1       0       0           0
Bar     0       0       1       1       0       1           1
Baz     0       0       1       0       0       0           0
Bat     0       0       1       0       0       1           0
Quux    1       0       0       0       0       0           0

здесь Foo… - это индекс, и Loc 1 to Loc 7 - это столбцы. Но преобразование в Матрицы Numpy или recarrays, похоже, не работает для генерации ввода для nx.Graph(). Существует ли стандартная стратегия достижения этой цели? Я не против переформатирования данных в Pandas --> dumping в CSV --> importing в NetworkX, но кажется, что я должен иметь возможность генерировать ребра из индекс и узлы из значений.

3 ответов


NetworkX ожидает квадратную матрицу (узлов и ребер), возможно,* вы хотите передать его:

In [11]: df2 = pd.concat([df, df.T]).fillna(0)

Примечание: важно, чтобы индекс и столбцы находились в одном порядке!

In [12]: df2 = df2.reindex(df2.columns)

In [13]: df2
Out[13]: 
       Bar  Bat  Baz  Foo  Loc 1  Loc 2  Loc 3  Loc 4  Loc 5  Loc 6  Loc 7  Quux
Bar      0    0    0    0      0      0      1      1      0      1      1     0
Bat      0    0    0    0      0      0      1      0      0      1      0     0
Baz      0    0    0    0      0      0      1      0      0      0      0     0
Foo      0    0    0    0      0      0      1      1      0      0      0     0
Loc 1    0    0    0    0      0      0      0      0      0      0      0     1
Loc 2    0    0    0    0      0      0      0      0      0      0      0     0
Loc 3    1    1    1    1      0      0      0      0      0      0      0     0
Loc 4    1    0    0    1      0      0      0      0      0      0      0     0
Loc 5    0    0    0    0      0      0      0      0      0      0      0     0
Loc 6    1    1    0    0      0      0      0      0      0      0      0     0
Loc 7    1    0    0    0      0      0      0      0      0      0      0     0
Quux     0    0    0    0      1      0      0      0      0      0      0     0

In[14]: graph = nx.from_numpy_matrix(df2.values)

это не передает имена столбцов/индексов в график, если вы хотите сделать это, вы можете использовать relabel_nodes (возможно, вам придется опасаться дубликатов, которые разрешены в кадрах данных панд):

In [15]: graph = nx.relabel_nodes(graph, dict(enumerate(df2.columns))) # is there nicer  way than dict . enumerate ?

*это неясно, что именно представляют собой столбцы и индекс для желаемого графика.


немного поздний ответ, но теперь networkx может считывать данные из фреймов данных pandas в таком случае идеальный формат для простого ориентированного графа:

+----------+---------+---------+
|   Source |  Target |  Weight |
+==========+=========+=========+
| Node_1   | Node_2  |   0.2   |
+----------+---------+---------+
| Node_2   | Node_1  |   0.6   |   
+----------+---------+---------+

Если вы используете матрицы смежности, то Энди Хейден прав, вы должны позаботиться о правильном формате. Поскольку в своем вопросе вы использовали 0 и 1, я думаю, вы хотели бы видеть неориентированный граф. Сначала это может показаться нелогичным, так как вы сказали индекс представляет, например, человека, а столбцы представляют группы, к которым принадлежит данный человек, но это правильно и с другой стороны, группа (членство) принадлежит человеку. Следуя этой логике, вы должны также поместить группы в индексы и людей в столбцы.

просто Примечание: Вы также можете определить эту проблему в смысле направленного графика, например, вы хотели бы визуализировать ассоциативную сеть иерархических категорий. Там ассоциация, например, от Samwise Gamgee до Хоббиты сильнее, чем в другом направлении обычно (так как Фродо Бэггинс, скорее всего, прототип Хоббита)


вы также можете использовать scipy для создания квадратной матрицы следующим образом:

import scipy.sparse as sp

cols = df.columns
X = sp.csr_matrix(df.astype(int).values)
Xc = X.T * X  # multiply sparse matrix
Xc.setdiag(0)  # reset diagonal

# create dataframe from co-occurence matrix in dense format
df = pd.DataFrame(Xc.todense(), index=cols, columns=cols)

позже вы можете создать список ребер из фрейма данных и импортировать его в Networkx:

df = df.stack().reset_index()
df.columns = ['source', 'target', 'weight']

df = df[df['weight'] != 0]  # remove non-connected nodes

g = nx.from_pandas_edgelist(df, 'source', 'target', ['weight'])