Numpy广播与比较运算符;循环迭代

时间:2014-11-22 02:52:19

标签: python arrays numpy

我以两种方式实现了循环迭代功能:

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;大概?

3 个答案:

答案 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上读过类似的问题,但我仍然没有得到它,为什么会这样?究竟是什么导致了这种放缓。在这里,我有意构成了一个缓冲区,以避免对相同元素的读写函数,并且不进行内存清理。那么什么可以更简单,我很困惑。不想打开一个新问题,因为它已经被问过几次了,所以可能有人会发表评论或有明确的链接澄清这个问题?