如何高效计算带日期索引DataFrame的WoW、MoM、YoY收益率
高效计算时间序列的周/月/同比收益率
直接用pandas的向量化操作就能搞定,完全不用循环,效率高得多。以下是针对你的需求的具体实现:
先明确前提
确保你的DataFrame索引是datetime类型,如果不是先转换:df.index = pd.to_datetime(df.index);另外建议先按时间升序排序:df = df.sort_index(),避免后续计算出错。
1. 周环比(WoW)
分两种常见场景:
场景A:基于前5个交易日(和你的示例逻辑一致)
直接用shift(5)取前5个交易日的价格:
df['WoW'] = (df['CTH3 Comdty'] / df['CTH3 Comdty'].shift(5) - 1) * 100
但这种方法在遇到节假日导致一周交易日不足5天时,会取更早的日期,可能偏离“周环比”的常规含义。
场景B:基于上周同一工作日(更符合通用周环比逻辑)
用pd.DateOffset生成上周同日的日期,再通过reindex+ffill获取对应价格:
# 生成每个日期往前推1周的日期 prev_week_dates = df.index - pd.DateOffset(weeks=1) # 匹配上周价格,无数据则向前填充 df['prev_week_price'] = df['CTH3 Comdty'].reindex(prev_week_dates, method='ffill') # 计算收益率 df['WoW'] = (df['CTH3 Comdty'] / df['prev_week_price'] - 1) * 100
你的示例中2022-11-28的上周同日是2022-11-21,刚好有数据,计算结果和你的示例一致:≈-1.04%。
2. 月环比(MoM)
同样用DateOffset生成1个月前的日期,结合reindex+ffill处理非交易日:
# 生成1个月前的对应日期 prev_month_dates = df.index - pd.DateOffset(months=1) # 获取对应价格,无数据则向前填充 df['prev_month_price'] = df['CTH3 Comdty'].reindex(prev_month_dates, method='ffill') # 计算月环比收益率 df['MoM'] = (df['CTH3 Comdty'] / df['prev_month_price'] - 1) * 100
3. 同比(YoY)
逻辑和月环比完全一致,只是时间跨度改为1年:
# 生成1年前的对应日期 prev_year_dates = df.index - pd.DateOffset(years=1) # 获取对应价格,无数据则向前填充 df['prev_year_price'] = df['CTH3 Comdty'].reindex(prev_year_dates, method='ffill') # 计算同比收益率 df['YoY'] = (df['CTH3 Comdty'] / df['prev_year_price'] - 1) * 100
为什么这种方法更高效?
这些都是pandas内部优化的向量化操作,避免了Python循环的开销,尤其是数据量较大(比如几万条以上)时,速度会比循环+loc快几个数量级,代码也更简洁易维护。
内容的提问来源于stack exchange,提问作者Haikal Yeo
相关产品推荐
相关产品推荐

