固定时间窗口内的滚动平均在数据框中。

3

我有一个类似这样的数据框:

import pandas as pd

df = pd.DataFrame({'ID': [1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3],
                   'val': [1,2,3,1,2,3,1,2,3,4,5,6,1,2,3,4,5,6,1,2,3],
                   'time': [pd.Timestamp(2017, 1, 1, 12), pd.Timestamp(2017, 1, 1, 13), pd.Timestamp(2017, 1, 1, 14), pd.Timestamp(2017, 1, 2, 16), pd.Timestamp(2017, 1, 2, 17), pd.Timestamp(2017, 1, 2, 18), pd.Timestamp(2017, 1, 1, 12), pd.Timestamp(2017, 1, 1, 13), pd.Timestamp(2017, 1, 1, 14), pd.Timestamp(2017, 1, 1, 15), pd.Timestamp(2017, 1, 1, 16), pd.Timestamp(2017, 1, 2, 15), pd.Timestamp(2017, 1, 1, 12), pd.Timestamp(2017, 1, 1, 13), pd.Timestamp(2017, 1, 1, 14), pd.Timestamp(2017, 1, 1, 15), pd.Timestamp(2017, 1, 1, 16), pd.Timestamp(2017, 1, 1, 17), pd.Timestamp(2017, 1, 2, 18), pd.Timestamp(2017, 1, 2, 19), pd.Timestamp(2017, 1, 2, 20)]})

我希望创建一个新列,为每行提供在该行的time之前24小时内与相同ID的所有行的val平均值。

如何用pythonic的方式实现这个目标?而非逐行迭代计算。

期望输出:

    ID  val                time  24hr_avg
0    1    1 2017-01-01 12:00:00       1.0 ###
1    1    2 2017-01-01 13:00:00       1.5  ##
2    1    3 2017-01-01 14:00:00       2.0   #
3    1    1 2017-01-02 16:00:00       1.0    ##
4    1    2 2017-01-02 17:00:00       1.5     ##
5    1    3 2017-01-02 18:00:00       2.0      #
6    2    1 2017-01-01 12:00:00       1.0       #####
7    2    2 2017-01-01 13:00:00       1.5        ####
8    2    3 2017-01-01 14:00:00       2.0         ###
9    2    4 2017-01-01 15:00:00       2.5          ###
10   2    5 2017-01-01 16:00:00       3.0           ##
11   2    6 2017-01-02 15:00:00       8.0            #
12   3    1 2017-01-01 12:00:00       1.0             ######
13   3    2 2017-01-01 13:00:00       1.5              #####
14   3    3 2017-01-01 14:00:00       2.0               ####
15   3    4 2017-01-01 15:00:00       2.5                ###
16   3    5 2017-01-01 16:00:00       3.0                 ##
17   3    6 2017-01-01 17:00:00       3.5                  #
18   3    1 2017-01-02 18:00:00       1.0                   ###
19   3    2 2017-01-02 19:00:00       1.5                    ##
20   3    3 2017-01-02 20:00:00       2.0                     #
2个回答

5

如果你首先用 set_index 来设置时间列,那么你可以使用窗口大小为 24 小时的 groupby.rolling。然后将其与原始数据进行merge

df_ = df.merge(df.set_index('time').sort_index()
                 .groupby('ID')
                 .rolling('24H')
                 ['val'].mean()
                 .rename('24hr_avg'), 
               left_on=['ID', 'time'], right_index=True)
print(df_)
    ID  val                time  24hr_avg
0    1    1 2017-01-01 12:00:00       1.0
1    1    2 2017-01-01 13:00:00       1.5
2    1    3 2017-01-01 14:00:00       2.0
3    1    1 2017-01-02 16:00:00       1.0
4    1    2 2017-01-02 17:00:00       1.5
5    1    3 2017-01-02 18:00:00       2.0
6    2    1 2017-01-01 12:00:00       1.0
7    2    2 2017-01-01 13:00:00       1.5
8    2    3 2017-01-01 14:00:00       2.0
9    2    4 2017-01-01 15:00:00       2.5
10   2    5 2017-01-01 16:00:00       3.0
11   2    6 2017-01-02 15:00:00       5.5
12   3    1 2017-01-01 12:00:00       1.0
13   3    2 2017-01-01 13:00:00       1.5
14   3    3 2017-01-01 14:00:00       2.0
15   3    4 2017-01-01 15:00:00       2.5
16   3    5 2017-01-01 16:00:00       3.0
17   3    6 2017-01-01 17:00:00       3.5
18   3    1 2017-01-02 18:00:00       1.0
19   3    2 2017-01-02 19:00:00       1.5
20   3    3 2017-01-02 20:00:00       2.0

4
我们可以使用 Groupby.rolling
df['24hr_avg'] = (
    df.set_index('time')
    .groupby('ID', sort=False)['val']
    .rolling('1D')
    .mean()
    .to_numpy()
)

    ID  val                time  24hr_avg
0    1    1 2017-01-01 12:00:00       1.0
1    1    2 2017-01-01 13:00:00       1.5
2    1    3 2017-01-01 14:00:00       2.0
3    1    1 2017-01-02 16:00:00       1.0
4    1    2 2017-01-02 17:00:00       1.5
5    1    3 2017-01-02 18:00:00       2.0
6    2    1 2017-01-01 12:00:00       1.0
7    2    2 2017-01-01 13:00:00       1.5
8    2    3 2017-01-01 14:00:00       2.0
9    2    4 2017-01-01 15:00:00       2.5
10   2    5 2017-01-01 16:00:00       3.0
11   2    6 2017-01-02 15:00:00       5.5
12   3    1 2017-01-01 12:00:00       1.0
13   3    2 2017-01-01 13:00:00       1.5
14   3    3 2017-01-01 14:00:00       2.0
15   3    4 2017-01-01 15:00:00       2.5
16   3    5 2017-01-01 16:00:00       3.0
17   3    6 2017-01-01 17:00:00       3.5
18   3    1 2017-01-02 18:00:00       1.0
19   3    2 2017-01-02 19:00:00       1.5
20   3    3 2017-01-02 20:00:00       2.0

请使用.reset_index(level=0, drop=True)代替.to_numpy() - jezrael
另一方面,如果时间戳上有重复的时间条目,使用合并将失败,这将导致重复。因此,最好的方法是按ID和时间对其进行排序,然后使用此方法。 - Erfan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接