醋醋百科网

Good Luck To You!

最强总结!随机森林+GRU时序预测 !!

哈喽,我是小白~

今天和大家来聊聊时间序列预测中随机森林和GRU的混合模型~

先从具体过程分解开始~

步骤一:时间序列数据准备(窗口划分)

假设我们有一个每日销售额的时间序列:

数据: y = [y, y, y, ..., y]

滑动窗口法 构造输入:

步骤二:随机森林提取特征

用滑动窗口得到的每一个 当作输入,训练随机森林模型:

或者,我们也可以使用随机森林中间的“叶子索引”或“树路径编码”作为 非线性高维表示 (像特征变换):

步骤三:构造 GRU 输入

将原始窗口 和随机森林输出或编码 拼接:

然后我们可以把一系列 组成 GRU 的时间输入序列:

步骤四:GRU 时间建模

GRU 单元状态更新如下(重复细节解释):

  1. 更新门 (决定保留多少历史信息):

  2. 重置门 (决定遗忘多少旧状态):

  3. 候选隐藏状态

  4. 更新隐藏状态

输出预测值:

优化目标(损失函数)

最常见是 MSE(均方误差):

也可以根据应用使用 MAE、Huber Loss、加权误差等。

混合模型的变种

1. 并联结构(Ensemble)

其中 是一个加权系数(可调超参数,也可以学习得到)。

2. 二阶段结构(预训练 + Fine-tune)

总的来说,如果你时间序列数据中存在 复杂的非线性结构 + 时序依赖 ,而且希望提升模型的 泛化能力 抗噪性

那么这个“ 随机森林 + GRU 的混合模型 ”确实是一个非常值得尝试的结构。

完整案例

之类,将传统机器学习方法(随机森林)与深度学习模型(GRU)结合进行时间序列预测。

首先生成带趋势、季节性和噪声的虚拟时间序列数据,并通过滑动窗口构造特征。

然后使用随机森林模型进行初步预测,并将其输出作为额外特征加入 GRU 模型输入中。

通过 PyTorch 构建并训练 GRU 网络,以进一步提升预测精度。最终可视化原始序列、预测效果和训练损失,并计算混合模型在测试集上的均方误差(MSE)评价指标。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
import torch
import torch.nn as nn
from torch.utils.data import DataLoader, TensorDataset

# 1. 生成模拟时间序列数据(带趋势、季节性与噪声)
np.random.seed(42)
T = 500
time = np.arange(T)
trend = time * 0.02
seasonal = 2 * np.sin(2 * np.pi * time / 50)
noise = 0.5 * np.random.randn(T)
series = 10 + trend + seasonal + noise

# 2. 构造滑动窗口特征
def create_windows(data, window_size):
X, y = [], []
for i in range(len(data) - window_size):
X.append(data[i:i+window_size])
y.append(data[i+window_size])
return np.array(X), np.array(y)

window_size = 20
X, y = create_windows(series, window_size)

# 3. 划分训练和测试集(避免泄露,按时间顺序切分)
split_idx = int(0.8 * len(X))
X_train, X_test = X[:split_idx], X[split_idx:]
y_train, y_test = y[:split_idx], y[split_idx:]

# 4. 训练随机森林并提取预测值
rf = RandomForestRegressor(n_estimators=100, random_state=42)
rf.fit(X_train, y_train)
rf_train_pred = rf.predict(X_train)
rf_test_pred = rf.predict(X_test)

# 5. 将 RF 输出拼接入 GRU 输入特征
X_train_gru = np.hstack([X_train, rf_train_pred.reshape(-1,1)])
X_test_gru = np.hstack([X_test, rf_test_pred.reshape(-1,1)])

# 6. PyTorch GRU 模型定义
class GRUModel(nn.Module):
def __init__(self, input_size, hidden_size=32, num_layers=1):
super(GRUModel, self).__init__()
self.gru = nn.GRU(input_size, hidden_size, num_layers, batch_first=True)
self.fc = nn.Linear(hidden_size, 1)
def forward(self, x):
out, _ = self.gru(x)
out = self.fc(out[:, -1, :])
return out

