Python - 在数组中查找序列:当两个值低于阈值时开始,当两个值高于阈值时结束

Python - Find sequence in array: start when two values below threshold, end when two values above threshold

我有一个干旱指数 (PDSI) 的年度时间序列,其值范围从 -4 到 +4。我正在尝试定义一个干旱事件,该事件以连续两年低于 PDSI 值 0 开始,并在连续两年大于或等于 0 时结束。

比如这一系列的数据:

ts = [-2, -2, -4,  0, -1,  0, -1,  1, -2,  2, -3, -2,  3,  1, -2, 
      -3, -4, -3,  3, -3, -3, -3, -1, -3,  3,  3, -4, -1, -1,  0]

注意:我尝试张贴图片以帮助可视化问题,但我的声誉不够高

根据上面的干旱定义,这个系列应该有三个干旱:

1) 从第 0 年开始到第 11 年结束(第 12 和 13 年是 >= 0)

2) 从第 14 年开始到第 23 年结束(第 24 和 25 年 >= 0)

3) 从第 26 年开始到系列结束时:第 29 年。尽管这场干旱没有连续两年结束 >=0,但它仍在进行中,应该计算在内。

return 值可以是一个数组,如:

droughts = [[0, 11], [14, 23], [26, 29]]

这意味着排除任何两个连续PDSI值<0的潜在子集。例如,在第一个序列[0, 11]中,[1,2]和[10,11]也满足'two consecutive values below the threshold' 规则。但是,它们应该被忽略,因为它们是更大序列的一部分。

编辑:

这里有一些代码可用于定义前两次干旱,但在最后一次上挂断了(我认为它会无限循环)。我是 Python 的新手,除此之外,代码无法正常工作,我猜它的效率也很低。

def find_droughts (array):
answer = []
i = 0
while i < len(array):
    if (array[i] < 0 and array[i+1] < 0):
        if i+1 >= len(array):
            i = len(array)
            end = i
            a.append([start, end])
            break
        else:
            start = i
            print "start = %s" %start
        for j in range(i+2, len(array)-1):
            if (array[j] >= 0 and array[j+1] >= 0):
                end = j-1
                a.append([start, end])
                print 'end=%s' %end
                i = j+2;
                break
            else:
                i += 1
    else:
        i += 1
return answer

find_droughts(ts)

和下面的输出。不得不中断内核,因为它陷入了循环。

start = 0
end=11
start = 14
end=23
start = 26
start = 27
start = 27
start = 27
start = 27
....

这样的事情怎么样:

ts = [-2, -2, -4,  0, -1,  0, -1,  1, -2,  2, -3, -2,  3,  1, -2,
      -3, -4, -3,  3, -3, -3, -3, -1, -3,  3,  3, -4, -1, -1,  0]

# find positions of 2 consecutive negatives
neg = [i for i in range(len(ts)-1) if ts[i]<0 and ts[i+1] < 0]
print neg

# find locations of 2 consecutive positives + last year
pos = [i for i in range(len(ts)-1) if ts[i]>0 and ts[i+1] > 0] + [len(ts)]
print pos

# find the earliest neg for each pos
draughts = []
for p in pos:
    try:
        draughts.append((neg[0],p))
        neg = [n for n in neg if n > p]
    except IndexError:
        # no more negatives left, no draught in progress
        break

print draughts

输出:

[0, 1, 10, 14, 15, 16, 19, 20, 21, 22, 26, 27]
[12, 24, 30]
[(0, 12), (14, 24), (26, 30)]

有一些需要解决的问题和边缘情况,但总体而言...

这里有一个替代方法,只需要一次通过 ts:

ts = [-2, -2, -4,  0, -1,  0, -1,  1, -2,  2, -3, -2,  3,  1, -2,
      -3, -4, -3,  3, -3, -3, -3, -1, -3,  3,  3, -4, -1, -1,  0]

in_draught = False
draught = []

for i in range(len(ts)-1):
    if in_draught and ts[i] > 0 and ts[i+1] > 0:
        in_draught = False
        draught.append(i)
    elif not in_draught and ts[i] <0 and ts[i+1] < 0:
        in_draught = True
        draught.append(i)
if in_draught:
    draught.append(len(ts)-1)

print [draught[i:i+2] for i in range(0,len(draught),2)]

输出:

[[0, 12], [14, 24], [26, 29]]