从图中删除不具有特定属性的节点时出错

Error when removing nodes that do not have a certain attrubute from the graph

我用 networkx 生成了一个图表。然后我将属性 'commu_per' 添加到一些节点。然后想删除那些没有属性 'commu_per'.

的节点
import urllib3
import io
import networkx as nx
from networkx.algorithms import community

## Import dataset
http = urllib3.PoolManager()
url = 'https://raw.githubusercontent.com/leanhdung1994/WebMining/main/lesmis.gml'
f = http.request('GET', url)
data = io.BytesIO(f.data)
g = nx.read_gml(data)

## Define a function to add attributes
def add_att(g, att, att_name):
    att = list(att)
    for i in g.nodes():
        for j in range(len(att)):
            if i in list(att[j]):
                nx.set_node_attributes(g, {i: j}, name = att_name)
                break

## Add attributes
commu_per = community.k_clique_communities(g, 3)   
add_att(g, commu_per, 'commu_per')

g_1 = g
## Remove nodes which do not have attribute 'commu_per'
for i in g.nodes:
    if 'commu_per' not in g.nodes[i]:
        g_1.remove_node(i)

然后它returns一个错误

---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-6-7339f3f2ea6a> in <module>
     26 g_1 = g
     27 ## Remove nodes which do not have attribute 'commu_per'
---> 28 for i in g.nodes:
     29     if 'commu_per' not in g.nodes[i]:
     30         g_1.remove_node(i)

RuntimeError: dictionary changed size during iteration

能否请您详细说明如何解决这个错误?

你的 g 和 g1 dict 对象是一样的。因此,在 1 上获取迭代器并使用它来尝试删除另一个是行不通的。

>>> a  = {1:10, 2:20}
>>> b  = a
>>> id(b) == id(a)
True
>>> b[4] = 40
>>> id(b) == id(a)
True
>>> b
{1: 10, 2: 20, 4: 40}
>>> a
{1: 10, 2: 20, 4: 40}
>>> 

使用 copy() 方法获取新副本,以便您可以在迭代同一对象时删除键。

>>> c = b.copy()
>>> id(b) == id(c)
False
>>> c[5] = 50
>>> c
{1: 10, 2: 20, 4: 40, 5: 50}
>>> 
>>> b
{1: 10, 2: 20, 4: 40}
>>> 

另一种方法是使用for i in list(g.nodes)

您的问题是由于 networkx 将图形存储在基于字典的数据结构中。

当您使用 for 循环遍历字典时,如果字典本身发生变化,python 将 运行 陷入困境。

所以您需要做的是以某种方式创建一个列表或一些其他不具有该属性的节点集合,然后删除它们。

如果您对“列表理解”还不适应,可以这样做:

nodes_to_delete = []
for node in g.nodes:
    if 'commu_per' not in g.nodes[node]:
    nodes_to_delete.append(node)
g.remove_nodes_from(nodes_to_delete)

要使用列表理解(消除 for 循环)来做到这一点,您可以这样做

nodes_to_delete = [node for node in g.nodes if 'commu_per' not in g.nodes[node]]
g.remove_nodes_from(nodes_to_delete)
delete = [i for i in g.nodes if 'commu_per' not in g.nodes[node]]
g.remove_nodes_from(delete)