我创建了一个iGraph.Graph
:
>> g.summary()
'IGRAPH DN-- 12120181 35746070 -- \n+ attr: name (v), rel (e)'
我想执行一个非常简单的查询:
def find(source:str, rel:str):
sel = g.es.select(_source=g.vs.find(source).index, rel_eq=rel)
if sel:
return [g.vs[res.target].attributes()['name'] for res in sel]
else:
raise ValueError('Not Found')
这需要花费大量时间:
%%time
>> find(source='Q43416', rel='P569')
Wall time: 17.8 s
我是在做错什么,还是有一些技巧可以提高性能?
先感谢您!
机器:win10,96 GB RAM,Xeon X5650; python 3.6。
....
我决定使用
Graph.incident()
来实现搜索,如下所示:def find2(source:Union[int, str], rel:str):
inc = g.incident(source, mode="out")
rels = map(lambda x: (x, g.es[x].attributes()['rel']), inc)
found = filter(lambda x: x[1] == rel, rels)
targets = map(lambda x: g.es[x[0]].target, found)
targets_names = map(lambda x: g.vs[x].attributes()['name'], targets)
return list(targets_names)
事实证明,我几乎立即获得了结果:
%%time
>> find2(10537653, 'P569')
Wall time: 0 ns
我可以使用该解决方案,但是这引发了一个问题:为什么
select
的工作时间更长?如果您能向我解释,我将不胜感激。 最佳答案
抱歉,我参加聚会有点晚了,但这是解释。 select()
基本上几乎总是对要过滤的顶点或边集执行线性扫描,不幸的是,select()
代码中没有优化的路径可以处理您的情况。也不能保证对参数求值的顺序,因此select()
首先是线性扫描网络以查找源节点的所有边,然后在选择中找到所有具有所需关系的边,或者更糟糕的是,它首先找到具有给定关系的所有边,然后选择源自所需源的边。
手工编写的代码更快的原因是,.find()
在name属性上使用内部索引(name
是igraph中的特殊属性,始终在哈希表中进行索引),在O()中找到所需的节点( 1)摊销时间,然后从那里很容易获得入射边缘。
理想情况下,select()
应该认识到这是完成您想要的事情的一种更快的方法。更准确地说,如果select() is operating on
g.es (and not some pre-filtered subset of
g.es ), there are no positional arguments, _and_
_source is somewhere among the keyword arguments, it should realize that it can use
find()`可以比默认情况更快地找到合适的边集。不幸的是,我还没有时间进一步开发igraph,因此这个特殊问题已经存在了一段时间。
好消息是igraph和python-igraph的开发再次获得动力,因此我希望在接下来的几天中解决此问题,然后在将近五年后适当发布python-igraph 0.8。
关于python - IGraph选择性能,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56638240/