如何用Matplotlib配置时间序列多子图并解决绘图异常问题
解决Matplotlib子图绘图异常问题:分离Original序列与预测序列
我看了你这段代码,问题主要出在子图绘图时没有指定目标坐标轴,还有一些小的逻辑和语法错误,我来帮你修正并优化:
首先,梳理你代码里的几个关键问题:
- 你给
ax1重新赋值了df_data['Data'].plot(...)的返回值,这会覆盖掉plt.subplots创建的原始坐标轴对象,导致第一个子图根本没被使用 train和test的划分完全相同,等于没拆分数据集,失去了训练和测试的意义- 代码里有笔误:
df_matric['Data'].index.freq = 'MS'应该是df_data,不然会报变量未定义错误 - 预测的时间范围
period用字符串的话,容易和索引格式不匹配,直接用时间戳更稳妥
修正后的完整代码:
import pandas as pd import numpy as np import matplotlib.pyplot as plt from statsmodels.tsa.holtwinters import ExponentialSmoothing # Data loading & preprocessing data = pd.read_csv('setpoints.csv', parse_dates=['date'], index_col=['date']) df_data = pd.DataFrame(data, columns=['Data']) # 修正笔误,设置时间序列频率 df_data['Data'].index.freq = 'MS' # 正确划分训练集和测试集:前24个月作为训练,后12个月作为测试 train = df_data['Data'].iloc[:24] test = df_data['Data'].iloc[24:] # 训练Holt-Winters模型 model = ExponentialSmoothing(train, trend='mul', seasonal='add', seasonal_periods=12).fit() # 直接用测试集的索引作为预测范围,更准确 pred = model.predict(start=test.index[0], end=test.index[-1]) # 创建子图 fig, (ax1, ax2) = plt.subplots(2, figsize=(10,8), sharex=True) fig.suptitle('Submissions Data', fontsize=14) # 上方子图:仅绘制Original序列 df_data['Data'].plot(ax=ax1, label='Original', color='blue') ax1.set_ylim(0, 300000) ax1.set_ylabel('Submissions') ax1.legend(loc='best') # 下方子图:绘制Train、Test和预测值 train.plot(ax=ax2, label='Train', color='green') test.plot(ax=ax2, label='Test', color='orange') pred.plot(ax=ax2, label='Holt-Winters Prediction', color='red') ax2.set_xlabel('Date') ax2.set_ylabel('Submissions') ax2.legend(loc='best') # 调整子图间距,避免标题和标签重叠 plt.tight_layout() plt.subplots_adjust(top=0.92) plt.show()
关键修改说明:
- 指定绘图的目标坐标轴:所有
plot方法都加上ax=ax1或ax=ax2参数,确保每个序列绘制到对应的子图上,这是解决你所有序列都跑到下方子图的核心 - 正确划分数据集:用
iloc拆分训练集和测试集,让训练和测试逻辑合理 - 修正笔误:把
df_matric改成df_data,避免运行报错 - 优化预测范围:直接用测试集的索引作为预测起止,比手动写字符串更准确,避免格式不匹配问题
- 添加布局优化:用
tight_layout()和subplots_adjust()避免标题和子图元素重叠,提升可视化效果
这样修改后,就能实现你想要的效果:上方子图只显示完整的Original序列,下方子图展示训练集、测试集和Holt-Winters的预测结果。
内容的提问来源于stack exchange,提问作者srgam
相关产品推荐
相关产品推荐

