第74步 时间序列建模实战:多步滚动预测 vol-2(以决策树回归为例)

2023-09-21 11:46:15

基于WIN10的64位系统演示

一、写在前面

上一期,我们讲了多步滚动预测的第一种策略:对于重复的预测值,取平均处理。例如,(1,2,3)预测出3.9和4.5,(2,3,4)预测出5.2和6.3,那么拼起来的结果就是3.9,(4.5 + 5.2)/2, 6.3。

这一期,我们来介绍第二种策略:删除一半的输入数据集。例如,4,5由(1,2,3)预测,6,7由(3,4,5)预测,删掉输入数据(2,3,4)。

2、多步滚动预测 vol-2

所谓的删除一半的输入数据集,大家看下表即可:

输入

输出

1,2,3

4,5

3,4,5

6,7

5,6,7

8,9

...

...

4,5由(1,2,3)预测,6,7由(3,4,5)预测,8,9由(5,6,7)预测,删掉输入数据(2,3,4),(4,5,6),以此类推。

2.1 数据拆分

import pandas as pd
import numpy as np
from sklearn.tree import DecisionTreeRegressor
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import mean_absolute_error, mean_squared_error

data = pd.read_csv('data.csv')
data['time'] = pd.to_datetime(data['time'], format='%b-%y')

n = 6  # 使用前6个数据点
m = 2  # 预测接下来的2个数据点

# 创建滞后期特征
for i in range(n, 0, -1):
    data[f'lag_{i}'] = data['incidence'].shift(n - i + 1)

data = data.dropna().reset_index(drop=True)

train_data = data[(data['time'] >= '2004-01-01') & (data['time'] <= '2011-12-31')]
validation_data = data[(data['time'] >= '2012-01-01') & (data['time'] <= '2012-12-31')]

# 只对X_train、y_train、X_validation取奇数行
X_train = train_data[[f'lag_{i}' for i in range(1, n+1)]].iloc[::2].reset_index(drop=True)

# 创建m个目标变量
y_train_list = [train_data['incidence'].shift(-i) for i in range(m)]
y_train = pd.concat(y_train_list, axis=1)
y_train.columns = [f'target_{i+1}' for i in range(m)]
y_train = y_train.iloc[::2].reset_index(drop=True).dropna()
X_train = X_train.head(len(y_train))

X_validation = validation_data[[f'lag_{i}' for i in range(1, n+1)]].iloc[::2].reset_index(drop=True)
y_validation = validation_data['incidence']

核心部分在于:只对X_train、y_train、X_validation取奇数行。也就是我们说的删除一半的输入数据集。

2.2 建模与预测

tree_model = DecisionTreeRegressor()
param_grid = {
    'max_depth': [None, 3, 5, 7, 9],
    'min_samples_split': range(2, 11),
    'min_samples_leaf': range(1, 11)
}

grid_search = GridSearchCV(tree_model, param_grid, cv=5, scoring='neg_mean_squared_error')
grid_search.fit(X_train, y_train)
best_params = grid_search.best_params_

best_tree_model = DecisionTreeRegressor(**best_params)
best_tree_model.fit(X_train, y_train)

# 预测验证集
y_validation_pred = []

for i in range(len(X_validation)):
    pred = best_tree_model.predict([X_validation.iloc[i]])
    y_validation_pred.extend(pred[0])

y_validation_pred = np.array(y_validation_pred)[:len(y_validation)]

mae_validation = mean_absolute_error(y_validation, y_validation_pred)
mape_validation = np.mean(np.abs((y_validation - y_validation_pred) / y_validation))
mse_validation = mean_squared_error(y_validation, y_validation_pred)
rmse_validation = np.sqrt(mse_validation)

print(mae_validation, mape_validation, mse_validation, rmse_validation)

# 预测训练集
y_train_pred = []

for i in range(len(X_train)):
    pred = best_tree_model.predict([X_train.iloc[i]])
    y_train_pred.extend(pred[0])

# 因为预测了多步,为了与y_train的形状相匹配,只取第一列
y_train_pred = np.array(y_train_pred)[:y_train.shape[0]]

mae_train = mean_absolute_error(y_train.iloc[:, 0], y_train_pred)
mape_train = np.mean(np.abs((y_train.iloc[:, 0] - y_train_pred) / y_train.iloc[:, 0]))
mse_train = mean_squared_error(y_train.iloc[:, 0], y_train_pred)
rmse_train = np.sqrt(mse_train)

print(mae_train, mape_train, mse_train, rmse_train)

核心代码,把每一个输出的结果(2个输出)按照顺序拼接形成最终的预测结果:

for i in range(len(X_validation)):

    pred = best_tree_model.predict([X_validation.iloc[i]])

    y_validation_pred.extend(pred[0])

这段代码通过循环对X_validation中的每一行数据进行预测,并将每次的预测结果依次添加到y_validation_pred中,体现了结果的依次拼接。

其中:

pred = best_tree_model.predict([X_validation.iloc[i]]) 是对第 i 行数据进行预测。

