如何摆脱Python代码中的嵌套for循环?

时间:2018-06-20 19:10:07

标签: python loops numpy for-loop parallel-processing

我对卫星进行了1年的卫星测量(仪器每4秒测量一次)。该阵列称为“电子”。我也有格式为datetime.datetime的相应时间(称为“时间”)。我想对电子阵列进行平均,以获得每分钟而不是每4秒的平均值。我想将它们放在新的数组“ g”中。但是,当我编写循环时,它变得非常慢。有什么方法可以使其更快?这是我的工作:

import numpy as np
import spacepy.time as spt
import datetime as dt

year=2001
for month in range (1,13):
        dmax=np.array([[31,28,31,30,31,30,31,31,30,31,30,31]]).T #number of days in a month
        for day in range(1,dmax[month-1]+1):
            for hour in range(24):
                for minute in range(60):

                D1=spt.Ticktock(dt.datetime(year, month, day, hour, minute, 0,0),'UTC').RDT #lower boundary of a minute

#here, spt is a spacepy.time, and '.RDT' returns GREGORIAN ORDINAL TIME.

                D2=spt.Ticktock(dt.datetime(year, month, day, hour, minute, 59,999999),'UTC').RDT #upper boundary of a minute

                mask=((time>D1)&(time<D2))

                electrons_logic=electrons[mask]
                k=(month-1)*dmax[month-1]*24*60+(day-1)*24*60+hour*60+(minute+1) #number of the minute in a year
                g[k,0]=np.nanmean(electrons_logic)

有没有办法避免嵌套循环并使之更快?

也许有一种方法可以使用多处理/并行计算来使其更快?

4 个答案:

答案 0 :(得分:2)

只要您对迭代有疑问,请考虑一下itertools

from itertools import product

dmax=np.array([[31,28,31,30,31,30,31,31,30,31,30,31]]).T
for month in range (1,13):
    for day, hour, minute in product(range(1,dmax[month-1]+1), range(24), range(60)):
        ...

我还建议在循环之外定义dmax,否则将在每次month迭代时实例化它。

答案 1 :(得分:1)

(至少对于3个内部循环而言)替代方式是按分钟数循环, 然后使用除法+余数计算小时和日期:

dmax=np.array([[31,28,31,30,31,30,31,31,30,31,30,31]]).T #number of days in a month
for month in range (1,13):
    nb_days = dmax[month-1]
    for m in range(60*24*nb_days):
        hour,minute = divmod(m,60)
        day,hour = divmod(hour,nb_days)
        day += 1

这是在每次迭代与2个循环之间使用2个除法/模(使用divmod函数可以一次完成)之间的折衷。由于python循环非常昂贵,因此值得尝试。

答案 2 :(得分:0)

(针对您的代码)是否有任何静态初始化

dmax=np.array([[31,28,31,30,31,30,31,31,30,31,30,31]]).T #number of days in a month

它应该在for循环之外。因为,每次循环运行时,该数组都会被初始化以进行许多计算。

答案 3 :(得分:0)

除了计算秒数外,您似乎没有使用月,日和分钟。

您可以使用如下所示的代码在1个循环中完成编码,而不必对一个月数组中的日期进行硬编码:

year=2001
DT1=dt.datetime(year, 1, 1, 0, 0, 0, 0),'UTC')
DT2=dt.datetime(year, 1, 1, 0, 0, 59, 999999),'UTC')
DToneSec=datetime.timedelta(seconds=1)
DTy=dt.datetime(year+1, 1, 1, 0, 0, 0, 0),'UTC')-DT1

for k in range (1,DTy.total_seconds()+1):
    D1=spt.Ticktock(DT1).RDT
    DT1+=DToneSec
    D2=spt.Ticktock(DT2).RDT
    DT2+=DToneSec

    g[k,0]=np.nanmean(electrons[(time>D1)&(time<D2)])