Python 基于多个条件处理numpy阵列的更有效方法是什么?

Python 基于多个条件处理numpy阵列的更有效方法是什么?,python,arrays,multidimensional-array,numpy,convolution,Python,Arrays,Multidimensional Array,Numpy,Convolution,我写过一些代码,在一段时间内(例如15年),ndimage.filters.convolve用于对数组(例如array1)进行卷积,然后当得到的数组(例如array2)高于随机生成的数字时,另一个数组(例如array3)的值为1。一旦为array3分配了一个值1,它每年都会进行计数,当它最终达到某个值(如5)时,array1将在此位置更新 抱歉,这有点让人困惑。实际上,我通过使用numpy使脚本正常工作。其中(布尔表达式,值,值),但当我需要多个表达式时(例如其中array2==1和array3

我写过一些代码,在一段时间内(例如15年),
ndimage.filters.convolve
用于对数组(例如array1)进行卷积,然后当得到的数组(例如array2)高于随机生成的数字时,另一个数组(例如array3)的值为1。一旦为array3分配了一个值1,它每年都会进行计数,当它最终达到某个值(如5)时,array1将在此位置更新

抱歉,这有点让人困惑。实际上,我通过使用
numpy使脚本正常工作。其中(布尔表达式,值,值)
,但当我需要多个表达式时(例如
其中array2==1和array3==0
),我使用for循环来迭代数组中的每个值。在这里的示例中,这非常有效,但是当我将数组替换为较大的数组(完整脚本导入GIS网格并将其转换为数组)时,每年处理这个for循环都需要几分钟的时间。由于我们必须将该模型运行60年1000次,因此我需要找到一种更有效的方法来处理这些阵列

我尝试在numpy.where中使用多个表达式,但无法解决如何使其工作。我还尝试了zip(array)将数组压缩在一起,但我无法更新它们,我想这是因为它创建了数组元素的元组

我已经附上了一份脚本副本,正如前面提到的,它完全按照我的需要工作。然而,它需要更有效地做到这一点。如果有人有任何建议,那就太好了。这是我关于Python的第一篇文章,所以我仍然认为自己是新手。p>
import numpy as np
from scipy import ndimage
import random
from pylab import *

###################### FUNCTIONS ###########################

def convolveArray1(array1, kern1):

    newArray = ndimage.filters.convolve(array1, kern1, mode='constant')

    return newArray


######################## MAIN ##############################

## Set the number of years
nYears = range(1,16)

## Cretae array1
array1 = np.zeros((10,10), dtype=np.int) # vegThreshMask

# Add some values to array1
array1[[4,4],[4,5]] = 8
array1[5,4] = 8
array1[5,5] = 8

## Create kerna; array
kernal = np.ones((3,3), dtype=np.float32)

## Create an empty array to be used as counter
array3 = np.zeros((10,10), dtype=np.int)

## iterate through nYears
for y, yea in enumerate(nYears):

    # Create a random number for the year
    randNum = randint(7, 40)
    print 'The random number for year %i is %i' % (yea, randNum)
    print

    # Call the convolveArray function
    convArray = convolveArray1(array1, kernal)

    # Update array2 where it is greater than the random number    
    array2 = np.where(convArray > randNum, 1, 0)
    print 'Where convArray > randNum in year %i' % (yea)
    print array2
    print 

    # Iterate through array2 
    for a, ar in enumerate(array2):
        for b, arr in enumerate(ar):
            if all(arr == 1 and array3[a][b] == 0):
                array3[a][b] = 1
            else:
                if array3[a][b] > 0:
                    array3[a][b] = array3[a][b] + 1
            if array3[a][b] == 5:
                array1[a][b] = 8

    # Remove the initial array (array1) from the updated array3   
    array3 = np.where(array1 > 0, 0, array3)
    print 'New array3 after %i years' % (yea)
    print '(Excluding initial array)'
    print array3
    print    

print 'The final output of the initial array'
print array1

听起来好像您试图在
np中使用多个条件。其中
使用了
array1>0和array2<0等表达式。这不起作用,因为正如所记录的那样,Python中的布尔操作是这样工作的。首先计算
array1>0
,然后使用
\uuuuuu非零
方法将其转换为布尔值(在Python 3中重命名为
\uuuuu bool\uuuuu
)。没有一种将数组转换为布尔值的唯一有用的方法,目前也没有方法覆盖布尔运算符的行为(尽管我相信这将在将来的版本中讨论),因此在numpy中,
ndarray.\uuuuu非零\uuuuuuu
被定义为引发异常。相反,您可以使用
np.logical\u和
np.logical\u或
,以及
np.logical\u不
,它们具有您期望的行为


不过,我不知道这会给你带来多大的加速。如果您最终在循环中执行了大量数组索引操作,那么可能值得研究一下,通过将数组操作移动到C扩展中,您可以轻松地加快数组操作的速度。

我怀疑如果您开始使用广播,您可能会获得相当大的加速。例如,从您的行开始迭代array2
,我们可以删除显式循环,只需广播我们想要更改的变量。注意:为了清晰起见,我使用的是
AX
而不是
arrayX

# Iterate through A2

idx  = (A2==1) & (A3==0)
idx2 = (~idx)  & (A3>0)
A3[idx ]  = 1
A3[idx2] += 1
A1[A3==5] = 8
此外,一旦您习惯了这种风格,这将大大提高代码的清晰度,因为您没有明确地处理索引(这里是
a
b

值得这么麻烦吗? 在尝试上述代码后,我要求OP进行速度测试:

如果您确实实现了循环更改,请让我知道您的真实代码的速度。 了解给出的建议是否只是美化了语法,或者是否有显著的效果是很有用的


经过测试,响应速度大大提高了40倍!在处理执行简单掩码的大型连续数据数组时,
numpy
是比本机python列表更好的选择。

这非常有效!我做了两次测试,比较了它和我原来的速度,这花了18秒,而不是超过12分钟!所以它肯定有显著的效果。谢谢(看起来也好多了)@TravisMoon太好了!我非常感谢您发布结果,当人们询问
numpy
是否值得为基本数组操作而费心时,我会在这里指导他们。我期望加速,但没有达到40倍!感谢您澄清python是如何处理布尔表达式的,我工作中的其他人也提到了np.logical_以及用于numpy数组。对于这份工作,我使用了上面给出的答案,但如果我在某个阶段有机会,我也会试试看哪个更快。我不确定我在工作中使用的电脑是否有cpython,但我可能仍会研究它。非常感谢。