从Pandas数据框架构造NetworkX图

2024-05-15 23:21:18 发布

您现在位置:Python中文网/ 问答频道 /正文

我想从一个简单的Pandas数据框创建一些NetworkX图:

        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 1Loc 7是列。但是,转换成Numpy矩阵或重新排列似乎无法为nx.Graph()生成输入。是否有一个标准的策略来实现这一点?我不反对重新格式化Pandas中的数据-->;转储到CSV-->;导入到NetworkX,但似乎我应该能够从索引生成边,从值生成节点。


Tags: 数据gtnumpynetworkxpandas标准foobar
3条回答

您还可以使用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)

稍后,您可以从dataframe创建一个边缘列表并将其导入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'])

NetworkX expects a square matrix(节点和边),可能*您想传递它:

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)

如果您想使用^{}来传递列/索引名,则这不会将列/索引名传递给图形(您可能必须小心重复项,这在pandas的数据帧中是允许的):

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

*目前还不清楚列和索引究竟代表了所需图形的什么。

回答有点晚,但是now networkx can read data from pandas dataframes,在这种情况下,理想情况下,对于简单的有向图,格式如下:

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

如果你使用的是邻接矩阵,那么安迪海登是对的,你应该注意正确的格式。因为在您的问题中,您使用了0和1,我想您希望看到一个无向图。首先,这似乎有悖常理,因为您说索引表示例如一个人,而列表示某个人所属的组,但另一方面,组(成员)属于某个人也是正确的。按照这种逻辑,实际上应该将组放在索引中,人员也放在列中。

只是一个附带说明:您还可以用有向图的意义定义这个问题,例如,您希望可视化层次类别的关联网络。在那里,从Samwise Gamgee到霍比特人之间的联系通常比在另一个方向上更为紧密(因为Frodo Baggins更可能是霍比特人的原型)

相关问题 更多 >