基于树的时间序列预测(LGBM)

2024-05-07 01:52
文章标签 时间 预测 序列 lgbm

本文主要是介绍基于树的时间序列预测(LGBM),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

        在大多数时间序列预测中,尽管有Prophet和NeuralProphet等方便的工具,但是了解基于树的模型仍然具有很高的价值。尤其是在监督学习模型中,仅仅使用单变量时间序列似乎信息有限,预测也比较困难。因此,为了生成足够的特征,需要采取一些方法,例如创建大量的滞后变量。此外,关于预测目标值,也要用过去的项来预测未来的项,而且需要决定是一步领先还是多步领先。

从单变量时间序列中创建特征

        在单变量时间序列中一般只能获得有限的信息。ARIMA 模型使用过去的值来预测未来的值,因此过去的值是重要的候选特征,可以创建许多滞后回归因子。时间指数是一个有价值的领域,因此可以基于此创建特征。由于日历上的事件和年度事件在生活中不断重复,它们为过去留下了印记,为未来提供了教益。因此可以从与时间相关的特征入手。

创建基于时间的特征

        创建基于时间的特征,包括日期、星期、季度等各种特征,通过 pandas series 的 "date" 类中提供的一系列函数,可以轻松实现这些需求。

def create_date_features(df):df['month'] = df.date.dt.monthdf['day_of_month'] = df.date.dt.daydf['day_of_year'] = df.date.dt.dayofyeardf['week_of_year'] = df.date.dt.weekofyeardf['day_of_week'] = df.date.dt.dayofweek + 1df['year'] = df.date.dt.yeardf['quarter'] = df.date.dt.quarterdf['hour_of_day'] = df.date.dt.hourdf['weekday'] = df.date.dt.weekdaydf['is_year_start'] = df.date.dt.is_year_start.astype(int)df['is_year_end'] = df.date.dt.is_year_end.astype(int)df['is_month_start'] = df.date.dt.is_month_start.astype(int)df['is_month_end'] = df.date.dt.is_month_end.astype(int)df['is_quarter_start'] = df.date.dt.is_quarter_start.astype(int)df['is_quarter_end'] = df.date.dt.is_quarter_end.astype(int)df['is_quarter_end'] = df.date.dt.is_quarter_end.astype(int)return df

这里我使用的数据集为本地的数据集,需要可自行搜集下载,除date、open字段外,它还包含其他字段(不做说明):

from matplotlib import pyplot as plt
import pandas as pd
import numpy as np
from pymysql import connect
from sqlalchemy import create_engine, textdef check_info(code):engine = create_engine('mysql+pymysql://root:152617@127.0.0.1:3306/stock_info')conn = engine.connect()result = conn.execute(text("SELECT * FROM stocks WHERE stock_code = " + code))conn.close()return result

将使用 date(日期 )和open(开盘价)字段来处理单变量时间序列。 

df = pd.DataFrame(check_info('000001'))[['date','open']]
df["date"] = pd.to_datetime(df["date"])
df = df.sort_values(by='date')
df.head()

这里数据量不多,因为有很久没有运行脚本去自动更新数据库了,大概只有:

进行可视化:

plt.figure(figsize=(10,4))
plt.plot(df['date'], df["open"])
plt.xlabel("date")
plt.ylabel("open_price")
plt.show()

显而易见的下跌趋势。

应用函数来创建日期特征:

df = create_date_features(df)
df.head()

note:这里需要进行一个步骤。在上面模型中,有几个字段不应作为数字特征,而应作为分类特征。需要把它们转化为虚拟变量

to_dummy = ['weekday', 'month', 'quarter', 'year', 'day_of_month', 'week_of_year', 'day_of_week', 'hour_of_day']
df = pd.get_dummies(df, columns= to_dummy)

一个特征列表就创建好了。

创建滞后特征和未来特征

在自动回归模型中,回归变量是滞后值。可以使用 .shift(n) 来创建滞后特征。接下来,在数据集 ff 中创建三个滞后特征。

