从 Pandas DataFrame 构建 NetworkX 图
Posted
技术标签:
【中文标题】从 Pandas DataFrame 构建 NetworkX 图【英文标题】:Construct NetworkX graph from Pandas DataFrame 【发布时间】:2014-02-08 01:55:55 【问题描述】:我想从一个简单的 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 1
到Loc 7
是列。但是转换为 Numpy 矩阵或重新数组似乎不适用于为nx.Graph()
生成输入。是否有实现此目标的标准策略?我不反对在 Pandas 中重新格式化数据 --> 转储到 CSV --> 导入到 NetworkX,但似乎我应该能够从索引中生成边,从值中生成节点。
【问题讨论】:
【参考方案1】: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)
这不会将列/索引名称传递给图表,如果您想这样做,您可以使用relabel_nodes
(您可能必须警惕重复,这在 pandas 的 DataFrames 中是允许的):
In [15]: graph = nx.relabel_nodes(graph, dict(enumerate(df2.columns))) # is there nicer way than dict . enumerate ?
*对于所需图表,列和索引到底代表什么尚不清楚。
【讨论】:
索引代表例如一个人,列表示给定人所属的组。【参考方案2】:答案有点晚,但是now networkx can read data from pandas dataframes,在这种情况下,理想情况下,简单有向图的格式如下:
+----------+---------+---------+
| Source | Target | Weight |
+==========+=========+=========+
| Node_1 | Node_2 | 0.2 |
+----------+---------+---------+
| Node_2 | Node_1 | 0.6 |
+----------+---------+---------+
如果您使用的是邻接矩阵,那么 Andy Hayden 是对的,您应该注意正确的格式。由于在您的问题中您使用了 0 和 1,我想您希望看到一个无向图。自从您说 Index 代表例如一个人,列代表给定人所属的组,但另一方面,组(成员资格)属于一个人也是正确的。按照这个逻辑,您实际上应该将组放在索引中,并将人员也放在列中。
附注:您也可以在有向图的意义上定义此问题,例如,您希望可视化分层类别的关联网络。在那里,协会例如从 Samwise Gamgee 到 Hobbits 通常比在另一个方向上更强(因为 Frodo Baggins 更可能是 Hobbit 原型)
【讨论】:
【参考方案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)
稍后您可以从数据框创建边缘列表并将其导入 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'])
【讨论】:
以上是关于从 Pandas DataFrame 构建 NetworkX 图的主要内容,如果未能解决你的问题,请参考以下文章
从大型元组/行列表中有效地构建 Pandas DataFrame
从大型元组/行列表中有效地构建 Pandas DataFrame
构建 MultiIndex pandas DataFrame 嵌套 Python 字典
pandas构建复合索引数据(multiple index dataframe)pandas索引复合索引dataframe数据