微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

带有指向 networkx 有向图的链接列表的数据框

如何解决带有指向 networkx 有向图的链接列表的数据框

我有一个用于链接文档集合的数据框,我想将其转换为具有边权重 link_weight 和节点属性 doc_attribute 的有向图。有什么有效方法可以做到这一点?我在这里提供了一个小例子,但实际数据针对大约 10 万个文档,每个文档平均有大约 10 个链接

示例:

import pandas as pd
import numpy as np
from string import ascii_lowercase

N = 100
doc_ids = [f"doc_{j}" for j in range(N)]
doc_attrs = np.random.choice(list(ascii_lowercase),N)
link_weights = np.random.choice(10,N)
links = [random.choices(doc_ids,k=np.random.choice(4)) for j in range(N)]
    
df = pd.DataFrame(data={"doc_attribute": doc_attrs,"link_weight":link_weights,"linked_docs":links},index=doc_ids) 

通知文档可能不包含链接文档或指向文档的链接

      doc_attribute  link_weight               linked_docs
doc_0             b            3          [doc_55,doc_67]
doc_1             i            2                        []
doc_2             l            4                  [doc_72]
doc_3             f            1                  [doc_78]
doc_4             e            6                  [doc_50]
doc_5             k            3                  [doc_24]
doc_6             j            6    [doc_3,doc_6,doc_63]
doc_7             g            4  [doc_11,doc_59,doc_59]
doc_8             f            9                        []
doc_9             f            8                  [doc_57]

期望输出:nx.DiGraph 对象,节点由 df.index 给出,有向边指向 linked_docs,节点属性 doc_attribute链接权重 link_weight。 Networkx 具有 from_dataframe 函数,但适用于不同的输入格式。我不知道创建有向图的最有效方法

解决方法

您可以使用 from_dict_of_dicts,然后使用 set_node_attributes 设置节点的属性:

dod = {d['index']: {t: {"weight": d['link_weight']} for t in d['linked_docs']} for d in
       df[['linked_docs','link_weight']].reset_index().to_dict('records')}

dg = nx.from_dict_of_dicts(dod,create_using=nx.DiGraph)
nx.set_node_attributes(dg,df['doc_attribute'].to_dict(),'doc_attribute')
,

首先使用pandas将链表列扩展为行,然后使用from_pandas_edgelist:

df["source_docs"] = df.index 
df = df.explode("linked_docs")
graph = nx.from_pandas_edgelist(
    df,source="source_docs",target="linked_docs",edge_attr="link_weight",create_using=nx.DiGraph,)    
nx.set_node_attributes(graph,'doc_attribute')
# remove the node created for source docs without links
graph.remove_node(np.nan)

示例输出:

df.head(10)

"""
      doc_attribute  link_weight linked_docs source_docs
doc_0             l            4      doc_62       doc_0
doc_1             k            1      doc_24       doc_1
doc_1             k            1      doc_20       doc_1
doc_2             g            1      doc_25       doc_2
doc_2             g            1      doc_47       doc_2
doc_3             u            6      doc_58       doc_3
doc_4             j            6      doc_83       doc_4
doc_4             j            6      doc_73       doc_4
doc_4             j            6      doc_51       doc_4
doc_5             w            2      doc_75       doc_5
"""

len(graph.nodes) # 100

sorted(graph.edges.data(),key=lambda x: int(x[0].split("_")[-1]))[0:10]
"""
[('doc_0','doc_62',{'link_weight': 4}),('doc_1','doc_24',{'link_weight': 1}),'doc_20',('doc_2','doc_25','doc_47',('doc_3','doc_58',{'link_weight': 6}),('doc_4','doc_83','doc_73','doc_51',('doc_5','doc_75',{'link_weight': 2})
]
"""


sorted(graph.nodes.data(),{'doc_attribute': 'l'}),{'doc_attribute': 'k'}),{'doc_attribute': 'g'}),{'doc_attribute': 'u'}),{'doc_attribute': 'j'}),{'doc_attribute': 'w'}),('doc_6',{'doc_attribute': 'b'}),('doc_7',{'doc_attribute': 's'}),('doc_8',('doc_9',{'doc_attribute': 'e'})
]
"""

然而,对于 N=100000,n_links ~10 在我的机器上,这比其他解决方案慢约 40%,两个解决方案都超过一秒。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。