突破 XGBoost!时间序列预测 !!

科技   2024-11-25 10:54   安徽  

哈喽,我是cos大壮!~

今儿再来和大家聊一个关于XGBoost的案例,未来销量的预测。

在销售预测中,准确预测未来的销量对库存管理、产品生产以及运营决策都有重大意义。时间序列预测主要基于过去的历史数据来推断未来的销售情况,传统的时间序列模型如ARIMA、SARIMA等,虽然能够捕捉数据中的时序规律,但在处理多维特征和复杂模式时表现一般。而XGBoost作为一种集成学习方法,可以同时处理非线性问题和多维特征,在时间序列预测中具有一定的优势。

咱们今天的案例会通过XGBoost结合时间序列模型,为销售预测问题提供一个完整的解决方案。我们将通过虚拟销售数据集,结合实际业务中的多维特征(如天气、促销、节假日等),使用XGBoost和PyTorch来进行时间序列预测,展示从数据生成、预处理、特征工程、模型构建、可视化到模型优化的完整流程。

1. 问题定义

假设我们有一个零售公司,该公司的目标是预测未来7天的销售量

数据集包括以下几列:

  • 日期:具体的销售日期
  • 销售量(Sales):每天的销售量数据
  • 天气(Weather):当天的天气情况(如晴天、多云、雨天等)
  • 节假日(Holiday):是否为节假日(1表示是,0表示否)
  • 促销(Promotion):是否有促销活动(1表示有,0表示无)

目标是利用历史数据构建一个模型,能够通过学习销售量的历史规律,结合天气、促销、节假日等因素,预测未来一段时间内的销售量

可能会遇到的业务挑战

  • 非线性因素:如促销活动对销售量的影响具有显著的非线性关系,而天气等因素的影响可能更加复杂。
  • 时间依赖性:销售数据具有显著的时间依赖性,可能存在周期性、趋势性和季节性规律。
  • 多维特征:除了时间序列本身的特征外,还有如天气、促销、节假日等外部因素的影响,如何有效融合这些信息是模型设计中的一个关键问题。

2. XGBoost与时间序列模型结合

XGBoost 是一种基于梯度提升决策树(GBDT)的集成算法。它通过逐步训练一系列弱学习器(决策树),并对每个弱学习器进行加权求和来形成最终的预测结果。与其他回归模型相比,XGBoost在面对高维特征和非线性关系时表现较好。此外,XGBoost通过加权和正则化手段,能有效避免过拟合问题。

XGBoost的目标函数可以表示为:

其中:

  • :是损失函数(如均方误差MSE),用于衡量预测值与真实值之间的误差。
  • :是正则化项,用于控制模型的复杂度,防止过拟合。
  • :表示树的数量。

每一轮训练,XGBoost都会构建一棵新的树来修正上一棵树的残差,最终模型是所有树预测结果的加权和。

XGBoost 结合时间序列模型

在时间序列问题中,传统的模型(如ARIMA)假设数据是平稳的,并基于过去的时序模式进行预测。而在XGBoost中,我们通过生成滞后特征将时间序列问题转化为一个标准的回归问题。

假设我们要预测第  天的销售量 ,我们可以用前几天的销售量以及其他因素(如天气、促销、节假日)作为特征:

其中:

  •  是过去  天的销售量,即滞后特征。
  •  是其他时间相关特征(如天气、节假日、促销)。
  •  是误差项。

通过这种方式,我们将时间序列问题转化为一个回归问题,并利用XGBoost的强大性能来进行预测。

时间序列中的窗口特征

在处理时间序列问题时,常用的特征生成方式包括滞后特征(Lag Features) 和 滚动窗口特征(Rolling Window Features)

  1. 滞后特征:即使用过去  天的销售量数据作为当前时刻的特征。例如,
  2. 滚动窗口特征:计算过去一段时间内的销售量统计特征,如均值、方差等。例如, 表示前7天的平均销售量。

3. 模型原理

为了进一步细化,假设我们定义的时间序列回归模型的目标是根据前  天的销售数据以及其他特征预测第 天的销售量:

