【发布时间】:2020-07-11 15:26:53
【问题描述】:
我正在处理相对较大的数据集(超过 100,000 个元素),需要为这些数据集创建邻接矩阵。
我已经编写了一个非常基本的 for 循环,可以为给定的连接节点 (nx2) 完成此操作
nodes = np.random.randint(20000, size=(20000, 2))
def adjMat(node_list):
n = np.max(node_list)
A = np.zeros((n, n))
for tail, head in node_list:
A[tail-1, head-1] = 1
return A
这很好用,并没有我想象的那么慢,但假设我可以通过使用 numba 来实现这个超级简单的功能,从而显着提高性能。
所以我添加了两个 jitted 函数(一个使用并行)来查看性能差异。我还刚刚包含了 networkx,看看它是否得到了很好的优化。
@njit()
def adjMat_numba(node_list):
n = np.max(node_list)
A = np.zeros((n, n))
for tail, head in node_list:
A[tail-1, head-1] = 1
return A
@njit(parallel = True)
def adjMat_numba_para(node_list):
n = np.max(node_list)
A = np.zeros((n, n))
for tail, head in node_list:
A[tail-1, head-1] = 1
return A
def getAdjacenyList(node_list):
G = nx.Graph([e for e in node_list])
A = nx.convert.to_dict_of_lists(G)
return A
这是我在 20000 对连接节点上测试的输出:
%timeit a = adjMat(nodes)
112 ms ± 3.7 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit b = adjMat_numba(nodes)
1.34 s ± 41.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit c = adjMat_numba_para(nodes)
251 ms ± 3.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit d = getAdjacenyList(nodes)
149 ms ± 3.31 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
令我惊讶的是,使用 numba 实际上会使函数慢几倍,而且即使在并行模式下,它仍然不如 for 循环快。 Numba 似乎也比 for 循环使用更多的内存。另外,我很惊讶 networkx 比 for 循环慢 - 我原以为唯一目的是处理这类问题的库会更快。
我的 numba 装饰器有什么问题吗?有没有更好的选择来快速有效地创建邻接矩阵?
我正在使用 pycharm 在 12 核 linux 桌面上运行这些测试。
【问题讨论】:
-
numba需要时间来初始化和编译,运行这些函数两次并检查每个函数的第二次运行时间。如果它只运行一次,那么没有它可能会更好。
标签: python numpy numba adjacency-matrix