ff = df.copy()
ff['open-1'] = ff['open'].shift(1)
ff['openy-2'] = ff['open'].shift(2)
ff['open-3'] = ff['open'].shift(3)
ff.head()

编写一个 forloop 来创建多个滞后特征。下面将在不同的数据集 ff 中创建 5 个滞后变量:

ff = df.copy()def create_lagged(df, n_vars):# Use a forloopfor i in range(n_vars):# The name will be y-1, y-2, etc.name = ('open-%d' % (i+1))df[name] = df['open'].shift(i+1)return dfff = create_lagged(ff, 5)
ff.head()

显然,也可以将数值前移,使其成为未来的目标值,如下所示:

ff = df.copy()
ff['open+1'] = ff['open'].shift(-1)
ff['open+2'] = ff['open'].shift(-2)
ff['open+3'] = ff['open'].shift(-3)
ff.tail()

正式为建模数据 df 创建 25 个滞后变量:

df = create_lagged(df, 25)
df.columns

数据集中包含了['date', 'open', 'open-1', ..., 'open-25']的数据。在此基础上,可以进行一系列汇总统计,如过去 n 小时、n 天或 n 周的总和或平均值。

创建移动平均值

另外,可以创建1,3,5,7,10的移动平均值。

def roll_mean_features(df, windows):df = df.copy()for window in windows:df['mv_' + str(window)] = df['open'].transform(lambda x: x.shift(1).rolling(window=window, min_periods=1, win_type="triang").mean())# min_periods=1表示即使在窗口初期数据不足时也计算平均值# win_type='triang'指定了窗口的权重类型为三角形(Triangular)权重return df
df = roll_mean_features(df, [1, 3, 5, 7, 10])
df.tail()

监督学习框架用于提前预测。模型目标是 open,特征包括滞后项 open-1到open-25以及时间相关和移动平均变量。

该模型可以通过yt-1到yt-25产生下一期的yt,即提前一步预测。在现实应用中,多步预测也很常见,传统方法是建立n个模型来预测接下来的n期。

建立 LightGBM 预测模型

LightGBM是微软开发的梯度提升框架,它使用叶向树生长以提高准确性。相比之下,level-wise树会尝试在同一级别的分支上生长,看起来更平衡。由于其能够处理大型数据集和并行化训练,因此比其他提升算法更高效、更快速,同时内存占用更低。此外,它原生支持分类特征,无需进行单次编码。梯度提升模型是机器学习算法的一种,它将多个较弱的模型组合在一起,从而创建一个强大的预测模型。它的基本思想是迭代训练决策树,每棵树都试图纠正前一棵树所犯的错误。最终的预测结果是所有决策树预测结果的总和。梯度提升模型特别适用于处理复杂的数据集,可以处理大量特征和特征之间的交互,并且对过度拟合也很稳健,同时能够处理缺失值。常用的算法有梯度提升机(GBM)、XGB 和 LightGBM。

划分训练和测试集

将时间序列切割成 "实时" 数据作为训练数据,"非实时" 数据作为测试数据:

from datetime import timedelta
# Count the days
num_days = (df['date'].max() - df['date'].min()).days
# reserve 20% for out-of-time
oot = num_days * 0.2 
# Get the cutdate
cutdate = df['date'].max() - timedelta(days = oot)# Create the training data
train = df.loc[(df['date'] <= cutdate), :]
print("Training data: from", train['date'].min(), "to", train['date'].max())# Create the test data
test = df.loc[(df['date'] > cutdate), :]
print("Test data: from", test['date'].min(), "to", test['date'].max())

LightGBM 建模

LightGBM 有许多超参数可以调整。可指定关键超参数:

