通俗易懂之广义加性模型GAM时序预测(pyGAM)

广义加性模型(GAM)在时间序列预测中是一种强大的工具,能够捕捉数据中的非线性趋势和复杂模式。本文将详细介绍如何在Python中实现广义加性模型进行时间序列预测,包括所需的库、数据预处理、模型构建、训练以及评估。

如果这篇文章对你有一点点的帮助,欢迎点赞、关注、收藏、转发、评论哦!
我也会在微信公众号“智识小站”坚持分享更多内容,以期记录成长、普及技术、造福后来者!

一、GAM在时间序列中的应用

时间序列预测旨在利用历史数据预测未来的趋势。GAM通过将时间变量及其他潜在影响因素的平滑函数引入模型,能够有效捕捉时间序列中的非线性趋势、季节性变化和其他复杂模式。其加性结构使得每个预测变量的影响独立且可解释,这对于理解时间序列数据的内部机制尤为重要。

二、Python中实现GAM的主要库

在Python中,有几种库可以用于实现GAM:

  1. pyGAM:一个功能强大的库,支持各种光滑函数和模型验证方法。
  2. statsmodels:虽然主要用于传统统计模型,但也支持部分GAM功能。
  3. 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()

说明

  • 每个子图展示了对应特征对预测结果的影响,便于理解和解释模型。

四、运行结果

运行上述代码后,你将获得以下结果:

  1. 模拟时间序列图:展示生成的时间序列数据,包含趋势、季节性和噪声。
    在这里插入图片描述
  2. 均方误差 (MSE):模型预测的准确性指标,数值越低表示模型表现越好。(本案例中均方误差 (MSE): 1.1201)
  3. 预测结果对比图:真实值与预测值的对比,可视化模型的预测效果。在这里插入图片描述
  4. 光滑函数图:展示各个特征对预测结果的影响,帮助理解模型的工作机制。在这里插入图片描述

五、完整示例代码

以下是一个完整的示例代码,整合了上述所有步骤:

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()

六、注意事项与建议

  1. 数据质量:确保时间序列数据的连续性和完整性,处理缺失值和异常值对模型性能至关重要。
  2. 特征选择:选择合适的特征能够显著提升模型的预测能力。可以通过特征重要性评估或领域知识进行选择。
  3. 过拟合与欠拟合:通过交叉验证和调整光滑参数防止模型过拟合或欠拟合。
  4. 模型解释:利用GAM的可解释性,深入理解各个特征对预测结果的影响,尤其在业务决策中具有重要价值。

七、结论

广义加性模型在时间序列预测中提供了一种灵活且可解释的方法,能够有效捕捉数据中的非线性关系和复杂模式。通过Python中的pyGAM库,用户可以方便地构建、训练和评估GAM模型,以实现精准的时间序列预测。结合适当的特征工程和模型优化策略,GAM能够在实际应用中发挥出色的性能。

### MATLAB 中使用广义模型 (GAM) 尽管 R 语言在处理广义模型(Generalized Additive Models, GAM)方面更为成熟,提供了 `gam` 和 `mgcv` 等专用包[^3],但在 MATLAB 中也可以通过特定工具箱实现类似的建模功能。 #### 工具需求 要在 MATLAB 中构建和分析 GAM 模型,通常需要以下工具箱的支持: - **Statistics and Machine Learning Toolbox**: 提供了基础统计建模能力以及机器学习算法支持。 - **Curve Fitting Toolbox**: 可用于拟合平滑样条和其他非线函数[^4]。 虽然 MATLAB 的内置功能可能不如 R 那么全面,但它仍能通过组合多项式回归、局部样条和平滑样条等功能来逼近 GAM 建模的效果。 --- #### 示例代码 以下是基于 MATLAB 实现的一个简单 GAM 模型示例: ```matlab % 数据准备 rng('default'); % 设置随机数种子以便结果可重复 n = 200; x1 = linspace(0, 10, n)'; x2 = rand(n, 1); y = sin(x1) + exp(-abs(x2)) + normrnd(0, 0.1, n, 1); % 添噪声的目标变量 % 构造平滑基底 smoothX1 = fit(x1, y, 'smoothingspline'); smoothX2 = fit(x2, y, 'lowess'); % 绘制单变量平滑效应 figure; subplot(2, 1, 1); plot(smoothX1, 'r-', x1, smoothX1(x1), 'b.'); title('Smooth Effect of X1 on Y'); xlabel('X1'); ylabel('Fitted Value'); subplot(2, 1, 2); plot(smoothX2, 'r-', x2, smoothX2(x2), 'b.'); title('Lowess Smoothing Effect of X2 on Y'); xlabel('X2'); ylabel('Fitted Value'); % 结合多个平滑器进行预测 predictedY = smoothX1(x1) + smoothX2(x2); % 对比实际值与预测值 figure; scatter(y, predictedY); hold on; plot([min(y), max(y)], [min(y), max(y)], 'k--', 'LineWidth', 1.5); xlabel('Actual Values'); ylabel('Predicted Values'); title('Comparison Between Actual and Predicted Values'); legend('Data Points', 'Perfect Fit Line'); ``` 上述代码展示了如何利用 MATLAB 的平滑样条 (`fit`) 函数分别对两个自变量 \(x_1\) 和 \(x_2\) 进行独立的平滑操作,并最终将它们的结果叠起来形成一个简单的 GAM 模型[^4]。 --- #### 关键点说明 1. **平滑样条** 是 GAM 的核心组成部分之一,在 MATLAB 中可通过 `fit` 函数轻松实现。它允许用户指定不同的平滑程度以适应数据特。 2. 虽然 MATLAB 不直接提供类似于 R 的 `gam` 或 `mgcv` 包的功能,但其灵活使得我们可以手动构造 GAM 模型并调整各个分量的复杂度。 3. 如果希望进一步提升模型能,可以考虑引入交叉验证机制来优化超参数设置,例如平滑参数的选择[^4]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智识小站

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值