其中:

  •  是第  天的销售量。
  •  是前  天的滞后销售数据。
  •  是第  天的其他特征(如天气、节假日、促销)。
  •  是滞后特征的权重。
  •  是其他特征的权重。
  •  是误差项。

在XGBoost中,模型通过不断迭代构建弱学习器(决策树)来拟合销售数据和其他特征的关系,预测值是所有树预测结果的加权和:

其中:

  •  是树的数量。
  •  是每棵树的权重。
  •  是第  棵树在特征  上的预测结果。

4. 销售数据集

这里,我们生成一个虚拟的销售数据集来模拟真实的销售情况。

该数据集将包含以下特征:

  • 日期(Date)
  • 销售量(Sales)
  • 天气(Weather)
  • 节假日(Holiday)
  • 促销(Promotion)

我们假设天气、节假日和促销都会影响每天的销售量,并且销售量具有一定的周期性(如每月的波动)。

生成虚拟数据集:

import pandas as pd
import numpy as np
import random

# 生成日期范围
dates = pd.date_range(start='2022-01-01', periods=1000, freq='D')

# 模拟销售量数据,假设其具有周期性和随机波动
np.random.seed(42)
sales = 200 + 10 * np.sin(np.arange(len(dates)) / 30) + np.random.normal(020, len(dates))

# 随机生成天气、节假日和促销数据
weather = np.random.choice(['Sunny''Rainy''Cloudy'], size=len(dates))
holiday = np.random.choice([01], size=len(dates), p=[0.90.1])  # 10% 是节假日
promotion = np.random.choice([01], size=len(dates), p=[0.80.2])  # 20% 有促销活动

# 创建DataFrame
df = pd.DataFrame({
    'Date': dates,
    'Sales': sales,
    'Weather': weather,
    'Holiday': holiday,
    'Promotion': promotion
})

# 显示前几行数据
df.head()

在这个数据集中:

  • 销售量(Sales) 受月度周期性影响,同时带有随机噪声。
  • 天气(Weather) 为一个类别变量,随机生成三种可能的天气:晴天(Sunny)、雨天(Rainy)和多云(Cloudy)。
  • 节假日(Holiday) 和 促销(Promotion) 为二值变量,分别表示是否为节假日和是否有促销活动。

通过上述步骤,我们生成了一个完整的虚拟销售数据集,包含365天的销售记录。

5. 数据预处理与特征工程

在数据预处理阶段,我们需要对数据进行多项处理,包括:

  1. 日期特征处理:将日期信息拆解为年、月、日和星期几等特征。
  2. 类别特征编码:将天气、节假日、促销等类别特征转换为模型可以接受的数值格式。
  3. 时间序列滞后特征:生成销售量的滞后特征,以捕捉历史数据对当前销售的影响。

日期特征处理

将日期信息转换为年、月、日、星期几等特征,以便模型能够捕捉到时间的季节性规律。

# 日期特征处理
df['Year'] = df['Date'].dt.year
df['Month'] = df['Date'].dt.month
df['Day'] = df['Date'].dt.day
df['DayOfWeek'] = df['Date'].dt.dayofweek

类别特征编码

将类别变量转换为数值特征,通常使用独热编码(One-Hot Encoding)

# 使用独热编码将天气特征转换为数值特征
df = pd.get_dummies(df, columns=['Weather'], drop_first=True)

滞后特征生成

为了捕捉历史数据对未来销售量的影响,我们需要生成滞后特征。假设我们使用过去7天的销售量作为滞后特征。

# 生成滞后特征
for lag in range(18):
    df[f'Sales_lag_{lag}'] = df['Sales'].shift(lag)

# 删除缺失值(由于滞后特征的产生,前几行会产生缺失值)
df = df.dropna()

滞后特征生成后,我们的数据集将包含过去7天的销售量特征,这对于捕捉时间序列中的依赖关系非常重要。

滚动窗口特征生成

除了滞后特征,滚动窗口特征也是常用的手段之一。我们可以计算过去几天的销售量的均值、方差等统计量,以更好地捕捉销售趋势。

# 生成滚动窗口的均值和标准差特征
df['Rolling_mean_7'] = df['Sales'].rolling(window=7).mean().shift(1)
df['Rolling_std_7'] = df['Sales'].rolling(window=7).std().shift(1)

