1

我需要从权重矩阵的值开始创建一个矩阵。在创建和迭代矩阵时,在速度方面保持矩阵的最佳结构是什么?我正在考虑一个列表列表或一个 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++,但我需要尽可能快。谢谢你们。

4

3 回答 3

4

一件事是,如果您已经知道列表的大小,则不应将其附加到列表中。

首先使用列表推导预分配内存并使用而不是生成r, c值,因为您使用的是 Python < 3.x(请参见此处):xrange()range()

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()生成器)和更少的时间,因为您无需通过预先指定尺寸来重新分配内存。

于 2014-05-29T17:47:05.187 回答
0

复制arc_weight并用 中的值填充对角线node_degree。对于 20000 x 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 级循环是性能灾难。

于 2014-05-31T09:31:36.377 回答
0

Numpy 矩阵通常更快,因为它们知道它们的维度和条目类型。

在您的特定情况下,由于您已经创建了 arc_weight 和 node_degree 矩阵,因此您可以直接从 arc_weight 创建矩阵,然后替换对角线:

A = np.matrix(arc_matrix)
np.fill_diagonal(A, node_degree)

另一种选择是用一个函数替换双循环,该函数将正确的元素放在每个位置并从该函数创建一个矩阵:

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
于 2014-05-29T18:10:11.007 回答