import lightgbm as lgb
lgb_params = {# 平均绝对误差'metric': {'mae'}, # 树中树叶的数量'num_leaves': 6, # 10以上训练效果才比较好# 学习日期'learning_rate': 0.02, # 随机选取 80% 的特征到训练              'feature_fraction': 0.8, # 树的最大深度'max_depth':5,# 忽略训练进度(不显示任何内容)'verbose': 0,# 提升迭代次数'num_boost_round': 150,# 如果精度没有提高,就停止训练'early_stopping_rounds': 200,# 使用计算机上的所有内核'nthread': -1}

LightGBM 有一个".Dataset()"代码类,用于打包目标变量、回归变量和数据。如下所示,操作非常简单。

train = train.dropna()Y_train = train[['open']]
X_train = train[cols]
Y_test = test[['open']]
X_test = test[cols]from sklearn import preprocessing
lbl = preprocessing.LabelEncoder()
Y_train['open'] = lbl.fit_transform(Y_train['open'].astype(float))
Y_test['open'] = lbl.fit_transform(Y_test['open'].astype(float))
for c in cols:X_train[c] = lbl.fit_transform(X_train[c].astype(float)) #将提示的包含错误数据类型这一列进行转换X_test[c] = lbl.fit_transform(X_test[c].astype(float))# Use the Dataset class of lightGBM
lgbtrain = lgb.Dataset(data=X_train, label=Y_train, feature_name=cols)
lgbtest = lgb.Dataset(data=X_test, label=Y_test, reference=lgbtrain, feature_name=cols)model = lgb.train(lgb_params, lgbtrain,valid_sets=[lgbtrain, lgbtest],num_boost_round=1000)

在这里需要注意你的数据特征或者label里面有没有NA,否则会出现报错:pandas dtype only support int float bool,检查数据是否是object

其次如果出现warm:-inf意味着可能你的数据过于稀疏(数据中特征的分布非常不均匀,或者特征值的范围很小,可能导致分割增益为负);特征质量差(某些特征可能对模型预测没有帮助,或者特征与目标变量的关联性太弱);参数设置(min_data_in_leaf(叶子节点最小样本数)或min_gain_to_split(最小增益阈值)设置得过高,导致模型在寻找分割时过于保守);需要进行参数重新设定

预测准确性评估

完成后,就可以得出训练数据和测试数据的预测值,并评估预测准确度。使用标准指标平均绝对百分比误差 (MAPE) 来评估预测准确度。MAPE 是绝对百分比误差的平均值,10% 的 MAPE 意味着预测值和实际值之间的平均偏差为 10%。

from sklearn.metrics import mean_absolute_percentage_error
y_pred_train = model.predict(X_train)
y_pred_test = model.predict(X_test)
mean_absolute_percentage_error(Y_test, y_pred_test)

此处数据量过少,提取的特征很勉强,训练效果不好,就不放了。

实际值与预测值可视化

# 将预测值添加到训练期
train_pred = train.copy()
train_pred['open_pred_train'] = y_pred_train# 将预测值添加到测试期
test_pred = test.copy()
test_pred['open_pred_test'] = y_pred_test
print([train_pred.shape, test_pred.shape])# 合并训练期和测试期
actual_pred = pd.concat([train_pred, test_pred], axis=0)
actual_pred.shape# 用蓝色绘制实际值
# 用橙色绘制训练期的预测值
# 用绿色标出测试期的预测值
plt.figure(figsize=(10,4))
plt.plot(actual_pred['date'], actual_pred[["open",'open_pred_train','open_pred_test']])
plt.xlabel("Date")
plt.ylabel("Actual vs. Predictions")
plt.show()

 不忍直视

模型可解释性

基于树的模型的优势之一是其可视性。可以通过变量重要性图直观地看到特征对预测的影响。

lgb.plot_importance(model, max_num_features=20, figsize=(10, 10),importance_type="gain")
plt.show()

特征重要性图显示,影响最大的三个变量是 *、*和*。 毫无解释力。变更数据重新检验即可。

这里探讨了单变量时间序列特征的创建方法,以及如何将其纳入基于树的监督学习框架中。利用 lightGBM 模型进行了一步预测,并展示了如何利用变量显著图提高模型可解释性。

对于timeseries predict进一步还有用LSTM进行分析。

这篇关于基于树的时间序列预测(LGBM)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/966001

相关文章

服务器集群同步时间手记

1.时间服务器配置(必须root用户) (1)检查ntp是否安装 [root@node1 桌面]# rpm -qa|grep ntpntp-4.2.6p5-10.el6.centos.x86_64fontpackages-filesystem-1.41-1.1.el6.noarchntpdate-4.2.6p5-10.el6.centos.x86_64 (2)修改ntp配置文件 [r

uva 10131 最长子序列

题意: 给大象的体重和智商,求体重按从大到小,智商从高到低的最长子序列,并输出路径。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vect

POJ1631最长单调递增子序列

最长单调递增子序列 import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.io.PrintWriter;import java.math.BigInteger;import java.util.StringTokenizer;publ

MiniGPT-3D, 首个高效的3D点云大语言模型,仅需一张RTX3090显卡,训练一天时间,已开源

项目主页:https://tangyuan96.github.io/minigpt_3d_project_page/ 代码:https://github.com/TangYuan96/MiniGPT-3D 论文:https://arxiv.org/pdf/2405.01413 MiniGPT-3D在多个任务上取得了SoTA,被ACM MM2024接收,只拥有47.8M的可训练参数,在一张RTX

leetcode105 从前序与中序遍历序列构造二叉树

根据一棵树的前序遍历与中序遍历构造二叉树。 注意: 你可以假设树中没有重复的元素。 例如,给出 前序遍历 preorder = [3,9,20,15,7]中序遍历 inorder = [9,3,15,20,7] 返回如下的二叉树: 3/ \9 20/ \15 7   class Solution {public TreeNode buildTree(int[] pr

批处理以当前时间为文件名创建文件

批处理以当前时间为文件名创建文件 批处理创建空文件 有时候,需要创建以当前时间命名的文件,手动输入当然可以,但是有更省心的方法吗? 假设我是 windows 操作系统,打开命令行。 输入以下命令试试: echo %date:~0,4%_%date:~5,2%_%date:~8,2%_%time:~0,2%_%time:~3,2%_%time:~6,2% 输出类似: 2019_06

【MRI基础】TR 和 TE 时间概念

重复时间 (TR) 磁共振成像 (MRI) 中的 TR(重复时间,repetition time)是施加于同一切片的连续脉冲序列之间的时间间隔。具体而言,TR 是施加一个 RF(射频)脉冲与施加下一个 RF 脉冲之间的持续时间。TR 以毫秒 (ms) 为单位,主要控制后续脉冲之前的纵向弛豫程度(T1 弛豫),使其成为显著影响 MRI 中的图像对比度和信号特性的重要参数。 回声时间 (TE)

LeetCode:64. 最大正方形 动态规划 时间复杂度O(nm)

64. 最大正方形 题目链接 题目描述 给定一个由 0 和 1 组成的二维矩阵,找出只包含 1 的最大正方形,并返回其面积。 示例1: 输入: 1 0 1 0 01 0 1 1 11 1 1 1 11 0 0 1 0输出: 4 示例2: 输入: 0 1 1 0 01 1 1 1 11 1 1 1 11 1 1 1 1输出: 9 解题思路 这道题的思路是使用动态规划

O(n)时间内对[0..n^-1]之间的n个数排序

题目 如何在O(n)时间内,对0到n^2-1之间的n个整数进行排序 思路 把整数转换为n进制再排序,每个数有两位,每位的取值范围是[0..n-1],再进行基数排序 代码 #include <iostream>#include <cmath>using namespace std;int n, radix, length_A, digit = 2;void Print(int *A,

day-50 求出最长好子序列 I

思路 二维dp,dp[i][h]表示nums[i] 结尾,且有不超过 h 个下标满足条件的最长好子序列的长度(0<=h<=k),二维数组dp初始值全为1 解题过程 状态转换方程: 1.nums[i]==nums[j],dp[i,h]=Math.max(dp[i,h],dp[j,h]+1) 2.nums[i]!=nums[j],dp[i,h]=Math.max(dp[i,h],dp[j,h-1