我创建了一个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/

10-12 23:05