在Numpy中使用更具Python风格的迭代方式

在Numpy中使用更具Python风格的迭代方式,python,numpy,iterator,scientific-computing,Python,Numpy,Iterator,Scientific Computing,我是一名工科学生,我习惯于用Fortran编写代码,但现在我正在尝试更多地了解Python,以便使用Numpy编写数值公式 如果我需要使用多个数组中的元素重复执行一个计算,那么我用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

我是一名工科学生,我习惯于用Fortran编写代码,但现在我正在尝试更多地了解Python,以便使用Numpy编写数值公式

如果我需要使用多个数组中的元素重复执行一个计算,那么我用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
但我想知道这种方式是否更像蟒蛇,或者在任何方面更可取:

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]
由于enumerate,我有了索引,否则如果我不需要它,我可以只使用zip或itertools.izip


有什么想法吗?代码在性能方面如何受到影响?还有其他方法可以做到这一点吗?

我喜欢列表理解

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=数组([x**y代表x,y在zip中(一些数组,一些其他数组)])

几乎所有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
大小相同的新数组,其中
r\u移位[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:][/code>来定义。注
r[:-1]
r[1://code>是
r
的切片,形状相同。 在这种情况下,您不需要任何额外的内存,因为
r
的基本片是
r
的所谓视图,而不是副本


在上面的例子中,我没有这样定义
k
,因为
k
的长度应该是
N-1
,而不是
N
,因此,它与原始代码产生的结果略有不同。

事实是,并非总是能够为所需的计算编写公式:可能涉及到更复杂的操作,或者可能将数组初始化为零,并使用一些外部值执行连续的方法。例如,当试图解决一个ODE时就是这样。无论如何,谢谢你的np.roll()提示!的确如果没有numpy基函数或表达式来避免Python循环,那么您可能希望尝试在中重写循环(另请参见“使用Cython进行快速数值计算”)。还有,它允许您从Python调用Fortran函数。那你就不必翻译你的代码了,我已经知道f2py,我想用Python写我的代码;但是Cython也是一个好主意,它从双方都受益。事实是,使用这种方法,您无法恢复以前的元素,例如(这就是为什么我使用enumerate,如图所示)非常正确。当我对序列进行复杂的操作时,我有时会编写一个独立的函数生成器来显式地生成结果。如果需要,我的调用代码可以将其打包到numpy数组中。-1,因为numpy中首选的方式是元素操作。见联合国大学的答复
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])