从Pandas DataFrame构建NetworkX图

25

我想从一个简单的Pandas DataFrame创建一些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,但看起来我应该能够从索引生成边缘并从值生成节点。

3个回答

25

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(您可能需要注意 Pandas 数据帧中允许的重复项):

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

*目前尚不清楚所需图表中的列和索引具体表示什么。


1
索引代表一个人,列代表一个给定的人所属的组。 - urschrei

12

回答有点晚,但现在networkx可以从pandas数据框中读取数据。在这种情况下,一个简单有向图的理想格式如下:

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

如果你正在使用邻接矩阵,那么Andy Hayden是正确的,你应该注意正确的格式。由于在你的问题中使用了0和1,我猜你想看到一个无向图。这可能起初似乎与你所说的“索引代表人,列代表给定人所属的组”的逻辑相反,但同样也正确,因为一个组(成员身份)也属于一个人。按照这种逻辑,你实际上应该将组放在索引中,将个人也放在列中。

顺便提一句:你还可以从有向图的角度定义这个问题,例如你想要可视化层次类别的关联网络。在那里,从山姆·詹吉到霍比特人的关联通常比另一个方向更强(因为弗罗多·巴金斯更有可能是霍比特人原型)。


2
你可以使用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'])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接