# 同样需要删除因滚动窗口导致的缺失值
df = df.dropna()

通过生成上述特征,我们完成了特征工程,数据集现在不仅包含原始的销售数据和外部特征,还增加了大量的时序特征。

6. 基于XGBoost的时间序列销售预测模型的构建

在数据预处理完成之后,我们可以开始构建基于XGBoost的时间序列预测模型。这里我们将使用PyTorch来实现一个简单的神经网络,并XGBoost的行为。

数据准备

首先,我们将数据划分为训练集和测试集,并转换为PyTorch的张量格式。

from sklearn.model_selection import train_test_split
import torch

# 准备训练和测试集
X = df.drop(columns=['Date''Sales']).values
y = df['Sales'].values

# 确保没有 NaN
X = np.nan_to_num(X)  # 将 NaN 转换为 0 或其他默认数值
y = np.nan_to_num(y)

# 确保数据类型都是数值型
X = X.astype(np.float32)
y = y.astype(np.float32)

# 数据集划分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False)

# 转换为PyTorch张量
X_train = torch.tensor(X_train, dtype=torch.float32)
X_test = torch.tensor(X_test, dtype=torch.float32)
y_train = torch.tensor(y_train, dtype=torch.float32).view(-11)
y_test = torch.tensor(y_test, dtype=torch.float32).view(-11)

模型结构定义

在这里,我们定义一个简单的XGBoost的回归模型结构。虽然XGBoost本质上是树模型,但我们来体现其非线性拟合能力。

import torch.nn as nn

# 定义神经网络模型
class XGBoostTimeSeriesModel(nn.Module):
    def __init__(self, input_dim):
        super(XGBoostTimeSeriesModel, self).__init__()
        self.fc1 = nn.Linear(input_dim, 128)
        self.fc2 = nn.Linear(12864)
        self.fc3 = nn.Linear(641)

    def forward(self, x):
        x = torch.relu(self.fc1(x))
        x = torch.relu(self.fc2(x))
        x = self.fc3(x)
        return x

# 初始化模型
input_dim = X_train.shape[1]
model = XGBoostTimeSeriesModel(input_dim)

损失函数与优化器

我们使用均方误差(MSE)作为损失函数,并使用Adam优化器进行模型优化。

import torch.optim as optim

# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)

模型训练

通过梯度下降法训练模型,进行500次迭代训练。

# 模型训练
epochs = 500
for epoch in range(epochs):
    model.train()
    optimizer.zero_grad()
    outputs = model(X_train)
    loss = criterion(outputs, y_train)
    loss.backward()
    optimizer.step()
    
    if epoch % 50 == 0:
        print(f'Epoch {epoch}/{epochs}, Loss: {loss.item()}')

模型测试

训练完成后,我们可以在测试集上进行预测,并计算模型的性能。

from sklearn.metrics import mean_squared_error

# 模型预测
model.eval()
predictions = model(X_test).detach().numpy()

# 计算均方误差
mse = mean_squared_error(y_test, predictions)
print(f'Test MSE: {mse}')

7. 结果可视化

为了更直观地展示模型的表现,我们将预测值与真实值进行对比绘图,并绘制其他有助于分析模型性能的图形。

预测值与真实值对比图

展示模型在测试集上的预测效果,通过对比可以看到模型是否准确地捕捉到销售趋势。

import matplotlib.pyplot as plt

