С 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
clip
в бункер на 2147483647
значения, возвращаемые gt.shortest_distance
на последней позиции hist
. Без использования clip
, hist's
size
должно быть 2147483647 + 1
на 64-битном Python, или bincount
создаст ValueError
на 32-битном Python. Таким образом, последняя позиция hist
будет содержать количество всех непустых; вы можете игнорировать это значение в анализе гистограммы.
Как ниже тайминги указывают, используя numpy
математику, чтобы получить гистограмму хорошо более чем на порядок величины быстрее, чем при использовании либо defaultdicts
или counters
(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))
Если между двумя вершинами нет пути, код возвращает мне длину пути '2147483647'. Я должен удалить их, поскольку это в противном случае взорвало бы мои средние значения. Вы уверены, что последняя модификация будет работать? Мне кажется, что код не будет знать, что такое 'a', так как мы еще не назначили переменную, или я не понимаю, что такое numpy? (Мои знания о 'numpy' очень ограничены. –
Это может быть понимание Python, а не numpy. Я буду расширять то, что я сделал в ответ. –
отредактировал ответ на обработку' [a! = 2147483647] 'в качестве комментария –