避免在np.array操作中使用for循环。蟒蛇

时间:2015-11-03 16:12:26

标签: python arrays for-loop numpy

我有这两个数组:

import numpy as np
a = np.array([0, 10, 20])
b = np.array([20, 30, 40, 50])  

我想以下列方式添加两者:

for i in range (len(a)):
   for j in range(len(b)):
      c = a[i] + b[j]
      d = delta(c, dr)

正如您在每次迭代中看到的那样,我得到一个值c,我通过函数delta(请参阅帖子末尾的注释)。 问题是,当阵列很大时,我想避免缓慢的Python“for”循环。

我能做的一件事是:

c = np.ravel(a(-1, 1) + b)

哪个更快。问题是现在c是一个数组,我不得不再使用for循环抛出它。 所以,你对我如何在不使用for循环的情况下做到这一点有任何想法。

注意:delta是我通过以下方式定义的函数:

def delta(r,dr):
   if r >= 0.5*dr and r <= 1.5*dr:
     delta = (5-3*abs(r)/dr-np.sqrt(-3*(1-abs(r)/dr)**2+1))/(6*dr)
   elif r <= 0.5*dr:
     delta = (1+np.sqrt(-3*(r/dr)**2+1))/(3*dr)
   else:
     delta = 0
   return delta

3 个答案:

答案 0 :(得分:3)

使用ravel是一个好主意。请注意,您还可以使用简单的array broadcastinga[:, np.newaxis] + b[np.newaxis, :])。

对于您的function,您可以对此进行大量改进,因为它仅由三个特定情况组成。可能最好的方法是对这三个部分中的每个部分使用掩蔽。

您从以下开始:

def delta(r,dr):
   if r >= 0.5*dr and r <= 1.5*dr:
     delta = (5-3*abs(r)/dr-np.sqrt(-3*(1-abs(r)/dr)**2+1))/(6*dr)
   elif r <= 0.5*dr:
     delta = (1+np.sqrt(-3*(r/dr)**2+1))/(3*dr)
   else:
     delta = 0

一种常见的替代方法是:

def delta(r, dr):
    res = np.zeros_like(r)
    ma = (r >= 0.5*dr) & (r <= 1.5*dr)  # Create first mask
    res[ma] = (5-3*np.abs(r[ma])/dr[ma]-np.sqrt(-3*(1-np.abs(r[ma])/dr[ma])**2+1))/(6*dr[ma])
    ma = (r <= 0.5*dr)    # Create second mask
    res[ma] = (1+np.sqrt(-3*(r[ma]/dr[ma])**2+1))/(3*dr[ma])
    return res

初始化为零会处理最终else个案。我还假设np.absabs更快---但我确实不确定......

编辑 稀疏矩阵

应该应用相同的基本思想,但也许不使用布尔掩蔽数组,使用有效索引本身会更好......例如类似的东西:

res = scipy.sparse.coo_matrix(np.shape(r))
ma = np.where((r >= 0.5*dr) & (r <= 1.5*dr))  # Create first mask
res[ma] = ...

答案 1 :(得分:0)

这与DilithiumMatrix的答案相同,但使用numpy接受的逻辑函数来生成蒙版。

import numpy as np
def delta(r, dr):
    res = np.zeros(r.shape)
    mask1 = (r >= 0.5*dr) & (r <= 1.5*dr)
    res[mask1] = \
        (5-3*np.abs(r[mask1])/dr \
        - np.sqrt(-3*(1-np.abs(r[mask1])/dr)**2+1)) \
         /(6*dr)
    mask2 = np.logical_not(mask1) & (r <= 0.5*dr)
    res[mask2] = (1+np.sqrt(-3*(r[mask2]/dr)**2+1))/(3*dr)
    return res

答案 2 :(得分:-1)

假设你的两个数组(a和b)不是很大,你可以这样做:

import itertools
a = numpy.array([1,2,3])
b = numpy.array([4,5,6])
c = numpy.sum(list(itertools.product(a, b), 1)
def func(x, y):
    return x*y
numpy.vectorize(func)(c, 10)

请注意,对于大型数组,这根本不起作用 - n**2中有c个元素,这意味着即使对于看似很小的数组,也会使用巨大的数组记忆量。对于每个100,000个元素的2个阵列,所需的总内存将在74 GB范围内。