Построить граф 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'])