广义加性模型(GAM)在时间序列预测中是一种强大的工具,能够捕捉数据中的非线性趋势和复杂模式。本文将详细介绍如何在Python中实现广义加性模型进行时间序列预测,包括所需的库、数据预处理、模型构建、训练以及评估。
如果这篇文章对你有一点点的帮助,欢迎点赞、关注、收藏、转发、评论哦!
我也会在微信公众号“智识小站”坚持分享更多内容,以期记录成长、普及技术、造福后来者!
一、GAM在时间序列中的应用
时间序列预测旨在利用历史数据预测未来的趋势。GAM通过将时间变量及其他潜在影响因素的平滑函数引入模型,能够有效捕捉时间序列中的非线性趋势、季节性变化和其他复杂模式。其加性结构使得每个预测变量的影响独立且可解释,这对于理解时间序列数据的内部机制尤为重要。
二、Python中实现GAM的主要库
在Python中,有几种库可以用于实现GAM:
- pyGAM:一个功能强大的库,支持各种光滑函数和模型验证方法。
- statsmodels:虽然主要用于传统统计模型,但也支持部分GAM功能。
- scikit-learn:通过扩展和自定义,可以实现类似GAM的加性模型。
本文将主要使用pyGAM库,因为它专门针对GAM进行了优化,且易于使用。
安装pyGAM
首先,确保你已经安装了pyGAM。如果尚未安装,可以使用以下命令进行安装:
pip install pygam
三、GAM时间序列预测的实现步骤
1. 数据准备与预处理
时间序列预测通常依赖于历史数据。以下是一个基本的数据预处理流程:
- 导入必要的库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pygam import GAM, s
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
- 加载数据
假设我们使用的是一个包含日期和相应数值的时间序列数据集。
# 示例:加载时间序列数据
# data = pd.read_csv('time_series_data.csv', parse_dates=['date'])
# data.set_index('date', inplace=True)
# 为了便于说明,这里使用仿真数据
def generate_time_series(start_date='2020-01-01', periods=1000, freq='D', seed=42):
"""
生成模拟的时间序列数据,包括趋势、季节性和噪声。
参数:
- start_date: 开始日期
- periods: 数据点数
- freq: 数据频率(如'D'表示日)
- seed: 随机种子
返回:
- DataFrame包含日期和数值
"""
np.random.seed(seed)
dates = pd.date_range(start=start_date, periods=periods, freq=freq)
# 趋势成分
trend = np.linspace(0, 10, periods)
# 季节性成分(年季节性和周季节性)
seasonal_yearly = 5 * np.sin(2 * np.pi * dates.dayofyear / 365.25)
seasonal_weekly = 2 * np.sin(2 * np.pi * dates.dayofweek / 7)
# 噪声
noise = np.random.normal(0, 1, periods)
# 总体数值
value = trend + seasonal_yearly + seasonal_weekly + noise
data = pd.DataFrame({'date': dates, 'value': value})
return data
# 生成模拟数据
data = generate_time_series()
# 设置日期为索引
data.set_index('date', inplace=True)
# 可视化模拟数据
plt.figure(figsize=(14,6))
plt.plot(data.index, data['value'], label='模拟值')
plt.title('模拟时间序列数据')
plt.xlabel('日期')
plt.ylabel('值')
plt.legend()
plt.show()
- 特征工程
对于时间序列数据,常见的特征包括时间变量(如年、月、日、星期)、滞后变量、滚动统计量等。
# 提取时间特征
data['year'] = data.index.year
data['month'] = data.index.month
data['day'] = data.index.day
data['weekday'] = data.index.weekday
# 创建滞后变量,例如滞后1期和滞后2期
data['lag1'] = data['value'].shift(1)
data['lag2'] = data['value'].shift(2)
# 删除缺失值
data.dropna(inplace=True)
2. 数据分割
将数据分为训练集和测试集,以评估模型性能。
# 定义特征和目标变量
X = data[['year', 'month', 'day', 'weekday', 'lag1', 'lag2']]
y = data['value']
# 划分训练集和测试集(例如,80%训练,20%测试)
split_ratio = 0.8
split_point = int(len(data) * split_ratio)
X_train, X_test = X.iloc[:split_point], X.iloc[split_point:]
y_train, y_test = y.iloc[:split_point], y.iloc[split_point:]
3. 构建和训练GAM模型
使用pyGAM构建加性模型。可以为每个特征指定不同的光滑函数。
# 定义GAM模型
gam = GAM(
s(0) + # year
s(1) + # month
s(2) + # day
s(3) + # weekday
s(4) + # lag1
s(5) # lag2
).fit(X_train, y_train)
# 或者使用网格搜索自动选择最佳光滑参数
# gam = GAM(
# s(0) + s(1) + s(2) + s(3) + s(4) + s(5),
# fit_intercept=True
# ).gridsearch(X_train, y_train)
说明:
s(i)
表示对第i
个特征应用样条光滑函数。- 你也可以根据需要调整每个特征的光滑度或选择其他类型的函数。
4. 模型预测与评估
# 进行预测
y_pred = gam.predict(X_test)
# 评估模型性能
mse = mean_squared_error(y_test, y_pred)
print(f'均方误差 (MSE): {mse:.4f}')
# 可视化预测结果
plt.figure(figsize=(14,6))
plt.plot(y_test.index, y_test.values, label='真实值')
plt.plot(y_test.index, y_pred, label='预测值')
plt.title('GAM 时间序列预测')
plt.xlabel('日期')
plt.ylabel('值')
plt.legend()
plt.show()
5. 模型解释与可视化
pyGAM提供了方便的图形化工具来理解模型的各个部分。
# 绘制各个特征的光滑函数
fig, axs = plt.subplots(3, 2, figsize=(15, 15))
titles = ['年 (Year)', '月 (Month)', '日 (Day)', '星期 (Weekday)', '滞后1 (Lag1)', '滞后2 (Lag2)']
for i, ax in enumerate(axs.flatten()):
if i < len(X.columns):
XX = gam.generate_X_grid(term=i)
ax.plot(XX[:, i], gam.partial_dependence(term=i, X=XX))
ax.plot(XX[:, i], gam.partial_dependence(term=i, X=XX, width=0.95)[1], c='r', ls='--')
ax.set_title(f'{titles[i]} 的光滑函数')
ax.set_xlabel(titles[i])
ax.set_ylabel('部分依赖')
else:
ax.axis('off')
plt.tight_layout()
plt.show()
说明:
- 每个子图展示了对应特征对预测结果的影响,便于理解和解释模型。
四、运行结果
运行上述代码后,你将获得以下结果:
- 模拟时间序列图:展示生成的时间序列数据,包含趋势、季节性和噪声。
- 均方误差 (MSE):模型预测的准确性指标,数值越低表示模型表现越好。(本案例中均方误差 (MSE): 1.1201)
- 预测结果对比图:真实值与预测值的对比,可视化模型的预测效果。
- 光滑函数图:展示各个特征对预测结果的影响,帮助理解模型的工作机制。
五、完整示例代码
以下是一个完整的示例代码,整合了上述所有步骤:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pygam import GAM, s
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
# 1. 数据加载
data = pd.read_csv('time_series_data.csv', parse_dates=['date'])
data.set_index('date', inplace=True)
# 2. 特征工程
data['year'] = data.index.year
data['month'] = data.index.month
data['day'] = data.index.day
data['weekday'] = data.index.weekday
data['lag1'] = data['value'].shift(1)
data['lag2'] = data['value'].shift(2)
data.dropna(inplace=True)
# 3. 数据分割
X = data[['year', 'month', 'day', 'weekday', 'lag1', 'lag2']]
y = data['value']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False)
# 4. 模型训练
gam = GAM(s(0) + s(1) + s(2) + s(3) + s(4) + s(5)).fit(X_train, y_train)
# 5. 预测与评估
y_pred = gam.predict(X_test)
mse = mean_squared_error(y_test, y_pred)
print(f'Mean Squared Error: {mse}')
# 6. 可视化结果
plt.figure(figsize=(12,6))
plt.plot(y_test.values, label='真实值')
plt.plot(y_pred, label='预测值')
plt.legend()
plt.title('GAM 时间序列预测')
plt.show()
# 7. 绘制光滑函数
fig, axs = plt.subplots(3, 2, figsize=(15, 15))
titles = ['Year', 'Month', 'Day', 'Weekday', 'Lag1', 'Lag2']
for i, ax in enumerate(axs.flatten()):
if i < len(X.columns):
XX = gam.generate_X_grid(term=i)
ax.plot(XX[:, i], gam.partial_dependence(term=i, X=XX))
ax.plot(XX[:, i], gam.partial_dependence(term=i, X=XX, width=0.95)[1], c='r', ls='--')
ax.set_title(titles[i])
else:
ax.axis('off')
plt.tight_layout()
plt.show()
六、注意事项与建议
- 数据质量:确保时间序列数据的连续性和完整性,处理缺失值和异常值对模型性能至关重要。
- 特征选择:选择合适的特征能够显著提升模型的预测能力。可以通过特征重要性评估或领域知识进行选择。
- 过拟合与欠拟合:通过交叉验证和调整光滑参数防止模型过拟合或欠拟合。
- 模型解释:利用GAM的可解释性,深入理解各个特征对预测结果的影响,尤其在业务决策中具有重要价值。
七、结论
广义加性模型在时间序列预测中提供了一种灵活且可解释的方法,能够有效捕捉数据中的非线性关系和复杂模式。通过Python中的pyGAM库,用户可以方便地构建、训练和评估GAM模型,以实现精准的时间序列预测。结合适当的特征工程和模型优化策略,GAM能够在实际应用中发挥出色的性能。