3、季节性指数计算:季节性指数的定义、计算公式、Python实现方法
各位同学,咱们今天聊一个硬核话题——季节性指数。
很多做农产品交易的朋友,一提到“季节性”就两眼放光。但说实话,光看历史价格涨跌图,那叫“凭感觉”。真正要量化分析,你得有个标准尺子。这把尺子,就是季节性指数。
我刚开始做量化研究那会儿,也犯过傻。看着玉米价格每年8月都涨,就以为稳了。结果有一年8月暴跌,亏得我差点怀疑人生。后来才明白——季节性指数不是简单的“涨跌统计”,它背后有一套严谨的计算逻辑。
今天,我就把这套逻辑掰开揉碎了讲给你听。
3.1 什么是季节性指数?
季节性指数,说白了就是衡量某个时间段(比如某个月份)的价格,相对于全年平均水平的偏离程度。
举个例子:
- 如果某个月份的季节性指数是1.2,意味着这个月的价格比全年平均水平高出20%。
- 如果是0.8,那就是低了20%。
你想想看,这不就是一把“标尺”吗?有了它,你就能一眼看出:哪个月份是“旺季”,哪个月份是“淡季”。
核心定义:季节性指数 = 某时期(如某月)的平均价格 ÷ 全年总平均价格
通常以1.0为基准线。大于1.0表示高于平均水平,小于1.0表示低于平均水平。
3.2 计算公式详解
公式其实不复杂,但细节决定成败。我习惯用三步法来计算:
第一步:计算各年各月的价格平均值
假设你有N年的数据,每年12个月。先算出每个月的多年平均值。
公式:
月平均值(Month_i) = (第1年Month_i价格 + 第2年Month_i价格 + ... + 第N年Month_i价格) / N
第二步:计算全年总平均值
把所有月份的平均值再平均一次:
全年总平均值 = (月平均值(1月) + 月平均值(2月) + ... + 月平均值(12月)) / 12
第三步:计算季节性指数
季节性指数(Month_i) = 月平均值(Month_i) / 全年总平均值
我的小习惯:在实际项目中,我通常会把季节性指数乘以100,变成百分比形式。比如1.2写成120%。这样更直观,汇报时领导也爱看。
3.3 一个完整的计算示例
光讲公式太枯燥。咱们拿大豆来举个真实例子。
假设我有3年的大豆月度价格数据(单位:元/吨):
| 月份 | 2021年 | 2022年 | 2023年 | 月平均值 | 季节性指数 |
|---|---|---|---|---|---|
| 1月 | 3800 | 4100 | 3950 | 3950 | 0.98 |
| 2月 | 3850 | 4150 | 4000 | 4000 | 0.99 |
| 3月 | 3900 | 4200 | 4050 | 4050 | 1.00 |
| 4月 | 3950 | 4250 | 4100 | 4100 | 1.01 |
| 5月 | 4000 | 4300 | 4150 | 4150 | 1.03 |
| 6月 | 4050 | 4350 | 4200 | 4200 | 1.04 |
| 7月 | 4100 | 4400 | 4250 | 4250 | 1.05 |
| 8月 | 4150 | 4450 | 4300 | 4300 | 1.06 |
| 9月 | 4000 | 4300 | 4100 | 4133 | 1.02 |
| 10月 | 3850 | 4150 | 3950 | 3983 | 0.98 |
| 11月 | 3750 | 4050 | 3850 | 3883 | 0.96 |
| 12月 | 3700 | 4000 | 3800 | 3833 | 0.95 |
计算过程:
- 先算全年总平均值 = (3950+4000+4050+4100+4150+4200+4250+4300+4133+3983+3883+3833) / 12 ≈ 4036
- 然后每个月的平均值除以4036,就得到季节性指数
你看,8月份的季节性指数是1.06,说明8月是大豆的传统旺季。12月只有0.95,是淡季。这个规律,在农产品交易中非常实用。
我曾经踩过的坑:有一年我直接用原始价格计算季节性指数,结果发现指数波动特别大。后来排查才发现——那一年发生了严重的干旱,价格异常高。如果不剔除这种“极端事件”,季节性指数就会被带偏。
所以我的建议是:计算前,先做数据清洗,剔除异常年份。或者用中位数代替平均值,抗干扰能力更强。
3.4 Python实现方法
理论讲完了,咱们上代码。我个人习惯用Pandas来处理,因为它对时间序列数据支持得特别好。
下面是一个完整的实现:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 示例数据:假设df是包含日期和价格的DataFrame
# 日期格式:'2021-01-01', 价格:float
def calculate_seasonal_index(df, price_col='price', date_col='date'):
"""
计算季节性指数
参数:
df: DataFrame,包含日期和价格
price_col: 价格列名
date_col: 日期列名
返回:
seasonal_index: Series,索引为月份,值为季节性指数
"""
# 1. 提取月份
df['month'] = pd.to_datetime(df[date_col]).dt.month
# 2. 计算各年各月的平均值
monthly_avg = df.groupby('month')[price_col].mean()
# 3. 计算全年总平均值
overall_avg = monthly_avg.mean()
# 4. 计算季节性指数
seasonal_index = monthly_avg / overall_avg
return seasonal_index
# 使用示例
# df = pd.read_csv('soybean_prices.csv')
# si = calculate_seasonal_index(df)
# print(si)
# 可视化
def plot_seasonal_index(seasonal_index):
plt.figure(figsize=(10, 6))
plt.plot(seasonal_index.index, seasonal_index.values,
marker='o', linewidth=2, markersize=8)
plt.axhline(y=1.0, color='red', linestyle='--', alpha=0.7)
plt.title('大豆季节性指数', fontsize=14)
plt.xlabel('月份', fontsize=12)
plt.ylabel('季节性指数', fontsize=12)
plt.grid(True, alpha=0.3)
plt.xticks(range(1, 13))
plt.show()
# 调用
# plot_seasonal_index(si)
进阶技巧:如果你觉得平均值不够稳健,可以用中位数代替。代码只需要改一行:
monthly_avg = df.groupby('month')[price_col].median()
中位数对异常值不敏感,适合处理有极端行情的年份。
3.5 核心逻辑流程图
为了让你更直观地理解整个计算流程,我画了一张图:
3.6 实际应用中的注意事项
嗯,这里我要多说几句。季节性指数看着简单,但用不好容易翻车。
- 数据长度要够:我建议至少用5年以上的数据。3年太短,偶然性太大。10年最佳。
- 注意结构性变化:如果某一年国家出台了新的农业政策,或者发生了重大疫情,那这一年的数据可能就不具备参考价值了。
- 季节性指数不是预测工具:它只是告诉你“历史上这个月份通常是什么样子”。但市场是活的,供需关系、天气、政策都会改变规律。
- 结合其他指标使用:我个人的做法是,把季节性指数作为辅助判断,再结合库存数据、天气模型、资金流向等,综合决策。
总结一句话:季节性指数是农产品量化分析的“基本功”。它不复杂,但很实用。掌握了它,你就有了一个客观的标尺,不再凭感觉做交易。
好了,这一节的内容就到这里。代码我已经贴出来了,你回去跑一跑,看看自己关注的品种是什么规律。有什么问题,咱们随时交流。