如何计算高于/低于阈值的时间序列中的连续周期?

时间:2019-07-02 19:13:13

标签: python for-loop count

我有一个为期一年的值的数据集,我要检测并计算连续值在预定阈值之上/之下的周期。我想简单地返回连续的上/下阈值的每个周期的长度。我在网上找到了几乎可以完全执行我想要的代码的代码(如下所示,该函数名为“ fire_season_length”),除了它在返回数据集结束之前(该年末)的最后连续时间段有困难。

我相信这个问题是因为只有在一系列值从阈值之上(以下)翻转到阈值之下(之上)时,才会报告一段连续的值。

这是我用来计算连续的上/下阈值周期的函数:

def fire_season_length(ts, threshold):

    ntot_ts = ts.count() #total number of values in ts (timeseries)
    n_gt_threshold = ts[ts >= threshold].count() #number of values greater than threshold

    type_day = 0 #below threshold
    type_day = 1 #meets or exceeds threshold

    type_prev_day = 0 #initialize first day 
    storage_n_cons_days = [[],[]]   #[[cons days above threshold], [cons days below threshold]]
    n_cons_days = 0

    for cur_day in ts: #current day in timeseries

        if cur_day >= threshold:
            type_cur_day = 1
            if type_cur_day == type_prev_day: #if same as current day
                n_cons_days += 1
            else: #if not same as current day
                storage_n_cons_days[1].append(n_cons_days)
                n_cons_days = 1
            type_prev_day = type_cur_day
        else:
            type_cur_day = 0
            if type_cur_day == type_prev_day:
                n_cons_days += 1
            else:
                storage_n_cons_days[0].append(n_cons_days)
                n_cons_days = 1
            type_prev_day = type_cur_day



    return ntot_ts, n_gt_threshold, storage_n_cons_days

这是我通过函数运行时间序列时的输出; 我注释了该图以显示有7个周期的连续值,但返回的数组为[[13,185,30],[24、78、12]](表示[[阈值以上的周期] ,[[低于阈值的时间段]]])仅列出了六个这样的时间段。似乎输出中未报告时间段7,这与我在此功能中测试的其他时间序列的输出也一致。{{3 }}

所以我的问题是:即使一系列值没有翻转为另一个符号(高于/低于阈值),我如何获取代码以返回连续值的最终周期?

1 个答案:

答案 0 :(得分:1)

您可以结合使用accumulate()和Counter():

import random
from itertools import accumulate
from collections import Counter

ts = [ random.randint(1,100) for _ in range(15) ]

treshold = 50
groups = accumulate([0]+[(a>=treshold) != (b>=treshold) for a,b in zip(ts,ts[1:])])
counts = sorted(Counter(groups).items())
above  = [ c for n,c in counts if (n%2==0) == (ts[0]>=treshold) ]
below  = [ c for n,c in counts if (n%2==0) != (ts[0]>=treshold) ]

print("data ",ts)
print("above",above)
print("below",below)

示例输出:

data  [99, 49, 84, 69, 27, 88, 35, 43, 3, 48, 80, 14, 32, 97, 78]
above [1, 2, 1, 1, 2]
below [1, 1, 4, 2]

其工作方式如下:

  • 首先确定上下之间发生变化的位置。
  • 状态更改由True(1)标识,而未更改的位置由False(0)标识。
  • 这些1和0的累加总和将产生一系列不同的变化值,重复这些无状态位置的值。
  • 然后使用Counter类来计算每个重复值出现了多少。这对应于通过明显的状态变化分解的连续状态的数量。
  • 对计数器排序将恢复状态更改的时间顺序。
  • 根据第一项的状态,偶数值将全部对应于上或下状态,而奇数值将成为相反状态。