我以两种方式实现了循环迭代功能:
def Spin1(n, N) : # n - current state, N - highest state
value = n + 1
case1 = (value > N)
case2 = (value <= N)
return case1 * 0 + case2 * value
def Spin2(n, N) :
value = n + 1
if value > N :
return 0
else : return value
这些函数与返回的结果完全相同。然而,第二个功能不适用于numpy阵列。所以为了测试我运行的第一个函数:
import numpy
AR1 = numpy.zeros((3, 4), dtype = numpy.uint32)
AR1[1,2] = 5
print AR1
print Spin1(AR1,5)
神奇地它起作用,那太好了。所以我看到了我想要的东西:
[[0 0 0 0]
[0 0 5 0]
[0 0 0 0]]
[[1 1 1 1]
[1 1 0 1]
[1 1 1 1]]
现在使用第二个函数print Spin2(AR1,5)
,它失败并出现此错误:
if value > N
ValueError: The truth value of an array with more than one element is ambiguous.
Use a.any() or a.all()
并且很清楚为什么,因为if Array
陈述是非的。所以现在我只使用了第一个变种。但是当我看到这些函数时,我有一种强烈的感觉,即在第一个函数中有更多的数学运算,所以我不会失去希望我可以做一些优化它。
的的问题:
1.是否可以优化函数Spin1
以减少操作或如何在广播模式下使用函数Spin2
(可能不会使我的代码太难看)?额外的问题:使用数组进行操作的最快方法是什么?
2。是否有一些标准的Python函数执行相同的计算(不能隐式地广播)以及如何正确调用它 - &#34;循环增量&#34;大概?
答案 0 :(得分:2)
这有一个numpy函数:np.where:
In [590]: AR1
Out[590]:
array([[0, 0, 0, 0],
[0, 0, 5, 0],
[0, 0, 0, 0]], dtype=uint32)
In [591]: np.where(AR1 >= 5, 0, 1)
Out[591]:
array([[1, 1, 1, 1],
[1, 1, 0, 1],
[1, 1, 1, 1]])
所以,你可以定义:
def Spin1(n, N) :
value = n + 1
return np.where(value > N, 0, value)
NumPy还提供了将普通Python函数转换为ufuncs的方法:
def Spin2(n, N) :
value = n + 1
if value > N :
return 0
else : return value
Spin2 = np.vectorize(Spin2)
这样你现在可以在数组上调用Spin2
:
In [595]: Spin2(AR1, 5)
Out[595]:
array([[1, 1, 1, 1],
[1, 1, 0, 1],
[1, 1, 1, 1]])
然而,np.vectorize主要提供语法糖。仍然为每个数组元素调用Python函数,这使得np.vectorized
ufuncs no faster than equivalent code using Python for-loops。
答案 1 :(得分:1)
你的Spin1
在数组导向语言(例如APL,MATLAB)中遵循一个完善的模式,用于“矢量化”像Spin2
这样的函数。您创建一个或多个布尔值(或0/1数组)来表示数组元素可以采用的各种状态,然后通过乘法和求和来构造输出。
例如,为了避免被零除问题,我使用了:
1/(x+(x==0))
对此的一种变体是使用布尔索引数组来选择应该更改的数组元素。在这种情况下,您希望返回value
,但选定的元素“滚动”。
def Spin3(n, N) : # n - current state, N - highest state
value = n + 1
value[value>N] = 0
return value
在这种情况下,索引方法更简单,并且似乎更适合程序逻辑。它可能更快,但我无法保证。记住这两种方法是很好的。
答案 2 :(得分:0)
我在这里提供了一些反馈作为答案,只是为了不弄乱这个问题。所以我已经对各种函数进行了时序测试,事实证明在这种情况下通过布尔掩码进行分配是最快的变量(hpaulj的答案)。 np.where
慢了1.4倍,np.vectorize(Spin2)
慢了15倍。现在只是出于好奇,我想用循环来测试它,所以我编写了这个算法用于测试:
AR1 = numpy.zeros((rows, cols), dtype = numpy.uint32)
while d <= 100:
Buf = numpy.zeros_like(AR1)
r = 0
c = 0
while (r < rows) :
while (c < cols) :
temp = AR1[r, c] + 1
if temp > 5 :
Buf[r, c] = 1
else : Buf[r, c] = temp
c += 1
r += 1
c = 0
AR1 = Buf
d += 1
我不确定,但似乎是非常简单地实现了上述所有功能。但它太慢了,慢了近300倍。我在SO上读过类似的问题,但我仍然没有得到它,为什么会这样?究竟是什么导致了这种放缓。在这里,我有意构成了一个缓冲区,以避免对相同元素的读写函数,并且不进行内存清理。那么什么可以更简单,我很困惑。不想打开一个新问题,因为它已经被问过几次了,所以可能有人会发表评论或有明确的链接澄清这个问题?