【Python时序预测系列】建立RF与GRU融合模型实现单变量时序预测(案例+源码)
·
这是我的第422篇原创文章。
一、引言
将传统机器学习方法(随机森林)与深度学习模型(GRU)结合进行时间序列预测。一般有以下两种结合的思路:
1. 并联结构(Ensemble)
- 随机森林和GRU分别预测,然后合并:

其中
是一个加权系数(可调超参数,也可以学习得到)。
2. 二阶段结构(预训练 + Fine-tune)
- 第一阶段:训练随机森林预测
; - 第二阶段:将
加入 GRU 输入,GRU fine-tune 预测。
如果你时间序列数据中存在复杂的非线性结构 + 时序依赖,而且希望提升模型的泛化能力和抗噪性;那么这个“随机森林 + GRU 的混合模型”确实是一个非常值得尝试的结构。本文通过一个具体的案例来实现第二种融合,大致步骤如下:
-
-
读取时间序列数据,并通过滑动窗口构造特征
-
使用随机森林模型进行初步预测
-
并将其输出作为额外特征加入 GRU 模型输入中
-
可视化分析原始序列、预测效果和训练损失
-
二、实现过程
2.1 读取数据
核心代码:
data = pd.read_csv('data.csv')
# 将日期列转换为日期时间类型
data['Month'] = pd.to_datetime(data['Month'])
# 将日期列设置为索引
data.set_index('Month', inplace=True)
series = np.array(data['Passengers'])
series = (series - series.min()) / (series.max() - series.min())
time = np.arange(len(series))
2.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 = 1
X, y = create_windows(series, window_size)
2.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:]
2.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)
2.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)])
2.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
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)
2.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(20):
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))
2.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())
2.9 画图展示
图1,原始时间序列与训练/测试分割:
plt.figure(figsize=(10,4))
plt.plot(time, series, color='magenta', label='原始序列')
print(split_idx+window_size)
plt.axvline(x=split_idx+window_size, color='cyan', linestyle='--', label='训练/测试分界')
plt.title('图1:原始时间序列与训练测试分割')
plt.legend()
plt.show()
结果:

图2,随机森林在测试集上的表现:
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,RU 训练损失曲线:
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,混合模型在测试集上的预测表现:
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()
结果:

输出评价指标:
mse = mean_squared_error(test_truth, test_preds)
print(f"混合模型测试集 MSE: {mse:.4f}")
结果:
![]()
作者简介:
读研期间发表6篇SCI数据挖掘相关论文,现在某研究院从事数据算法相关科研工作,结合自身科研实践经历不定期分享关于Python、机器学习、深度学习、人工智能系列基础知识与应用案例。致力于只做原创,以最简单的方式理解和学习,关注我一起交流成长。需要数据集和源码的小伙伴可以关注底部公众号添加作者微信。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)