networkx与PyG计算度数degree时需避免的坑:自环selfloop和多重边

networkx与PyG计算度数degree时需避免的坑:自环selfloop和多重边


近日需要统计图的基本性质,在使用 nxPyG自带的度数计算时,发现他们的底层逻辑是不同的,因此计算结果在一些情况下也会不同。这里做个简单的小结,也避免自己今后踩坑。

先上结论:

  • networkx在计算度数的时候,自环selfloop部分会被计算为2,多重边只计算一条。
  • PyG中度数计算不分方向,只和传入index中每个节点出现的次数有关。
    • 使用PyG中的to_undirected将有向图转化为无向图后,自环边只有一条,因此自环度数为1
    • 多重边的度数为相应为n

下面分别看一下具体的实例。

networkx

有向图的self-loop

import networkx as nx
DG = nx.DiGraph()
DG.add_edges_from([[0, 0], [0, 1], [1, 2]])
nx.draw(DG, with_labels=True)

在这里插入图片描述
分别计算degree, out_degreein_degree

DG.degree(DG.nodes())
>>> DiDegreeView({0: 3, 1: 2, 2: 1}) #节点0的度数为3,因为自环的度数是2
DG.out_degree(DG.nodes())
>>> OutDegreeView({0: 2, 1: 1, 2: 0}) #节点0的出度为2,因为自环提供了出度1
DG.in_degree(DG.nodes())
>>> InDegreeView({0: 1, 1: 1, 2: 1}) #节点0的入度为1,因为自环提供了入度1

我们可以看到节点0degree, out_degreein_degree分别为3, 2, 1,这是因为在计算度数的时候,有向图中selfloop提供了2的度数。同样都是自己指向自己,但一次是自己指向了跟自己相同的邻居,一次是跟自己相同的邻居指向了自己。其中前者是出度,后者是入度。

无向图self-loop

import networkx as nx
G = nx.Graph()
G.add_edges_from([[0, 0], [0, 1], [1, 2]])
nx.draw(G, with_labels=True)

在这里插入图片描述

G.degree(G.nodes())
DegreeView({0: 3, 1: 2, 2: 1})

其中节点0的度数仍然为3。另外对于无向图,in_degreeout_degree方法不再适用。

多重边

import networkx as nx
DG = nx.DiGraph()
DG.add_edges_from([[0, 1], [0,1], [1, 2]])
nx.draw(DG, with_labels=True)

在这里插入图片描述

DG.out_degree(DG.nodes())
>>> OutDegreeView({0: 1, 1: 1, 2: 0})

可以看到尽管有两条(0,1)边,在计算度数的时候,只会被算作一条。这是因为nx内部存储是以字典形式存储信息的,多重边对应的键是一样的,因此后来传入的信息会覆盖前面的信息。

pytorch geometric

PyG的度数计算是利用torchscatter,所以是不分方向的,只看你传进去什么样的index。下面给大家举个例子:

from torch_geometric.utils import degree
import torch

edge_index = torch.tensor([[0, 0], [0, 1], [1, 2]]).T.contiguous() #传入和nx例子中相同的边
edge_index
>>> 
tensor([[0, 0, 1],
        [0, 1, 2]])

degree(edge_index[0])
>>> tensor([2., 1.])  #传入edge_index[0]计算出度,因为节点2没有出度,所以这里出度的shape只有(2,)

degree(edge_index[0], num_nodes=3)
>>> tensor([2., 1., 0.]) #指定节点个数,避免维度不同

degree(edge_index[1])
>>> degree(edge_index[1]) #传入edge_index[1]计算入度

PyGedge_index[0]source,所以对degree函数传入edge_index[0]计算出度。计算的逻辑就是统计index中每个节点出现的次数。如果有节点没有出度且节点的id在尾部,可以传入节点的个数,避免返回的结果出现缺失。同理传入edge_index[1]计算入度。

如果需要计算度数,可以先对有向的edge_index做无向处理。

from torch_geometric.utils import to_undirected
edge_index = to_undirected(edge_index)
edge_index
>>> tensor([[0, 0, 1, 1, 2],    #节点0的自环边只出现一次
        [0, 1, 0, 2, 1]])
        
degree(edge_index[0])
>>> tensor([2., 2., 1.])

可以看出来,to_undirected并不会重复自环边,所以后期计算自环度数时为1

因为计算的degree只和传入的index有关,所以重复边会被重复统计。

from torch_geometric.utils import degree
import torch

edge_index = torch.tensor([[0, 1], [0, 1], [1, 2]]).T.contiguous() #传入和上个例子中相同的边
edge_index
>>> tensor([[0, 0, 1],
        [1, 1, 2]])

degree(edge_index[0])
>>> tensor([2., 1.])
  • 9
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值