NetworkX - 设置节点从数据框属性

时间:2019-02-02 21:59:05

标签: python pandas networkx

我在弄清楚如何从数据帧中的列向网络中的节点添加属性时遇到麻烦。

我提供以下,大约有总共10列我的数据帧的例子,但我只使用创建我的网络时如下所示的5列。

不幸的是,目前只能使边缘属性与我的网络一起使用,我正在这样做,如下所示:

g = nx.from_pandas_dataframe(df, 'node_from', 'node_to', edge_attr=['attribute1','attribute2','attribute3'])

该网络将是定向网络。在下面的数据帧中示出的属性为“node_from”节点的属性。 “ node_to”节点有时显示为“ node_from”节点。 df_attributes_only表中将显示网络中可能显示的所有节点及其各自的属性。

df_relationship:

node_from:  node_to: ........ attribute1:   attribute2:   attribute3:
    jim      john    ........    tall          red             fat
    ...

所有列均以单词作为其值,而不是数字。

我还有另一个数据框,其中包含每个可能的节点及其属性:

df_attributes_only:

id:   attribute1:   attribute2:     attribute3:
jim      tall          red             fat
john     small         blue            fat
...

我基本上需要将上述三个属性分配给它们各自的id,因此每个节点都附加有它们的3个属性。

这是我怎么能拿我的网络工作节点属性的任何帮助是极大的赞赏。

3 个答案:

答案 0 :(得分:2)

Networkx 2.0 开始,您可以在 nx.set_node_attributes 中输入词典字典以设置多个节点的属性。与手动遍历每个节点相比,这是一种更加简化的方法。外部词典键代表每个节点,内部词典键对应于要为每个节点设置的属性。像这样:

attr = {
    node0: {attr0: val00, attr1: val01},
    node1: {attr0: val10, attr1: val11},
    node2: {attr0: val20, attr1: val21},
}

您可以在documentation中找到更多详细信息。


以您的示例为例,假设索引为id,则可以将节点属性的数据框df_attributes_only转换为这种格式并添加到图形中:

df_attributes_only = pd.DataFrame(
    [['jim', 'tall', 'red', 'fat'], ['john', 'small', 'blue', 'fat']],
    columns=['id', 'attribute1', 'attribute2', 'attribute3']
)
node_attr = df_attributes_only.set_index('id').to_dict('index')
nx.set_node_attributes(g, node_attr)

g.nodes['jim']


>>> {'attribute1': 'tall', 'attribute2': 'red', 'attribute3': 'fat'}

答案 1 :(得分:1)

nx.from_pandas_dataframe(和from_pandas_edgelist在最新的稳定版本2.2),概念性地转换一个EdgeList都到的曲线图。即,在数据帧的每一行代表一个边缘,这是一对的 2个不同节点

使用此API将无法读取节点的属性。这是有道理的,因为每一行都有两个不同的节点,并且为不同的节点保留特定的列会很麻烦,并且可能导致差异。例如,考虑以下数据框:

node_from node_to src_attr_1 tgt_attr_1
  a         b         0         3
  a         c         2         4

节点a的“ src_attr_1”值应该是什么?是0还是2?而且,我们需要为每个属性保留两列(因为它是一个节点属性,所以每个边上的两个节点都应该拥有它)。在我看来,这将是糟糕的设计,以支持它,我想这就是为什么NetworkX API没有。

可以仍然读节点的属性,使用df转换成图形之后,如下所示:

import networkx as nx
import pandas as pd

# Build a sample dataframe (with 2 edges: 0 -> 1, 0 -> 2, node 0 has attr_1 value of 'a', node 1 has 'b', node 2 has 'c')
d = {'node_from': [0, 0], 'node_to': [1, 2], 'src_attr_1': ['a','a'], 'tgt_attr_1': ['b', 'c']}
df = pd.DataFrame(data=d)
G = nx.from_pandas_edgelist(df, 'node_from', 'node_to')

# Iterate over df rows and set the source and target nodes' attributes for each row:
for index, row in df.iterrows():
    G.nodes[row['node_from']]['attr_1'] = row['src_attr_1']
    G.nodes[row['node_to']]['attr_1'] = row['tgt_attr_1']

print(G.edges())
print(G.nodes(data=True))

编辑:

如果要为源节点提供大量属性,可以按以下步骤自动提取此列的字典:

#List of desired source attributes:
src_attributes = ['src_attr_1', 'src_attr_2', 'src_attr_3']

# Iterate over df rows and set source node attributes:
for index, row in df.iterrows():
    src_attr_dict = {k: row.to_dict()[k] for k in src_attributes}    
    G.nodes[row['node_from']].update(src_attr_dict)

答案 2 :(得分:0)

这是基于@ zohar.kom的答案。有一种无需迭代即可解决此问题的方法。该答案可以优化。我假设属性描述了node_from

从边缘列表中的图形开始(例如@ zohar.kom的分析服务):

 G = nx.from_pandas_edgelist(df, 'node_from', 'node_to')

您可以先添加节点和属性。

 # Create a mask with only the first records
 mask = ~df['node_from'].duplicated()
 # Get a list of nodes with attributes
 nodes = df[mask][['node_from','attribute1','attribute2','attribute3']]

这种从数据框中添加节点的方法来自this answer

 # Add the attributes one at a time.
 attr_dict = nodes.set_index('node_from')['attribute1'].to_dict()
 nx.set_node_attributes(G,attr_dict,'attr1')

 attr_dict = nodes.set_index('node_from')['attribute2'].to_dict()
 nx.set_node_attributes(G,attr_dict,'attr2')

 attr_dict = nodes.set_index('node_from')['attribute3'].to_dict()
 nx.set_node_attributes(G,attr_dict,'attr3')

与@ zohar.kom类似的结果,但迭代次数较少。