更多pythonic方式迭代Numpy

时间:2011-12-26 10:25:25

标签: python numpy iterator scientific-computing

我是一名工科学生,我习惯于在Fortran中编写代码,但现在我正在尝试使用Numpy为Python编写更多的数据。

如果我需要使用来自多个数组的元素重复执行计算,那么我在Fortran中编写的内容的直接翻译将是

k = np.zeros(N, dtype=np.float)
u = ...
M = ...
r = ...
for i in xrange(N):
  k[i] = ... # Something with u[i], M[i], r[i] and r[i - 1], for example

但是我想知道这种方式是否更具有pythonic,或者更喜欢以任何方式:

for i, (k_i, u_i, M_i, r_i) in enumerate(zip(k, u, M, r)):
  k_i = ... # Something with u_i, M_i, r_i and r[i - 1]

感谢枚举我有索引,否则如果我不需要它,我可以使用zip或者itertools.izip。

有什么想法吗?代码如何在性能方面受到影响?有没有其他方法可以实现这个目标?

2 个答案:

答案 0 :(得分:7)

几乎所有的numpy操作都是按元素执行的。因此,不要编写显式循环,而是尝试使用基于数组的公式定义k

r_shifted = np.roll(x, shift = 1)
k = ... # some formula in terms of u, M, r, r_shifted

例如,而不是

import numpy as np

N=5
k = np.zeros(N, dtype=np.float)
u = np.ones(N, dtype=np.float)
M = np.ones(N, dtype=np.float)
r = np.ones(N, dtype=np.float)
for i in xrange(N):
  k[i] = u[i] + M[i] + r[i] + r[i-1]
print(k)  
# [ 4.  4.  4.  4.  4.]

使用:

r_shifted = np.roll(r, shift = 1)
k = u + M + r + r_shifted
print(k)
# [ 4.  4.  4.  4.  4.]

np.roll(r, shift = 1)会返回与r大小相同的新数组,r_shifted[i] = r[i-1]会返回i = 0, ..., N-1

In [31]: x = np.arange(5)

In [32]: x
Out[32]: array([0, 1, 2, 3, 4])

In [33]: np.roll(x, shift = 1)
Out[33]: array([4, 0, 1, 2, 3])

制作这样的副本需要更多内存(与r大小相同),但允许您执行快速numpy操作,而不是使用慢速Python循环。


有时,k的公式可以用r[:-1]r[1:]来定义。注意r[:-1]r[1:]r的切片,形状相同。 在这种情况下,您不需要任何额外的内存,因为r的基本切片是r的所谓视图,而不是副本。

我没有在上面的示例中以这种方式定义k因为k的长度为N-1而不是N,所以它本来就是与原始代码产生的略有不同。

答案 1 :(得分:-1)

我喜欢列表推导

k = [ x ** y for x, y in zip(some_array, some_other_array) ]

其他人如map

map( lambda x, y : x*y , zip(some_array, some_other_array) )

将乘以两个数组并返回一个列表或生成器。 (当然,还有其他方法可以在numpy中执行该特定任务。)如果要将其转换回数组,则可以执行

k = array([x ** y代表x,y代表zip(some_array,some_other_array)])