Python - 时间加权平均 Pandas ,按时间间隔分组

标签 python pandas timestamp time-series weighted-average

我在 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

我想获取 15 分钟 block 的时间加权平均值。时间戳直接在 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 行,因此逐条迭代每条记录会非常慢。

我尝试查看 Pandas 的 df.rolling() 函数,但无法弄清楚如何将它直接应用于我的特定场景。

非常感谢您的帮助!

更新 1:

根据Simon的精彩解决方案,我对其进行了一些修改。

我对其进行了一些调整以适应我的具体情况:

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 分钟间隔(数据库中缺少行)

最佳答案

这个很棘手。我很乐意看到另一位评论者更有效地做到这一点,因为我有一种预感,有更好的方法来做到这一点。

我还跳过了一个部分,即对 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)

关于Python - 时间加权平均 Pandas ,按时间间隔分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46030055/

相关文章:

python - 在 Flask 中,我可以在函数运行时显示一个模板并在函数完成后重定向到另一个模板吗?

sql - 如何将日期和时间组合成 db2 中的时间戳?

python - 根据最频繁的值删除列

python - 如何按python pandas中的值范围列表进行分组

java - Android Kotlin/JAVA - 获取自 1970 年以来的当前世界时间/UTC(以秒为单位)

c++ - 使用 C++ 驱动程序向 MongoDB 添加毫秒时间戳的最有效方法

python - Postgresql 数值类型在python中的显示

Python Pandas qcut 行为,其中 # of observations 不能被 # of bins 整除

python - shell退出时必须捕获什么样的信号

python - Pandas - 从数据框创建差异矩阵