我正在尝试在我的算法中编写一个嵌套循环,并且由于这些嵌套循环而遇到整个算法花费太长时间的一些问题。我对Python很新(正如你可能从我的下面的非专业代码中找到的那样:()希望有人可以指导我加速我的代码!
整个算法用于多个1500 * 6400阵列的火灾探测。在遍历整个阵列时应用小的上下文分析。上下文分析以动态分配的窗口大小方式执行。窗口大小可以从11 * 11到31 * 31,直到采样窗口内的验证值足以进行下一轮计算,例如如下所示:
def ContextualWindows (arrb4,arrb5,pfire):
####arrb4,arrb5,pfire are 31*31 sampling windows from large 1500*6400 numpy array
i=5
while i in range (5,16):
arrb4back=arrb4[15-i:16+i,15-i:16+i]
## only output the array data when it is 'large' enough
## to have enough good quality data to do calculation
if np.ma.count(arrb4back)>=min(10,0.25*i*i):
arrb5back=arrb5[15-i:16+i,15-i:16+i]
pfireback=pfire[15-i:16+i,15-i:16+i]
canfire=0
i=20
else:
i=i+1
###unknown pixel: background condition could not be characterized
if i!=20:
canfire=1
arrb5back=arrb5
pfireback=pfire
arrb4back=arrb4
return (arrb4back,arrb5back,pfireback,canfire)
然后,这个动态窗口将被输入下一轮测试,例如:
b4backave=np.mean(arrb4Windows)
b4backdev=np.std(arrb4Windows)
if b4>b4backave+3.5*b4backdev:
firetest=True
要将整个代码运行到我的多个1500 * 6400 numpy阵列,它花了半个多小时甚至更长时间。只是想知道是否有人知道如何处理它?我应该付出努力的一般性想法会非常有用!
非常感谢!
答案 0 :(得分:1)
如果速度是一个问题,请避免while
循环。循环适用于for
循环,因为开始和结束是固定的。此外,您的代码进行了大量复制,这并非真正必要。重写的功能:
def ContextualWindows (arrb4,arrb5,pfire):
''' arrb4,arrb5,pfire are 31*31 sampling windows from
large 1500*6400 numpy array '''
for i in range (5, 16):
lo = 15 - i # 10..0
hi = 16 + i # 21..31
# only output the array data when it is 'large' enough
# to have enough good quality data to do calculation
if np.ma.count(arrb4[lo:hi, lo:hi]) >= min(10, 0.25*i*i):
return (arrb4[lo:hi, lo:hi], arrb5[lo:hi, lo:hi], pfire[lo:hi, lo:hi], 0)
else: # unknown pixel: background condition could not be characterized
return (arrb4, arrb5, pfire, 1)
为了清楚起见,我使用了PEP 8的样式指南(如扩展注释,注释字符数,运算符周围的空格等)。复制窗口arrb4
在此处出现两次,但仅在条件满足时才会发生,并且每次函数调用只会发生一次。 else
子句只有在for
- 循环已经结束时才会执行。当我们完全退出函数时,我们甚至不需要循环break
如果这样可以加快代码的速度,请告诉我们。我认为它不会很多,但不管怎样我都没有多少代码。
答案 1 :(得分:0)
我使用ContextualWindows
和变体进行了一些时间测试。一个i
步骤大约需要50us,全部大约需要500个。
这个简单的迭代需要大约相同的时间:
[np.ma.count(arrb4[15-i:16+i,15-i:16+i]) for i in range(5,16)]
迭代机制,以及'复制'数组是时间的一小部分。在可能的情况下numpy
正在制作观点,而非副本。
我专注于尽量减少这些count
步骤的数量,或加快count
。
比较这些窗口上各种操作的时间:
第一次进行一步:
In [167]: timeit [np.ma.count(arrb4[15-i:16+i,15-i:16+i]) for i in range(5,6)]
10000 loops, best of 3: 43.9 us per loop
现在进行10个步骤:
In [139]: timeit [arrb4[15-i:16+i,15-i:16+i].shape for i in range(5,16)]
10000 loops, best of 3: 33.7 us per loop
In [140]: timeit [np.sum(arrb4[15-i:16+i,15-i:16+i]>500) for i in range(5,16)]
1000 loops, best of 3: 390 us per loop
In [141]: timeit [np.ma.count(arrb4[15-i:16+i,15-i:16+i]) for i in range(5,16)]
1000 loops, best of 3: 464 us per loop
简单的索引不需要花费太多时间,但对条件的测试需要更多时间。
cumsum
有时用于加速滑动窗口的总和。您不是在每个窗口上取和(或平均值),而是计算cumsum
,然后使用窗口前端和末端之间的差异。
尝试类似的东西,但在2d - 两个维度的cumsum中,然后是对角线对角线之间的差异:
In [164]: %%timeit
.....: cA4=np.cumsum(np.cumsum(arrb4,0),1)
.....: [cA4[15-i,15-i]-cA4[15+i,15+i] for i in range(5,16)]
.....:
10000 loops, best of 3: 43.1 us per loop
这几乎比(几乎)等效sum
快10倍。价值观并不完全匹配,但时间表明这可能值得提炼。