面板数据中的熊猫时间加权平均分组依据

时间:2019-03-11 17:31:40

标签: pandas pandas-groupby weighted-average

嗨,我有一个面板数据集,看起来像

require 'csv'
table = CSV.table('file_name.csv')
transformed_into_hash = table.map { |row| row.to_hash }
File.open("file_name.yaml", "w") do |f|
  f.puts transformed_into_hash.to_yaml
end

我想计算每天每一只股票的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 加权平均值。我可以将解决方案分为几个步骤。即,我可以应用spread1groupby函数来获取数据框1中每一天每一股票的点差1 *权重之和,然后计算数据框2中每一天每一只股票的权重之和。之后,agg将获得两个数据集,并获得spread1的加权平均值。

我的问题是,有什么简单的方法可以计算出spread1的加权平均值吗?我也有spread2,spread3和spread4。所以我想写更少的代码。谢谢

1 个答案:

答案 0 :(得分:1)

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