我需要从权重矩阵的值开始创建矩阵。在创建和迭代时,哪个是在速度方面保持矩阵的最佳结构?我正在考虑一个列表列表或一个numpy 2D数组,但它们对我来说似乎都很慢。 我需要的是:
numpy array
A = np.zeros((dim, dim))
for r in range(A.shape[0]):
for c in range(A.shape[0]):
if(r==c):
A.itemset(node_degree[r])
else:
A.itemset(arc_weight[r,c])
或
list of lists
l = []
for r in range(dim):
l.append([])
for c in range(dim):
if(i==j):
l[i].append(node_degree[r])
else:
l[i].append(arc_weight[r,c])
其中dim也可以是20000,node_degree是向量而arc_weight是另一个矩阵。我用c ++编写它,它花费的时间不到0.5秒,而其他两个在python中的时间超过20秒。我知道python不是c ++,但我需要尽可能快。 谢谢大家。
答案 0 :(得分:2)
如果你已经知道它的大小,那么你不应该追加到列表中。
首先使用列表推导来预先分配内存,并使用r, c
而不是xrange()
生成range()
值,因为您使用的是Python< 3.x(见here):
l = [[0 for c in xrange(dim)] for r in xrange(dim)]
更好的是,您可以使用以下方式一次性构建所需内容:
l = [[node_degree[r] if r == c else arc_weight[r,c]
for c in xrange(dim)] for r in xrange(dim)]
与原始实现相比,这应该使用更少的内存(因为xrange()
生成器)和更少的时间,因为您通过预先指定维度来消除重新分配内存的需要。
答案 1 :(得分:0)
Numpy矩阵通常更快,因为他们知道它们的尺寸和入口类型。
在您的特定情况下,由于您已经创建了arc_weight和node_degree矩阵,因此您可以直接从arc_weight创建矩阵,然后替换对角线:
A = np.matrix(arc_matrix)
np.fill_diagonal(A, node_degree)
另一个选择是用一个函数替换double循环,该函数将右元素放在每个位置并从函数创建一个矩阵:
def fill_matrix(r, c):
return arc_weight[r,c] if r != c else node_degree[r]
A = np.fromfunction(fill_matrix, (dim, dim))
根据经验,numpy必须不惜一切代价避免循环。第一种方法应该更快,但你应该分析两者,看看哪些方法适合你。您还应该考虑到您似乎在内存中复制了数据集,因此如果它真的很大,您可能会遇到麻烦。最好的想法是直接创建矩阵,完全避免使用arc_weight和node_degree。
编辑:列表理解和numpy矩阵创建之间的一些简单时间比较。由于我不知道你的arc_weight和node_degree是如何定义的,所以我只编写了两个随机函数。如果函数有条件,numpy.fromfunction
似乎有点抱怨,所以我分两步构造矩阵。
import numpy as np
def arc_weight(a,b):
return a+b
def node_degree(a):
return a*a
def create_as_list(N):
return [[arc_weight(c,r) if c!=r else node_degree(c) for c in xrange(N)] for r in xrange(N)]
def create_as_numpy(N):
A = np.fromfunction(arc_weight, (N,N))
np.fill_diagonal(A, node_degree(np.arange(N)))
return A
此处N=2000
的时间安排:
time A = create_as_list(2000)
CPU times: user 839 ms, sys: 16.5 ms, total: 856 ms
Wall time: 845 ms
time A = create_as_numpy(2000)
CPU times: user 83.1 ms, sys: 12.9 ms, total: 96 ms
Wall time: 95.3 ms
答案 2 :(得分:0)
复制arc_weight
并使用node_degree
的值填充对角线。对于20000×20000输出,我的机器需要大约1.6秒:
>>> import numpy
>>> dim = 20000
>>> arc_weight = numpy.arange(dim**2).reshape([dim, dim])
>>> node_degree = numpy.arange(dim)
>>> import timeit
>>> timeit.timeit('''
... A = arc_weight.copy()
... A.flat[::dim+1] = node_degree
... ''', '''
... from __main__ import dim, arc_weight, node_degree''',
... number=1)
1.6081738501125764
一旦你有了你的阵列,尽量不要迭代它。与广播运算符和NumPy内置函数相比,Python级循环是一种性能灾难。