【问题标题】:Weighted average of time-series with changing weights over time权重随时间变化的时间序列的加权平均值
【发布时间】:2019-06-02 08:19:19
【问题描述】:

我需要生成一些金融资产回报的加权平均值,其中使用的权重会随时间变化。 (申请是财务问题,但问题本身是一个非常普遍的问题)。

我的回报和权重摘录如下:

returns_df:随着时间的推移资产回报率

┌──────────────────┬────────────┬────────────┬────── ──────┐ │ 日期时间 │ 资产 1 │ 资产 2 │ 资产 3 │ ├──────────────────┼────────────┼────────────┼────── ──────┤ │ 2015-04-09 07:00 │ -0.000959 │ -0.000207 │ -0.000233 │ │ 2015-04-09 08:00 │ -0.004003 │ 0.000169 │ 0.001221 │ │ 2015-04-09 09:00 │ -0.000700 │ -0.000070 │ -0.000096 │ │ 2015-04-09 10:00 │ -0.000812 │ -0.000289 │ 0.000177 │ │ 2015-04-09 11:00 │ -0.000030 │ -0.000168 │ -0.000315 │ └──────────────────┴────────────┴───────────┴────── ──────┘

weights_df:资产权重随时间变化

┌──────────────────┬──────────┬─────────┬─────────┐ │ 权重开始 │ 资产 1 │ 资产 2 │ 资产 3 │ ├──────────────────┼──────────┼─────────┼──────────┤ │ 2015-03-01 │ 1 │ 0 │ 0 │ │ 2015-04-01 │ 0.023 │ 0.8733 │ 0.1037 │ │ 2015-05-01 │ 1 │ 0 │ 0 │ │ 2015-06-01 │ 0.0477 │ 0.8278 │ 0.1245 │ └──────────────────┴──────────┴─────────┴─────────┘

例如,第一个表中的收益都将由{0.023; 0.8733; 0.103} 加权,因为它们都落在之后 2015-04-01之前 2015-05-01。 p>

当然,我的真实数据集的回报跨越了我体重的整个日期范围。

我完全不知道如何解决这个问题,我想过使用groupby(),但鉴于weights_df 的形状与returns_df 不同,这似乎不起作用。

import numpy as np
import pandas as pd
from io import StringIO
# alternatively try `import StringIO`

returns_datatext = StringIO("""
    DateTime     │  Asset 1  │  Asset 2  │  Asset 3
2015-04-09 07:00 │ -0.000959 │ -0.000207 │ -0.000233
2015-04-09 08:00 │ -0.004003 │  0.000169 │  0.001221
2015-04-09 09:00 │ -0.000700 │ -0.000070 │ -0.000096
2015-04-09 10:00 │ -0.000812 │ -0.000289 │  0.000177
2015-04-09 11:00 │ -0.000030 │ -0.000168 │ -0.000315
""")
returns_df = pd.read_table(returns_datatext, index_col=[0], parse_dates=True, sep='│')

weights_datatext = StringIO("""
Start of weights │ Asset 1 │ Asset 2 │ Asset 3
2015-03-01       │       1 │       0 │       0
2015-04-01       │   0.023 │  0.8733 │  0.1037
2015-05-01       │       1 │       0 │       0
2015-06-01       │  0.0477 │  0.8278 │  0.1245
""")
weights_df = pd.read_table(weights_datatext, index_col=[0], parse_dates=True, sep='│')

上表的预期结果如下:

┌──────────────────┬──────────────────┐ │ 日期时间 │ 加权平均 │ ├──────────────────┼──────────────────┤ │ 2015-04-09 07:00 │ -0.000227 │ │ 2015-04-09 08:00 │ 0.000182 │ │ 2015-04-09 09:00 │ -0.000087 │ │ 2015-04-09 10:00 │ -0.000253 │ │ 2015-04-09 11:00 │ -0.000180 │ └──────────────────┴──────────────────┘

【问题讨论】:

    标签: python pandas dataframe time-series weighted-average


    【解决方案1】:

    这是pd.merge_asof将两者联系起来,然后是numpy.average

    import pandas as pd
    import numpy as np
    
    ## Fix whitespace in sample data
    #returns_df.index.name = 'DateTime'
    #returns_df.columns = ['Asset1', 'Asset2', 'Asset3']
    #weights_df.index.name= 'Start of weights'
    #weights_df.columns = ['Asset1', 'Asset2', 'Asset3']
    
    df = pd.merge_asof(returns_df, weights_df,
                       left_index=True, right_index=True, 
                       direction='backward',
                       suffixes=['', '_weight'])
    
    cols = ['Asset1', 'Asset2', 'Asset3']
    returns_df['weighted_average'] = np.average(df[cols], weights=df[[col + '_weight' for col in cols]], axis=1)
    

    输出:returns_df

                           Asset1    Asset2    Asset3  weighted_average
    DateTime                                                           
    2015-04-09 07:00:00 -0.000959 -0.000207 -0.000233         -0.000227
    2015-04-09 08:00:00 -0.004003  0.000169  0.001221          0.000182
    2015-04-09 09:00:00 -0.000700 -0.000070 -0.000096         -0.000087
    2015-04-09 10:00:00 -0.000812 -0.000289  0.000177         -0.000253
    2015-04-09 11:00:00 -0.000030 -0.000168 -0.000315         -0.000180
    

    为了说明,这是合并后的DataFrame。逻辑选择weights_df中最接近returns_df中日期之前的日期作为合并条件:

                           Asset1    Asset2    Asset3  Asset1_weight  Asset2_weight  Asset3_weight
    DateTime                                                                                      
    2015-04-09 07:00:00 -0.000959 -0.000207 -0.000233          0.023         0.8733         0.1037
    2015-04-09 08:00:00 -0.004003  0.000169  0.001221          0.023         0.8733         0.1037
    2015-04-09 09:00:00 -0.000700 -0.000070 -0.000096          0.023         0.8733         0.1037
    2015-04-09 10:00:00 -0.000812 -0.000289  0.000177          0.023         0.8733         0.1037
    2015-04-09 11:00:00 -0.000030 -0.000168 -0.000315          0.023         0.8733         0.1037
    

    【讨论】:

    • 漂亮!请注意,如果您使用 left_index=Trueright_index=True,则不需要 reset_index(),因为这两个数据集都将日期时间作为索引。
    • @Doggie52 很棒。
    • 实际上np.average 不是在这里使用的正确方法。权重会随着时间而变化,但在我看来,它只接受提供的一组固定权重。
    • @Doggie52 你误会了。 merge_asof 步骤负责根据时间匹配适当的权重。然后numpy.average 沿axis=1 计算,这意味着对于每一行它使用指定的权重。仅在您提供的示例中,结果始终是相同的权重。
    • 正确 - 道歉。我的错误来自我的代码的不同部分。仅供参考,如果某些权重行有时总和为零,您可以使用np.ma.average()。我相信否则功能与np.average()相同。
    猜你喜欢
    • 1970-01-01
    • 2012-06-06
    • 1970-01-01
    • 1970-01-01
    • 2019-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多