# 绘制预测值与真实值的对比图
plt.figure(figsize=(126))
plt.plot(df['Date'][-len(y_test):], y_test, label='True Sales', linewidth=2
plt.plot(df['Date'][-len(y_test):], predictions, label='Predicted Sales', linestyle='--', linewidth=2)  
plt.xlabel('Date')
plt.ylabel('Sales')
plt.title('Sales Prediction vs True Sales')
plt.legend()
plt.grid(True)
plt.show()

损失下降曲线

通过绘制训练过程中的损失下降曲线,可以帮助我们判断模型是否收敛。

# 绘制损失下降曲线
losses = []
for epoch in range(epochs):
    model.train()
    optimizer.zero_grad()
    outputs = model(X_train)
    loss = criterion(outputs, y_train)
    loss.backward()
    optimizer.step()
    
    losses.append(loss.item())
    
plt.figure(figsize=(84))
plt.plot(losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training Loss Curve')
plt.show()

特征重要性图

虽然XGBoost具有内建的特征重要性评估机制,但我们可以通过分析模型的权重来了解哪些特征对预测影响最大。

importances = model.fc1.weight.abs().mean(dim=0).detach().numpy()
feature_names = df.drop(columns=['Date''Sales']).columns
plt.figure(figsize=(106))
plt.barh(feature_names, importances)
plt.xlabel('Feature Importance')
plt.title('Feature Importance in Sales Prediction')
plt.show()

8. 模型优化与调参

在实际应用中,优化模型的性能是关键步骤。常见的调优手段包括:

  1. 特征选择与重要性分析:通过分析特征重要性,筛选对模型效果有贡献的特征,并去除不重要的特征。
  2. 超参数调优:使用网格搜索或随机搜索调优超参数,例如树的数量、学习率、正则化参数等。
  3. 交叉验证:使用时间序列分割的交叉验证方法评估模型,确保模型的泛化能力。

超参数调优

XGBoost模型的关键超参数包括:

  • 学习率(learning_rate):控制每棵树的贡献。
  • 树的最大深度(max_depth):控制每棵树的复杂度。
  • 正则化参数(lambda 和 alpha):防止过拟合。

可以使用GridSearchCV进行网格搜索:

from sklearn.model_selection import GridSearchCV
import xgboost as xgb

# 创建XGBoost模型
xgb_model = xgb.XGBRegressor()

# 定义超参数搜索空间
param_grid = {
    'learning_rate': [0.010.050.1],
    'max_depth': [357],
    'n_estimators': [100200300],
    'reg_alpha': [00.10.5],
    'reg_lambda': [11.52]
}

# 进行网格搜索
grid_search = GridSearchCV(estimator=xgb_model, param_grid=param_grid, cv=5, scoring='neg_mean_squared_error', verbose=1)
grid_search.fit(X_train, y_train)

# 输出最佳参数
print("Best Parameters:", grid_search.best_params_)

模型验证与早停

在训练过程中可以引入早停机制(Early Stopping),即如果模型在验证集上的性能在连续几轮迭代中没有提升,则提前终止训练以防止过拟合。

# 使用早停机制训练XGBoost模型
xgb_model = xgb.XGBRegressor(learning_rate=0.1, max_depth=5, n_estimators=300)
xgb_model.fit(X_train, y_train, eval_set=[(X_test, y_test)], early_stopping_rounds=50, verbose=True)

通过这种方式,模型的训练将更加稳健,避免因过度训练导致的过拟合现象。

整个内容,通过结合XGBoost与时间序列模型,给大家分享了如何利用历史销售数据以及多维特征(如天气、促销、节假日等)进行销售预测。XGBoost的强大非线性拟合能力使其在处理复杂特征和多维数据时表现优异。通过合理的特征工程、模型训练、调参与优化,我们可以构建出一个精确且具备良好泛化能力的预测模型。

模型可继续改进的方向:

  • 进一步增强时序特征:可以加入更多的时间序列特征,如季节性成分和长短期记忆网络(LSTM)等方法进行对比。
  • 外部因素引入:可以考虑加入更多的外部因素,如竞争对手信息、经济指标等,以进一步提高预测的精度。
  • 优化超参数调优:通过更多的超参数搜索和交叉验证,进一步提升模型的泛化性能。

最终,该模型可以应用于库存管理、市场营销以及生产计划等多种业务场景。



推荐阅读

(点击标题可跳转阅读)

《机器学习 100 天》视频讲解

公众号历史文章精选

我的深度学习入门路线


重磅

1700多页的《人工智能学习路线、干货分享全集》PDF文档



扫描下方二维码,添加我的微信,领取1700多页的《人工智能学习路线、干货分享全集》PDF文档(一定要备注:资料。 



长按扫码,申请入群



感谢你的分享,点赞,在看三  

AI有道
一个值得关注的 AI 技术公众号。主要涉及人工智能领域 Python、ML 、CV、NLP 等前沿知识、干货笔记和优质资源!我们致力于为您提供切实可行的 AI 学习路线。
 最新文章