迭代计算列表中的元素并在字典中存储计数

时间:2016-09-01 16:14:10

标签: python performance list dictionary graph-tool

我有一段代码循环遍历一组节点,并计算将给定节点连接到网络中每个其他节点的路径长度。对于每个节点,我的代码返回一个列表,b包含整数值,为每个可能的连接提供路径长度。我想计算给定路径长度的出现次数,这样我就可以创建一个直方图。

local_path_length_hist = {}
for ver in vertices:
    dist = gt.shortest_distance(g, source=g.vertex(ver))
    a = dist.a
    #Delete some erroneous entries
    b = a[a!=2147483647]
    for dist in b:
        if dist in local_path_length_hist:
            local_path_length_hist[dist]+=1
        else:
            local_path_length_hist[dist]=1

就字典更新而言,这可能是非常粗略的编码。有没有更好的方法呢?创建此直方图的最有效方法是什么?

4 个答案:

答案 0 :(得分:1)

检查dict中元素是否存在并不是必需的。您可以使用collections.defaultdict。它的初始化接受可调用对象(如函数),如果你想访问(或指定某些东西)不存在的元素来生成值(即生成默认值的函数),它将被调用。对于您的情况,它可以只是int。即。

import collections
local_path_length_hist = collections.defaultdict(int)
# you could say collections.defaultdict(lambda : 0) instead
for ver in vertices:
    dist = gt.shortest_distance(g, source=g.vertex(ver))
    a = dist.a
    #Delete some erroneous entries
    b = a[a!=2147483647]
    for dist in b:
        local_path_length_hist[dist] += 1

你可以把最后两行改成一个,但实际上没有意义。

答案 1 :(得分:1)

由于gt.shortest_distance返回ndarraynumpy数学最快:

max_dist = len(vertices) - 1
hist_length = max_dist + 2
no_path_dist = max_dist + 1
hist = np.zeros(hist_length) 
for ver in vertices:
    dist = gt.shortest_distance(g, source=g.vertex(ver))
    hist += np.bincount(dist.a.clip(max=no_path_dist))

我使用ndarray方法clip2147483647gt.shortest_distance的最后一个位置hist返回的值clip。不使用hist'ssize 2147483647 + 1必须在64位Python上bincount,或ValueError在{32}上产生hist -bit Python。所以numpy的最后一个位置将包含所有非路径的计数;你可以在直方图分析中忽略这个值。

如下面的时序所示,使用defaultdicts数学来获得直方图比使用counters# vertices numpy defaultdict counter 9000 0.83639 38.48990 33.56569 25000 8.57003 314.24265 262.76025 50000 26.46427 1303.50843 1111.93898 (Python 3.4)快一个数量级:

9 * (10**6)

我的计算机太慢而无法使用from collections import defaultdict, Counter import numpy as np from random import randint, choice from timeit import repeat # construct distance ndarray such that: # a) 1/3 of values represent no path # b) 2/3 of values are a random integer value [0, (num_vertices - 1)] num_vertices = 50000 no_path_length = 2147483647 distances = [] for _ in range(num_vertices): rand_dist = randint(0,(num_vertices-1)) distances.append(choice((no_path_length, rand_dist, rand_dist))) dist_a = np.array(distances) def use_numpy_math(): max_dist = num_vertices - 1 hist_length = max_dist + 2 no_path_dist = max_dist + 1 hist = np.zeros(hist_length, dtype=np.int) for _ in range(num_vertices): hist += np.bincount(dist_a.clip(max=no_path_dist)) def use_default_dict(): d = defaultdict(int) for _ in range(num_vertices): for dist in dist_a: d[dist] += 1 def use_counter(): hist = Counter() for _ in range(num_vertices): hist.update(dist_a) t1 = min(repeat(stmt='use_numpy_math()', setup='from __main__ import use_numpy_math', repeat=3, number=1)) t2 = min(repeat(stmt='use_default_dict()', setup='from __main__ import use_default_dict', repeat= 3, number=1)) t3 = min(repeat(stmt='use_counter()', setup='from __main__ import use_counter', repeat= 3, number=1)) print('%0.5f, %0.5f. %0.5f' % (t1, t2, t3)) 个顶点进行测试,但相对时序对于不同数量的顶点看起来非常一致(正如我们所期望的那样)。

计时代码

Array
(
    [0] => 15/09/2016 00:00
    [1] => 02/09/2016 00:00
    [2] => 01/09/2016 00:00
    [3] => 29/09/2016 00:00
)

答案 2 :(得分:1)

collections模块中有一个名为Counter的实用程序。这比使用defaultdict(int)

更清晰
from collections import Counter
hist = Counter()
for ver in vertices:
    dist = gt.shortest_distance(g, source=g.vertex(ver))
    a = dist.a
    #Delete some erroneous entries
    b = a[a!=2147483647]
    hist.update(b)

答案 3 :(得分:0)

我认为你可以完全绕过这段代码。您的问题标有。请查看他们文档的这一部分:graph_tool.stats.vertex_hist

摘录链接文档:

  

graph_tool.stats.vertex_hist(g,deg,bins = [0,1],float_count = True)
  返回给定度数类型或属性的顶点直方图。

     

参数:
  g:图表   要使用的图表。
  deg:string或PropertyMap
  用于直方图的程度或属性。对于in-,
,它可以是“in”,“out”或“total”   out-或顶点的总程度。它也可以是顶点属性图   箱柜:箱柜列表(可选,默认:[0,1])
  用于直方图的箱的列表。给出的值代表箱的边缘
  (即下限和上限)。如果列表包含两个值,则将用于自动
  创建一个合适的bin范围,具有由第二个值给出的恒定宽度,并开始
  从第一个值。
  float_count:bool(可选,默认值:True)
  如果为True,则每个直方图bin中的计数将作为浮点数返回。如果为假,他们将是
  以整数形式返回。

     

返回:   计数:ndarray
  垃圾箱数量   箱子:ndarray
  箱边缘。

这将返回像ndarray中的直方图一样分组的边。然后,您可以获取ndarray列的长度以获取计数以生成直方图。