微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在双时态数据集上计算移动平均

如何解决在双时态数据集上计算移动平均

我正在尝试计算双时态数据集的移动平均值。数据集由数据日期和生效日期(数据可用的日期)组成。该日期的数据可以在未来多次重述(相同的数据日期但不同的生效日期)。 我需要使用对正在计算的行的生效日期有效的数据来计算过去 4 个季度的移动平均值。

数据集看起来像这样

id 数据日期 生效 价值
1 2005-03-31 2005-04-15 10
1 2005-03-31 2005-05-30 11
1 2005-06-30 2005-07-15 9
1 2005-06-30 2005-08-20 9.5
1 2005-06-30 2005-10-15 9.6
1 2005-09-30 2005-10-15 10.5
1 2005-09-30 2005-11-10 11
1 2005-09-30 2006-02-20 10.75
1 2005-12-31 2006-02-13 12
1 2005-12-31 2006-02-20 11.6
1 2005-12-31 2006-05-10 11
1 2006-03-31 2006-04-20 8
1 2006-03-31 2006-05-10 8.25

结果应该是

id 数据日期 生效 价值 平均
0 1 2005-03-31 2005-04-15 10 10
1 1 2005-03-31 2005-05-30 11 11
2 1 2005-06-30 2005-07-15 9 10
3 1 2005-06-30 2005-08-20 9.5 10.25
4 1 2005-06-30 2005-10-15 9.6 10.30
5 1 2005-09-30 2005-10-15 10.5 10.37
6 1 2005-09-30 2005-11-10 11 10.53
7 1 2005-09-30 2006-02-20 10.75 10.45
8 1 2005-12-31 2006-02-13 12 10.9
9 1 2005-12-31 2006-02-20 11.5 10.71
10 1 2005-12-31 2006-05-10 11 10.59
11 1 2006-03-31 2006-04-20 8 9.96
12 1 2006-03-31 2006-05-10 8.25 9.9

我正在使用 Pandas 在 python 中执行此操作。我这样做的方法是在 id 和前 4 个季度将数据框与自身连接,并根据过去 4 个季度的 effdates 计算所有时期的新​​ effdates,然后我再次加入 id、datadate 和 effdate 并计算平均值。

keys["id"]
calc_df = df1.merge(df2,on=keys,how='left')
calc_df = calc_df.loc[
            (calc_df["datadate_x"] >= calc_df["datadate_y"])
            & (calc_df["datadate_y"] >= calc_df["datadate_x"] - pd.tseries.offsets.MonthEnd(n=9))
            & (calc_df["effdate_x"] <= calc_df["thrudate_y"])
            & (calc_df["thrudate_x"] >= calc_df["effdate_y"])
        ]
calc_df = calc_df.drop_duplicates().reset_index(drop=True)
grp_keys = keys + ["datadate_x"]
calc_df["effdate"] = calc_df[["effdate_x","effdate_y"]].max(axis=1)
calc_df = calc_df.sort_values(grp_keys + ["effdate"]).drop_duplicates(
            subset=grp_keys + ["effdate"],keep="first"
        )
calc_df = calc_df['id','datadate_x','effdate','value']

calc_df = calc_df.merge(df1,on=["id"],how="left")
calc_df = calc_df.loc[
            (calc_df["datadate_x"] >= calc_df["datadate"])
            & (
                calc_df["datadate"]
                >= calc_df["datadate_x"] - pd.tseries.offsets.MonthEnd(n=9)
            )
            & (calc_df["effdate_x"] <= calc_df["thrudate_y"])
            & (calc_df["thrudate_x"] >= calc_df["effdate_y"])
        ]

        
calc_df["MAvg"] = calc_df.groupby(["id","datadate_x","effdate_x"])["value"].transform(
            lambda s: s.mean(skipna=False)
        )

这有效,但当我在完整数据集上运行它时非常慢,该数据集从 2000 年到最近一个季度(大约 500K 行)有大约 2000 个不同的 ID 和数据日期,我必须计算不同字段的移动平均值视窗。所以我想看看有没有有效的方法来做到这一点。

解决方法

目前尚不清楚该问题的答案是什么,因为您只要求“更好”,而您没有指明您希望此改进位于哪个轴上.

所以我会为您提供更好的可读性方面的内容。这可能有助于其他人找到其他方向的改进:

鉴于 csv data.csv

datadate,effdate,value
2005-03-31,2005-04-15,10
2005-03-31,2005-05-30,11
2005-06-30,2005-07-15,9
2005-06-30,2005-08-20,9.5
2005-06-30,2005-10-15,9.6
2005-09-30,10.5
2005-09-30,2005-11-10,11
2005-09-30,2006-02-20,10.75
2005-12-31,2006-02-13,12
2005-12-31,11.5
2005-12-31,2006-05-10,11
2006-03-31,2006-04-20,8
2006-03-31,8.25

您可以通过执行以下操作获得相同的结果:

import pandas as pd

data = pd.read_csv('data.csv').sort_values(by=["effdate"])


def moving_avg(df,quarters):
    df = df[
        df.index <= df.last_valid_index
    ].drop_duplicates(subset="datadate",keep="last").tail(quarters)
    return df["value"].sum() / df["value"].count()


print(data.assign(MAvg=[moving_avg(d,4) for d in data.expanding()]).sort_index())

这提供:

      datadate     effdate  value       MAvg
0   2005-03-31  2005-04-15  10.00  10.000000
1   2005-03-31  2005-05-30  11.00  11.000000
2   2005-06-30  2005-07-15   9.00  10.000000
3   2005-06-30  2005-08-20   9.50  10.250000
4   2005-06-30  2005-10-15   9.60  10.300000
5   2005-09-30  2005-10-15  10.50  10.366667
6   2005-09-30  2005-11-10  11.00  10.533333
7   2005-09-30  2006-02-20  10.75  10.450000
8   2005-12-31  2006-02-13  12.00  10.900000
9   2005-12-31  2006-02-20  11.50  10.712500
10  2005-12-31  2006-05-10  11.00  10.587500
11  2006-03-31  2006-04-20   8.00   9.962500
12  2006-03-31  2006-05-10   8.25   9.900000

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。