# 准备 DataLoader
def to_tensor_dataset(X, y):
return TensorDataset(torch.tensor(X, dtype=torch.float32).unsqueeze(1),
torch.tensor(y, dtype=torch.float32).unsqueeze(-1))


train_dataset = to_tensor_dataset(X_train_gru, y_train)
test_dataset = to_tensor_dataset(X_test_gru, y_test)
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=False)
test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)

# 7. 训练 GRU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = GRUModel(input_size=window_size+1).to(device)
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)

train_losses = []
for epoch in range(50):
model.train()
epoch_loss = 0
for X_batch, y_batch in train_loader:
X_batch, y_batch = X_batch.to(device), y_batch.to(device)
optimizer.zero_grad()
outputs = model(X_batch)
loss = criterion(outputs, y_batch)
loss.backward()
optimizer.step()
epoch_loss += loss.item() * X_batch.size(0)
train_losses.append(epoch_loss / len(train_loader.dataset))

# 8. 测试并预测
model.eval()
with torch.no_grad():
test_preds = []
test_truth = []
for X_batch, y_batch in test_loader:
X_batch = X_batch.to(device)
preds = model(X_batch).cpu().numpy().flatten()
test_preds.extend(preds)
test_truth.extend(y_batch.numpy().flatten())

# 9. 画图展示

# 图1:原始序列与训练/测试分割
plt.figure(figsize=(10,4))
plt.plot(time, series, color='magenta', label='原始序列')
plt.axvline(x=split_idx+window_size, color='cyan', linestyle='--', label='训练/测试分界')
plt.title('图1:原始时间序列与训练测试分割')
plt.legend()
plt.show()

# 图2:随机森林预测 vs 真实值(测试集)
plt.figure(figsize=(10,4))
plt.plot(range(len(y_test)), y_test, color='orange', label='真实值 y_test')
plt.plot(range(len(rf_test_pred)), rf_test_pred, color='blue', linestyle='--', label='RF 预测')
plt.title('图2:随机森林在测试集上的表现')
plt.legend()
plt.show()

# 图3:GRU 训练损失曲线
plt.figure(figsize=(10,4))
plt.plot(range(1, len(train_losses)+1), train_losses, color='red', marker='o')
plt.title('图3:GRU 训练损失曲线')
plt.xlabel('Epoch')
plt.ylabel('MSE Loss')
plt.show()

# 图4:混合模型最终预测 vs 真实值
plt.figure(figsize=(10,4))
plt.plot(range(len(test_truth)), test_truth, color='green', label='真实值')
plt.plot(range(len(test_preds)), test_preds, color='purple', linestyle='--', label='混合模型预测')
plt.title('图4:混合模型在测试集上的预测表现')
plt.legend()
plt.show()

# 10. 输出评价指标
mse = mean_squared_error(test_truth, test_preds)
print(f"混合模型测试集 MSE: {mse:.4f}")
图1,原始时间序列与训练/测试分割 :展示了整体数据走势(包含趋势、季节性与噪声),并标出训练集与测试集的分界,帮助理解数据量划分与模型验证。


图2,随机森林在测试集上的表现 :对比了随机森林的预测值与真实值,直观展现 RF 单独对非线性模式的拟合能力及误差分布。
图3,RU 训练损失曲线 :展示了 GRU 模型在每个 epoch 上的 MSE 变化,帮助判断训练过程是否收敛、是否存在过拟合趋势。
图4,混合模型在测试集上的预测表现 :将最终混合模型的预测与真实值对比,验证了引入随机森林特征后,GRU 对时间依赖的建模提升,以及整体误差水平。

此外,代码计算了测试集上的 MSE 指标,量化了模型性能。全流程严格按时间先后顺序切分数据,确保无“信息泄露”。

推荐阅读

最近准备了 16大块的内容,124个算法问题总结 ,完整的机器学习小册,免费领取~
领取:备注「算法小册」即可~

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言