y_validation_pred.extend(pred[0]) 是将预测结果pred[0]依次添加到y_validation_pred列表中。

因此,y_validation_pred列表最后的内容是将每一次预测的结果依次拼接而成。

2.3 输出

三、数据

链接:https://pan.baidu.com/s/1EFaWfHoG14h15KCEhn1STg?pwd=q41n

提取码:q41n

更多推荐

详解junit

目录1.概述2.断言3.常用注解3.1.@Test3.2.@Before3.3.@After3.4.@BeforeClass3.5.@AfterClass4.异常测试5.超时测试6.参数化测试1.概述什么是单元测试:单元测试,是针对最小的功能单元编写测试代码,在JAVA中最小的功能单元是方法,单元测试针对JAVA就是单

Blender批量修改名称

假如在Blender里按顺序添加了多个mesh,名字后缀按照数字1,2,3…编号,此时又要插入一个新的mesh,那么这个mesh之后的其它mesh名字都要加1,此时该怎么办呢?比较简单的办法是把新mesh后面的mesh名称一个一个手动加1,如果数量少还可以,如果很多就有点浪费时间了。Blender自身也提供了批量修改的

多旋翼无人机组合导航系统-多源信息融合算法(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。⛳️座右铭:行百里者,半于九十。📋📋📋本文目录如下:🎁🎁🎁目录💥1概述📚2运行结果🎉3参考文献🌈4Matlab代码实现💥1概述多旋翼无人机已被广泛应用于军事与民用领域。导航系统

C++中string对象之间比较、char*之间比较

#include<cstring>//char*使用strcmp#include<string>//string使用compare#include<iostream>usingnamespacestd;intmain(){stringstringStr1="42";stringstringStr2="42";strin

《golang设计模式》第二部分·结构型模式-05-门面模式Facade)

文章目录1.概述1.1角色1.2类图2.代码示例2.1设计2.2代码2.2类图1.概述门面(Facade)向客户端提供使用子系统的统一接口,用于简化客户端使用子系统的操作。1.1角色门面角色(Facade)客户端可以调用的接口或方法此角色知晓系统的所有功能和责任一般情况下,该角色没有实际业务逻辑,只是一个委托类。子系统

蓝桥杯每日一题2023.9.16

蓝桥杯2022年第十三届省赛真题-X进制减法-C语言网(dotcpp.com)题目描述进制规定了数字在数位上逢几进一。X进制是一种很神奇的进制,因为其每一数位的进制并不固定!例如说某种X进制数,最低数位为二进制,第二数位为十进制,第三数位为八进制,则X进制数321转换为十进制数为65。现在有两个X进制表示的整数A和B,

基于NAudio实现录制声卡声音

之前的文章《测试.net开源音频库NAudio》中介绍了基于NAudio模块中的WaveInEvent和WaveFileWriter类实现基本的录音功能,但存在一个问题:本来想录制视频中的声音,但录音过程中会把麦克风中的杂音(挪动物品的声音、说话声音等)一并录进去。NAudio模块中提供有WasapiLoopbackC

代理IP与Socks5代理:跨界电商智能爬虫与出海之道

跨界电商正成为全球市场的关键驱动力,而代理IP和Socks5代理则为其提供了技术支持。本文将深入研究这两种代理技术在跨界电商、爬虫和出海战略中的重要作用。引言:介绍跨界电商的崛起和全球化趋势。引出代理IP和Socks5代理的重要性以及本文的主题。第一部分:代理IP和Socks5代理的基础知识代理IP和Socks5代理的

文心一言 VS 讯飞星火 VS chatgpt (97)-- 算法导论9.3 3题

三、用go语言,假设所有元素都是互异的,说明在最坏情况下,如何才能使快速排序的运行时间为O(nlgn)。文心一言:快速排序是一种基于分治策略的排序算法,其平均时间复杂度为O(nlgn)。在最坏情况下,快速排序的时间复杂度为O(n^2),这是因为当输入数组已经排序或接近排序时,快速排序的性能会退化。为了使快速排序在最坏情

Python的协程异步IO(asyncio)详解

一、协程简介1.1定义协程不是系统级线程,很多时候协程被称为“轻量级线程”、“微线程”、“纤程(fiber)”等。简单来说可以认为协程是线程里不同的函数,这些函数之间可以相互快速切换。协程和用户态线程非常接近,用户态线程之间的切换不需要陷入内核,但部分操作系统中用户态线程的切换需要内核态线程的辅助。协程是编程语言(或者

Blender关键帧动画简明教程

Blender3D是一款能够创建令人惊叹的动画的免费软件。Blender中的大多数动画都使用所谓的关键帧。Blender中关键帧的介绍将涵盖开始制作动画所需的一切!推荐:用NSDT编辑器快速搭建可编程3D场景1、什么是关键帧?在计算机出现之前,动画师必须手动绘制动画的每一帧——在每幅图像之间进行极其微小的更改。通过Bl

热文推荐