Python - 时间加权平均熊猫,按时间间隔分组
问题描述:
我有熊猫数据框中的时间序列。时间戳可能不均匀(每1-5分钟一次),但每隔5分钟总会有一次(分钟以0,5,10,15,20,25,30,35,40,45,50结尾的时间戳,55)。Python - 时间加权平均熊猫,按时间间隔分组
例子:
2017-01-01 2:05:00 32.90
2017-01-01 2:07:30 29.83
2017-01-01 2:10:00 45.76
2017-01-01 2:15:00 16.22
2017-01-01 2:20:00 17.33
2017-01-01 2:25:00 23.40
2017-01-01 2:28:45 150.12
2017-01-01 2:30:00 100.29
2017-01-01 2:35:00 38.45
2017-01-01 2:40:00 67.12
2017-01-01 2:45:00 20.00
2017-01-01 2:50:00 58.41
2017-01-01 2:55:00 58.32
2017-01-01 3:00:00 59.89
我想15分钟块的时间加权平均值。具有时间戳直接是在15分钟标记(时间戳与结束0,15,30,45分钟)结束的时间间隔中的行,所以分组如下:
Group 1 (interval 2017-01-01 2:00:00):
2017-01-01 2:05:00 32.90
2017-01-01 2:07:30 29.83
2017-01-01 2:10:00 45.76
2017-01-01 2:15:00 16.22
Group 2 (interval 2017-01-01 2:15:00):
2017-01-01 2:20:00 17.33
2017-01-01 2:25:00 23.40
2017-01-01 2:28:45 150.12
2017-01-01 2:30:00 100.29
Group 3 (interval 2017-01-01 2:30:00):
2017-01-01 2:35:00 38.45
2017-01-01 2:40:00 67.12
2017-01-01 2:45:00 20.00
Group 4 (interval 2017-01-01 2:45:00):
2017-01-01 2:50:00 58.41
2017-01-01 2:55:00 58.32
2017-01-01 3:00:00 59.89
平均必须是时间加权,所以不仅仅是一个组中所有值的标准平均值。
例如,组2的时间加权平均值不是72.785,这是所有4个值的常规平均值。相反,它应该是:
(5 minutes/15 minutes) * 17.33 = 5.776667 ==> The 5 minutes is taken from the difference between this timestamp and the previous timestamp
+(5 minutes/15 minutes) * 23.40 = 7.8
+(3.75 minutes/15 minutes) * 150.12 = 37.53
+(1.25 minutes/15 minutes) * 100.29 = 8.3575
= **59.46417**
而且理想情况下,15分钟参数,因为这可能会在未来的60分钟(每小时)改变,但我不认为这是一个问题在这里。
此外,性能在此非常重要。由于我的数据集将有大约10k行,因此逐个遍历每条记录会非常缓慢。
我试过寻找熊猫的df.rolling()函数,但无法弄清楚如何将它直接应用到我的特定场景。
非常感谢您的帮助!
更新1:
继西蒙的辉煌的解决方案,我修改了它一点点。
我做了一些调整,它以使其适应我的具体情况:
def func(df):
if df.size == 0: return
timestep = 15*60
indexes = df.index - (df.index[-1] - pd.Timedelta(seconds=timestep))
seconds = indexes.seconds
weight = [seconds[n]/timestep if n == 0 else (seconds[n] - seconds[n - 1])/timestep
for n, k in enumerate(seconds)]
return np.sum(weight*df.values)
这是为了应付可能是空的,每隔15分钟(中缺少DB行)
答
这一次是棘手。我希望看到另一位评论者更有效地做到这一点,因为我有预感,有更好的方法来做到这一点。
我也跳过了一个部分,它参数化了15分钟的值,但我指出你可以在评论中做到这一点。这留给读者一个练习:D它应该被参数化,因为它现在有很多随机的'* 15'和'* 60'值散布在这个地方,看起来很笨拙。
我也很累,我的妻子想看电影,所以我没有清理我的代码。这有点混乱,应该写得更清洁 - 这可能或不值得做,取决于其他人是否可以在6行代码中重做这些。如果明天早上它还没有回答,我会回过头来,做得更好。
更新更好的解决方案1
def func(df):
timestep = 15*60
seconds = (df.index.minute*60+df.index.second)-timestep
weight = [k/timestep if n == 0 else (seconds[n] - seconds[n - 1])/timestep
for n, k in enumerate(seconds)]
return np.sum(weight*df.values)
df.resample('15min', closed='right').apply(func)
这是辉煌!非常感谢,这正是我需要的! 有没有办法使用GroupBy()而不是Resample()? 原因是我有另一列我想分组,其中我没有包括在原来的问题,为简单起见。我似乎是使用表: df.groupby([pd.TimeGrouper(freq ='15Min')])) 但似乎没有办法关闭右侧的组,如resample()函数具有。 –
所以基本上,我有以下的4列在我的表: “TIME | ZONE |价格1 | PRICE2” 我想有每个区的时间加权平均每十五分钟间隔每个价格 –
我做一些更多的数据测试和整个事情是非常缓慢的;也许我只是不习惯Python的速度。要处理160万行(每组约3行530k组),大约需要10分钟。我在C#程序中做了同样的事情(代码长得多,因为我不得不在每一行上手动迭代),并且花了不到10秒。 –