簡體   English   中英

迭代計算列表中的元素並將其存儲在字典中

[英]Iteratively count elements in list and store count in dictionary

我有一段代碼循環通過一組節點,並計算將給定節點連接到網絡中每個其他節點的路徑長度。 對於每個節點,我的代碼都會向我返回一個列表, 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

就字典更新而言,這大概是非常粗糙的編碼。 有更好的方法嗎? 創建此直方圖的最有效方法是什么?

確實不需要檢查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

您可以將最后兩行變成這樣,但實際上沒有意義。

由於gt.shortest_distance返回ndarray ,因此numpy數學運算最快:

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方法clipndarray返回的2147483647gt.shortest_distancehist的最后一個位置。 如果不使用clip ,則在64位Python上hist's size必須為2147483647 + 1 ,否則bincount在32位Python上會產生ValueError 因此hist的最后一個位置將包含所有非路徑的計數; 您可以在直方圖分析中忽略此值。


如下所示,使用numpy數學獲取直方圖比使用defaultdictscounters (Python 3.4)快一個數量級:

# 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

我的計算機太慢了,無法測試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))

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)

我認為您可以完全繞過此代碼。 您的問題用標記。 看看他們的文檔的這一部分: graph_tool.stats.vertex_hist

摘自鏈接文檔:

graph_tool.stats.vertex_hist(g,deg,bins = [0,1],float_count = True)
返回給定度數類型或屬性的頂點直方圖。

參數:
g:圖形所使用的圖形。
deg:字符串或PropertyMap
用於直方圖的度數或屬性。 它可以是“ in”,“ out”或“ total”,對於in-,
頂點的總度數。 它也可以是頂點屬性圖。
bins:bin列表(可選,默認值:[0,1])
直方圖要使用的bin列表。 給定的值代表垃圾箱的邊緣
(即上下限)。 如果列表中包含兩個值,它將被用於自動
創建一個適當的bin范圍,其寬度由第二個值給定,然后開始
從第一個值開始。
float_count:bool(可選,默認:True)
如果為True,則每個直方圖bin中的計數將以浮點數形式返回。 如果為False,它們將是
以整數形式返回。

返回:計數:ndarray
垃圾箱計數。
箱:ndarray
垃圾箱邊緣。

這將返回像ndarray的直方圖一樣分組的邊緣。 然后,您只需獲取ndarray列的長度即可獲取計數以生成直方圖。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM