Vin*_*t L 3 python timestamp time-series weighted-average pandas
我在Pandas DataFrame中有一个时间序列.时间戳可能不均匀(每1-5分钟一个),但总会有一个每5分钟一次(时间戳以分钟结尾于0,5,10,15,20,25,30,35,40,45,50 ,55).
例:
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
Run Code Online (Sandbox Code Playgroud)
我想获得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
Run Code Online (Sandbox Code Playgroud)
平均值必须是时间加权的,因此不仅仅是组中所有值的标准平均值.
例如,第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**
Run Code Online (Sandbox Code Playgroud)
理想情况下,15分钟是参数化的,因为将来可能会改变为60分钟(每小时),但我不认为这是一个问题.
此外,性能在这方面非常重要.由于我的数据集将有大约10k行,因此逐个迭代每个记录将非常慢.
我试着查看Pandas的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)
Run Code Online (Sandbox Code Playgroud)
这是为了应对可能空的15分钟间隔(数据库中缺少行)
这个很棘手.我希望看到另一位评论者更有效地做到这一点,因为我有预感,有更好的方法来做到这一点.
我也跳过了一个参数化15分钟值的部分,但是我指出你可以在评论中做到这一点.这是留给读者的练习:D它应该参数化,因为它现在有很多随机的'*15'和'*60'值分散在这个地方,看起来很笨拙.
我也累了,我的妻子想看电影,所以我没有清理我的代码.它有点乱,应该写得更干净 - 这可能是也可能不值得做,这取决于其他人是否可以在6行代码中重做这一切.如果明天早上仍然没有答案,我会回过头来做得更好.
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)
Run Code Online (Sandbox Code Playgroud)