计算多年 5 天 运行 百分位数

Calculating multi year 5-day running percentile

我需要根据多年数据计算每个日历日的 3 天 运行 第 90 个百分位值。我有 30 年的每日数据集,如下所示,

            year    month   day  value
DATE                    
01/01/1980  1980    1       1    12.3957
02/01/1980  1980    1       2    8.2678
03/01/1980  1980    1       3    11.9438
04/01/1980  1980    1       4    8.8035
05/01/1980  1980    1       5    2.749
...             ... ... ...
27/01/2010  2010    1       27   4.1186
28/01/2010  2010    1       28   5.9619
29/01/2010  2010    1       29   8.8146
30/01/2010  2010    1       30   12.9397
31/01/2010  2010    1       31   11.8427

为了计算 1 月 1 日的第 90 个百分位值,我必须选择以 1 月 1 日为中心的 3 天 window 30 年。所以,我每天会有 90 (3*30) 个数据点。我可以计算百分位并将其记录为该中心日的第 90 个百分位值。然后,我将通过移动 3 天 window 对每一天重复此过程,直到我有一个新的数据框,其中填充了从 1 月 1 日到 12 月 31 日的每一天的百分位值。

问题是,我的数据集有时是正常的日历年(即 365/366 天),有时只有 365 天,或 360 天(12 个月*30 天)。我正在删除闰日,但我不知道哪个数据集是哪个。

我尝试了几天的迭代,但是当没有 2 月 29 日或 1 月 31 日时我遇到了问题。我尝试使用 for 循环在多个条件下进行切片,但我遇到了同样的问题。

我不知道如何选择 30 年的 3 天移动 window 并计算百分位数。

如有任何帮助,我们将不胜感激!

我已经设法解决了这个问题。首先,我放弃了 2 月 29 日。因此,我将有一个 365 天或 360 天的数据集。然后,我将日期时间索引更改为字符串。

df.index = df.index.strftime('%m-%d')

我在唯一索引值上使用了枚举来遍历所有天。我使用 if-else 块能够选择以一年的第一天和最后两天为中心的 5 天 window,否则 start 将大于 end

对于 1 月 1 日,它将是

current = '01-01'
start = '12-30'
end = '01-03'

因此,我同时使用了 or |and & 运算符来选择日期。

90p = {}
for count, date in enumerate(df.index.unique()):
    start = df.index[count-2]
    end = df.index[count+2]
    current = df.index[count]
    print("My date is %s, 2 day before is %s and 2 day later is %s" % (current, start, end))

    # day[0]
    if count == 0:
        temp = df.loc[((df.index >= current) & (df.index <= end)) | ((df.index >= df.index[count - 2]) & (df.index <= df.index[count - 1]))]
        90p[date] = temp.value.quantile(0.9)
    
    # day[1]
    elif count == 1:
        temp = df.loc[((df.index >= df.index[count - 1]) & (df.index <= end)) | ((df.index >= df.index[count - 2]) & (df.index <= df.index[count - 2]))]
        90p[date] = temp.value.quantile(0.9)
    
    # day[-2]
    elif count == len(df.index.unique()) - 2:
        temp = df.loc[((df.index >= df.index[count - 2]) & (df.index <= df.index[count + 1])) | ((df.index >= df.index[count + 2]) & (df.index <= df.index[count + 2]))]
        90p[date] = temp.value.quantile(0.9)

    # day[-1]
    elif count == len(df.index.unique()) - 1:
        temp = df.loc[((df.index >= df.index[count - 2]) & (df.index <= df.index[count])) | ((df.index >= df.index[count + 1]) & (df.index <= df.index[count + 2]))]
        90p[date] = temp.value.quantile(0.9)
    
    # day[2:-2]
    else:
        temp = df.loc[(df.index >= start) & (df.index <= end)]  
        90p[date] = temp.value.quantile(0.9)