NumPy加速2D Array的设置元素

时间:2014-11-25 09:04:57

标签: arrays performance python-2.7 numpy vectorization

我正在尝试在Python中有效地索引2D数组,并且问题是它非常慢。

这就是我尝试过的(简化示例):

xSize = veryBigNumber
ySize = veryBigNumber
a = np.ones((xSize,ySize))
N = veryBigNumber  
const = 1

for t in range(N):

  for i in range(xSize):
    for j in range(ySize):
      a[i,j] *= f(i,j)*const   # f(i,j) is an arbitrary function of i and j. 

现在我想用更高效的东西替换嵌套循环。我该怎么做?

3 个答案:

答案 0 :(得分:6)

您可以使用以下内容生成2D数组:

np.arange(200)[:,np.newaxis] + np.arange(200)

这种矢量化操作可能非常快:

>>> %timeit np.arange(200)[:,np.newaxis] + np.arange(200)
1000 loops, best of 3: 178 µs per loop

not 中的此方法仅限于添加。我们可以在上面的操作中使用两个数组作为任何universal function的参数(通常缩写为 ufunc )。

例如:

>>> np.multiply(np.arange(5)[:,np.newaxis], np.arange(5))
array([[ 0,  0,  0,  0,  0],
       [ 0,  1,  2,  3,  4],
       [ 0,  2,  4,  6,  8],
       [ 0,  3,  6,  9, 12],
       [ 0,  4,  8, 12, 16]])

NumPy为所有基本算术运算构建了ufunc,并且还有一些更有趣的运算。如果您需要更具异国情调的功能,NumPy allows you to make your own ufunc


编辑:快速解释此方法中发生的广播;你能想到这样......

np.arange(5)生成一维数组,如下所示:

array([0, 1, 2, 3, 4])

代码np.arange(5)[:,np.newaxis]在范围中添加第二维(列),生成此2D数组:

array([[0],
       [1],
       [2],
       [3],
       [4]])

使用np.multiply创建最终的5x5数组(尽管我们可以使用任何ufunc或二进制算术运算),NumPy在第二个数组中取0并将其与第一个数组中的每个元素一起删除像这样排:

[ 0,  0,  0,  0,  0]

然后它接受第二个数组中的第二个元素1,并将它与第一个数组相乘,产生这一行:

[ 0,  1,  2,  3,  4]

这一直持续到我们有最终的5x5矩阵。

答案 1 :(得分:5)

您可以使用indices例程:

b=np.indices(a.shape)
a=b[0]+b[1]

<强>时序:

%%timeit
    ...: b=np.indices(a.shape)
    ...: c=b[0]+b[1]
1000 loops, best of 3: 370 µs per loop


%%timeit
for i in range(200):
  for j in range(200):
     a[i,j] = i + j

100 loops, best of 3: 10.4 ms per loop

答案 2 :(得分:1)

由于输出矩阵a是矩阵F的N的元素幂,其元素为f_ij = f(i,j) * const,因此您的代码可以简化为

F = np.empty((xSize, ySize))
for i in range(xSize):
    for j in range(ySize):
        F[i,j] = f(i,j) * const

a = F ** n

为了更快的速度,你可以用更有效的东西来交换F矩阵的创建,因为函数f(i,j)是矢量化的:

xmap, ymap = numpy.meshgrid(range(xSize), range(ySize))
F = f(xmap, ymap) * const