pandas面板数据中的时间加权平均groupby

pandas time-weighted average groupby in panel data

你好我有一个面板数据集看起来像

stock    date     time   spread1  weight  spread2 
VOD      01-01    9:05    0.01    0.03     ...
VOD      01-01    9.12    0.03    0.05     ...
VOD      01-01   10.04    0.02    0.30     ...
VOD      01-02   11.04    0.02    0.05
...       ...     ...     ....     ...
BAT      01-01   0.05     0.04    0.03
BAT      01-01   0.07     0.05    0.03
BAT      01-01   0.10     0.06    0.04

我想计算每天每只股票的 spread1 的加权平均值。我可以将解决方案分成几个步骤。即我可以应用 groupbyagg 函数来获取 dataframe1 中每天每只股票的 spread1*weight 之和,然后计算 dataframe2 中每天每只股票的权重总和。之后 merge 两个数据集并得到 spread1 的加权平均值。

我的问题是这里有什么简单的方法可以计算点差 1 的加权平均值吗?我还有点差 2、点差 3 和点差 4。所以我想写尽可能少的代码。谢谢

IIUC,您需要 transform 将结果恢复为原始结果,但是使用 .transform 输出取决于两列是棘手的。我们编写自己的函数,在其中传递传播序列 s 和原始 DataFrame df,因此我们也可以使用权重:

import numpy as np

def weighted_avg(s, df):
    return np.average(s, weights=df.loc[df.index.isin(s.index), 'weight'])

df['spread1_avg'] = df.groupby(['stock', 'date']).spread1.transform(weighted_avg, df)

输出:

  stock   date   time  spread1  weight  spread1_avg
0   VOD  01-01   9:05     0.01    0.03     0.020526
1   VOD  01-01   9.12     0.03    0.05     0.020526
2   VOD  01-01  10.04     0.02    0.30     0.020526
3   VOD  01-02  11.04     0.02    0.05     0.020000
4   BAT  01-01   0.05     0.04    0.03     0.051000
5   BAT  01-01   0.07     0.05    0.03     0.051000
6   BAT  01-01   0.10     0.06    0.04     0.051000

如果需要多列:

gp = df.groupby(['stock', 'date'])
for col in [f'spread{i}' for i in range(1,5)]:
    df[f'{col}_avg'] = gp[col].transform(weighted_avg, df)

或者,如果您不需要转换回来并且想要每个股票日期的价值:

def my_avg2(gp):
    avg = np.average(gp.filter(like='spread'), weights=gp.weight, axis=0)
    return pd.Series(avg, index=[col for col in gp.columns if col.startswith('spread')])    

### Create some dummy data
df['spread2'] = df.spread1+1
df['spread3'] = df.spread1+12.1
df['spread4'] = df.spread1+1.13

df.groupby(['stock', 'date'])[['weight'] + [f'spread{i}' for i in range(1,5)]].apply(my_avg2)

#              spread1   spread2    spread3   spread4
#stock date                                          
#BAT   01-01  0.051000  1.051000  12.151000  1.181000
#VOD   01-01  0.020526  1.020526  12.120526  1.150526
#      01-02  0.020000  1.020000  12.120000  1.150000