4. 现金流季节性分解
任务说明
本案例针对企业月度现金流序列,使用STL(Seasonal-Trend decomposition using LOESS)方法将其分解为趋势、季节和残差三个成分。分解结果可用于识别现金流的季节性规律、判断长期趋势方向,以及通过残差成分发现异常月份。案例使用Python的statsmodels库实现,输入为一份包含12个月以上连续月度现金流数据的CSV文件。
环境与依赖
需要安装pandas、statsmodels、matplotlib。若使用X13-ARIMA需额外安装statsmodels的X13后端并配置X13AS二进制路径,本案例以STL为主实现。
数据准备
创建输入文件cash_flow.csv,包含两列:month(格式YYYY-MM)和amount(万元)。以下为示例数据(24个月),可直接复制使用:
month,amount
2022-01,320
2022-02,285
2022-03,310
2022-04,298
2022-05,335
2022-06,352
2022-07,340
2022-08,365
2022-09,348
2022-10,372
2022-11,358
2022-12,390
2023-01,355
2023-02,318
2023-03,342
2023-04,330
2023-05,368
2023-06,385
2023-07,372
2023-08,398
2023-09,380
2023-10,405
2023-11,392
2023-12,428
完整实现代码
将以下代码保存为stl_decompose.py:
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.tsa.seasonal import STL
# 读取数据
df = pd.read_csv('cash_flow.csv')
df['month'] = pd.to_datetime(df['month'])
df.set_index('month', inplace=True)
# 确保按月频率且无缺失
ts = df['amount'].asfreq('MS')
# STL分解(周期为12个月)
stl = STL(ts, period=12, robust=True)
result = stl.fit()
# 输出分解结果
components = pd.DataFrame({
'observed': ts,
'trend': result.trend,
'seasonal': result.seasonal,
'resid': result.resid
})
print("分解结果(最近6个月):")
print(components.tail(6).round(2))
# 残差统计
print("\n残差标准差:", round(result.resid.std(), 2))
print("残差均值:", round(result.resid.mean(), 4))
# 可视化
fig = result.plot()
fig.set_size_inches(10, 8)
plt.tight_layout()
plt.savefig('stl_result.png', dpi=150)
print("\n图表已保存为 stl_result.png")
运行方式
pip install pandas statsmodels matplotlib
python stl_decompose.py
验证方法与判定标准
运行后观察以下输出以确认分解成功:
- 控制台打印最近6个月的分解结果,包含observed、trend、seasonal、resid四列数值,且resid数值明显小于原始序列量级(示例数据中残差值通常小于15);
- 残差均值接近0(示例中应小于0.5),残差标准差在5~15之间;
- 当前目录生成
stl_result.png,图中包含4个子图:原始序列、趋势成分(平滑上升曲线)、季节成分(呈周期性波动,每年同月数值一致)、残差(围绕0轴随机波动)。
若使用自己的数据,需保证至少24个月连续月度数据且无缺失值,否则STL无法正确估计12个月季节周期。判定通过标准为:趋势成分呈现合理单调或平滑变化,季节成分呈现12个月固定周期形态,残差无显著趋势且均值接近0。
常见问题
- 数据不足24个月:STL要求至少2个完整季节周期,否则会报错或季节成分失真。解决方法是增加数据长度或改用周期为6的
period=6参数。 - 缺失值报错:STL不接受NaN,需先通过
ts.interpolate()或ts.fillna(method='ffill')处理。 - 季节成分每年同月不完全相等:STL允许季节成分随时间缓慢变化,这是正常现象,与X13-ARIMA的固定季节成分不同。
上图展示了STL分解的核心逻辑:原始序列被拆分为三个可解释成分,其中季节成分呈现以12个月为周期的重复形态,残差则围绕零值波动。实际应用中,可进一步对残差设定阈值(如±2倍标准差)来自动标记现金流异常月份。