时间序列预测模型实战案例(二)(Holt-Winter)(Python)结合K-折交叉验证进行时间序列预测实现企业级预测精度(包括运行代码以及代码讲解)

news2024/11/26 8:25:12

目录

引言

数据格式

运行代码 

Holt-Winters模型主体

程序入口

参数讲解

开始训练

预测结果


 

引言

话不多说上来先上预测精度分析图,其中MAE的误差大概在0.11,以下数据均是预测未知数据,而不是训练数据的预测图。

8b50b51e7a674df9b35e6300dea52867.png

 

开始之前我们先来简单了解一下Holt-Winters模型

Holt-Winters模型,也称为三重指数平滑模型,是一种经典的时间序列预测模型,用于处理具有趋势和季节性的时间序列数据。

Holt-Winters模型基于指数平滑法,通过对历史数据进行加权平均来预测未来的值。它使用三个指数平滑系数来估计未来的趋势、季节性和平稳项,从而可以对未来的值进行预测。

Holt-Winters模型的三个指数平滑系数分别为:α、β和γ。其中,α表示对当前观测值的加权系数,β表示对趋势的加权系数,γ表示对季节性的加权系数。这些系数可以通过利用K-折交叉验证最小化平均绝对误差或平均平方误差来确定。

Holt-Winters模型大致可以分为三种类型:加法模型、乘法模型和季节性模型。加法模型适用于季节性变化的幅度相对稳定的情况,乘法模型适用于季节性变化的幅度随着趋势的变化而变化的情况,季节性模型则适用于季节性变化的周期相对稳定的情况。

本文主要选择一种模型来进行实现(季节性模型)同时利用K-折交叉验证法来确定其中三个平滑系数α、β和γ以验证最好的系数,从而达到最高的预测精度极限。

下面来接介绍一下什么是K-折交叉验证

K-折交叉验证(K-fold cross-validation)是一种常用的模型评估方法,用于评估机器学习模型的性能和泛化能力。它将原始数据集分成K个子集,称为“折叠”(fold),其中K-1个子集用于训练模型,1个子集用于测试模型。这个过程重复K次,每个子集都会轮流作为测试集,最终得到K个模型的性能评估结果,这些结果可以平均或加权平均得到模型的最终性能评估结果。

K-折交叉验证的优点是可以有效地利用数据集,减少因数据划分不合理而引入的偏差,提高模型的泛化能力。同时,K-折交叉验证可以避免过拟合和欠拟合等问题,提高模型的稳定性和可靠性。

数据格式

在正式开始之前需要先了解一下,holt-winter模型是单元变量预测模型,所以其只接受单个时间变量的时间序列预测,所以其数据只需要一列即可,就是你需要预测的数据我们这里拿官方的数据ETTh1来进行举例 

91d94e151ab94f2283d03552f0130893.png

数据是这种格式即可,当然你也可以只有OT一列数据也可以,但是你要确保你的数据要符合时间序列,因为你的顺序不能够打乱,因为我们需要时间date这一列主要是为了确保数据是有序的,当然如果你确定你的数据是有序的你也可以只读取进来一列数据即可!!! 

运行代码 

Holt-Winters模型主体

大家可以新建一个py文件将以下所有代码复制进去加上你的数据即可运行出结果!!

import pandas as pd
import numpy as np
from scipy.optimize import minimize  # 优化函数
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import TimeSeriesSplit


class HoltWinters:
    def __init__(self, series, slen, alpha, beta, gamma, n_preds, scaling_factor=1.96):
        self.series = series
        self.slen = slen
        self.alpha = alpha
        self.beta = beta
        self.gamma = gamma
        self.n_preds = n_preds
        self.scaling_factor = scaling_factor

    def initial_trend(self):
        """
        初始化趋势,使用第一个原始数据周期内的数据
        依据现有的数据,除非输入的原始数据发生变化,否则为常数
        :return: 初始化的趋势
        """
        sum = 0.0
        for i in range(self.slen):
            sum += float(self.series[i + self.slen] - self.series[i]) / self.slen
        return sum / self.slen

    def initial_seasonal_components(self):
        """
        初始化季节性参数
        :return: 季节性对于当周期平均值的平均变化值
        """
        seasonals = {}
        season_averages = []
        # 现有数据的周期个数
        n_seasons = int(len(self.series) / self.slen)
        # let's calculate season averages
        # 最后一个周期会有稍微的影响,但影响不大
        # 每个周期平均值,从第一个周期开始,共有n个周期的数据
        for j in range(n_seasons):
            season_averages.append(sum(self.series[self.slen * j:self.slen * j + self.slen]) / float(self.slen))
        # let's calculate initial values
        # 周期中第i天的季节性增长(对比周期内的平均值)
        # 数据个数为一个周期的长度,index为一个周期内的第几个值,从0开始
        # 与原始数据相关,并不是一个固定值
        for i in range(self.slen):
            sum_of_vals_over_avg = 0.0
            for j in range(n_seasons):
                sum_of_vals_over_avg += self.series[self.slen * j + i] - season_averages[j]
            seasonals[i] = sum_of_vals_over_avg / n_seasons
        return seasonals

    def triple_exponential_smoothing(self):
        """
        三次指数平滑
        :return:
        """
        # 预测结果
        self.result = []
        # 平滑值
        self.Smooth = []
        # 季节性
        self.Season = []
        # 趋势性
        self.Trend = []
        # 预测标准差
        self.PredictedDeviation = []
        self.UpperBond = []
        self.LowerBond = []

        # 对于当周期的平均值,每一时刻的平均变化值,为初始值
        seasonals = self.initial_seasonal_components()

        for i in range(len(self.series) + self.n_preds):
            if i == 0:  # components initialization
                smooth = self.series[0]
                trend = self.initial_trend()
                self.result.append(self.series[0])
                self.Smooth.append(smooth)
                self.Trend.append(trend)
                self.Season.append(seasonals[i % self.slen])

                self.PredictedDeviation.append(0)

                self.UpperBond.append(self.result[0] +
                                      self.scaling_factor *
                                      self.PredictedDeviation[0])

                self.LowerBond.append(self.result[0] -
                                      self.scaling_factor *
                                      self.PredictedDeviation[0])
                continue

            if i >= len(self.series):  # predicting
                m = i - len(self.series) + 1
                self.result.append((smooth + m * trend) + seasonals[i % self.slen])
                # self.result.append(max(0,min(1, (smooth + m * trend) + seasonals[i % self.slen])))

                # when predicting we increase uncertainty on each step
                # 每一步增加预测的波动性
                self.PredictedDeviation.append(self.PredictedDeviation[-1] * 1.01)

            else:
                val = self.series[i]
                last_smooth, smooth = smooth, self.alpha * (val - seasonals[i % self.slen]) + (1 - self.alpha) * (
                        smooth + trend)
                trend = self.beta * (smooth - last_smooth) + (1 - self.beta) * trend
                seasonals[i % self.slen] = self.gamma * (val - smooth) + (1 - self.gamma) * seasonals[i % self.slen]
                self.result.append(smooth + trend + seasonals[i % self.slen])
                # self.result.append(max(0,min(1, smooth + trend + seasonals[i % self.slen])))

                # Deviation is calculated according to Brutlag algorithm.
                self.PredictedDeviation.append(self.gamma * np.abs(self.series[i] - self.result[i])
                                               + (1 - self.gamma) * self.PredictedDeviation[-1])

            self.UpperBond.append(self.result[-1] +
                                  self.scaling_factor *
                                  self.PredictedDeviation[-1])

            self.LowerBond.append(self.result[-1] -
                                  self.scaling_factor *
                                  self.PredictedDeviation[-1])

            self.Smooth.append(smooth)
            self.Trend.append(trend)
            self.Season.append(seasonals[i % self.slen])

def timeseriesCVscore(params, series, loss_function=mean_squared_error, slen=7):
    """
        Returns error on CV

        params - vector of parameters for optimization
        series - dataset with timeseries
        slen - season length for Holt-Winters model
    """
    # errors array
    errors = []

    values = series.values
    alpha, beta, gamma = params

    # set the number of folds for cross-validation
    # tscv = TimeSeriesSplit(n_splits=50, test_size=4)
    tscv = TimeSeriesSplit(n_splits=5, test_size=4)

    # iterating over folds, train model on each, forecast and calculate error
    for train, test in tscv.split(values):
        model = HoltWinters(series=values[train], slen=slen,
                            alpha=alpha, beta=beta, gamma=gamma, n_preds=len(test))
        model.triple_exponential_smoothing()

        predictions = model.result[-len(test):]
        actual = values[test]
        error = loss_function(predictions, actual)
        errors.append(error)

    return np.mean(np.array(errors))  # 返回了一个损失函数的平均值

以上的部分就是Holt-Winters的程序内部,其中有一些个人阅读时候的个人理解,大家可以在阅读时候进行一个参考,

程序入口

下面的代码就是程序的入口,我们复制粘贴到文件的最后面即可,下面我将介绍其中每一行的具体含义!!

if __name__ == '__main__':
    data = pd.read_csv('')
    # initializing model parameters alpha, beta and gamma
    cycle = '在这里输入你数据的周期'
    pre_len = '这里输入你要预测未来多久的数据'
    # Minimizing the loss function
    opt = minimize(timeseriesCVscore, x0=[0, 0, 0],
                   args=(data, mean_squared_error,),
                   method="TNC", bounds=((0, 1), (0, 1), (0, 1))
                   )
    # Take optimal values...
    alpha, beta, gamma = opt.x
    model = HoltWinters(data, slen=cycle,
                        alpha=alpha,
                        beta=beta,
                        gamma=gamma,
                        n_preds=pre_len, scaling_factor=2)
    model.triple_exponential_smoothing()
    print(model.result)

 

参数讲解

 首先data = pd.read_csv('')这一行很好理解就是读取你的数据,首先要求你的数据需要是csv格式的文件,然后读取来的数据要满足第二节所述的数据格式(如果你的文件是其他格式你也可以更换类似于read_excel()即可)

    data = pd.read_csv('')

当我们将数据读取进来之后,我们可以对数据进行一个按照时间排序的操作(如果你的数据只有目标值列而没有时间列则忽略掉本段代码) 这一段代码如果你们没有也可以运行如果需要排序则可以自己复制粘贴到对应位置即可

    data.sort_values(by=['date'], inplace=True)

之后的两行,这两行是一个是你数据拥有的周期性,因为holt-winter模型主要的参数还是你数据的一个周期来预测未来某一时段的数据,所有你要知道你数据所拥有的周期性,可以通过数据建模的方式或者根据你的经验来分析(如果大家不会可以评论区留言我可以给大家出用powerbi,matplotlib,excel来建模从而分析数据的教程)

    cycle = '在这里输入你数据的周期'
    pre_len = '这里输入你要预测未来多久的数据'

 这一段代码如果大家了解深度学习就可以理解为模型训练的一个过程,其中

timeseriesCVscore是一个K-折交叉验证的方法来求出损失值最小的方法,

x0就是Holt-Winters模型的三个参数α、β和γ我们初始时将其设置为0

args=(data,mean_squared_error) 其中data就是你们读取进来的数据, mean-squared_error就是一个军方损失函数,就是用前面的K-折交叉验证来求这一损失函数的最小值

method='TNC'就是模型训练的从而收敛的方法,其有很多选项如下大家可以多做实验从而得到一个最好损失结果,

- 'Nelder-Mead' :ref:`(see here) <optimize.minimize-neldermead>`
- 'Powell' :ref:`(see here) <optimize.minimize-powell>`
- 'CG' :ref:`(see here) <optimize.minimize-cg>`
- 'BFGS' :ref:`(see here) <optimize.minimize-bfgs>`
- 'Newton-CG' :ref:`(see here) <optimize.minimize-newtoncg>`
- 'L-BFGS-B' :ref:`(see here) <optimize.minimize-lbfgsb>`
- 'TNC' :ref:`(see here) <optimize.minimize-tnc>`
- 'COBYLA' :ref:`(see here) <optimize.minimize-cobyla>`
- 'SLSQP' :ref:`(see here) <optimize.minimize-slsqp>`
- 'trust-constr':ref:`(see here) <optimize.minimize-trustconstr>`
- 'dogleg' :ref:`(see here) <optimize.minimize-dogleg>`
- 'trust-ncg' :ref:`(see here) <optimize.minimize-trustncg>`
- 'trust-exact' :ref:`(see here) <optimize.minimize-trustexact>`
- 'trust-krylov' :ref:`(see here) <optimize.minimize-trustkrylov>`

每一个方法都不一样,不同的数据也可能适合不同的方法大家可以多尝试尝试, 

bounds就是限制α、β和γ的范围其通常都是位于0-1之间的一个数字,我们限制其一下不要让其超出范围!

    opt = minimize(timeseriesCVscore, x0=[0, 0, 0],
                   args=(data, mean_squared_error,),
                   method="TNC", bounds=((0, 1), (0, 1), (0, 1))
                   )

之后的代码就是将我们训练好的三个参数α、β和γ取出来

    alpha, beta, gamma = opt.x

 下面的代码就是正式到我们预测的部分了,其中的大部分参数我们都已经讲过了,除了其中的scaling_factor大家可以将其理解为一个平滑的参数,之后就是我们对输出结果作了一个三指数的平滑操作可以让数据更加平滑从而提高精度!!!

    model = HoltWinters(data, slen=cycle,
                        alpha=alpha,
                        beta=beta,
                        gamma=gamma,
                        n_preds=pre_len, scaling_factor=2)
    model.triple_exponential_smoothing()

最后我们打印一下结果即可

    print(model.result)

 

 

开始训练

将上述准备工作全部做完以后我们就可以运行我们的程序开始训练了!

运行你们保存代码的文件,控制台就会输出训练过程

5cc2e4dd2c9043c18e2c95d17f9933e5.png 我这里选用的method是L-BFGS-B这个对于我的数据而言我能拿到更高的精度,其控制台输出如上图所示,直到其最终收敛!

967318fc126f464e9946922ce66ed9fe.png

可以看到控制台收敛以后打印出了 α、β和γ三个参数,其中α=0.38537304、β=0和γ=0.89117814

α表示对当前观测值的加权系数,β表示对趋势的加权系数,γ表示对季节性的加权系数。

 


预测结果

32b0cdc960054ee98a7a1238a9f58e82.png

我将所有的结果输出下来并进行了保存到本地的csv文件中并用excel画出了如图可以看出预测值和真实值之间的误差还是有一定误差的!

1927a52b0fef4a6c97820ca6d9c4ffe0.png

这个图可以看出我们的误差MAE大部分都集中在0-0.1之间预测效果还是可以的!

到此Holt-Winters模型的使用就讲解完了!!!!!希望大家都能运行出一个好的结果! 

其它时间序列预测模型讲解

后期我会讲一些最新的预测模型包括transform, Informer,TPA-LSTM,ARIMA,XGBOOST,Holt-winter,移动平均法等等一系列关于时间序列预测的模型,包括深度学习和机器学习方向的模型我都会讲,你可以根据需求选取适合你自己的模型进行预测,如果有需要可以+个关注,包括本次模型我自己的代码和数据大家有需要我也会放出百度网盘下载链接!!

-----------------------------------------------------MTS-Mixers------------------------------------------------------------

【全网首发】(MTS-Mixers)(Python)(Pytorch)最新由华为发布的时间序列预测模型实战案例(一)(包括代码讲解)实现企业级预测精度包括官方代码BUG修复Transform模型

--------------------------------------------------------LSTM-----------------------------------------------------------------

 时间序列预测模型实战案例(三)(LSTM)(Python)(深度学习)时间序列预测(包括运行代码以及代码讲解)

如果大家有不懂的也可以评论区留言一些报错什么的大家可以讨论讨论看到我也会给大家解答如何解决!
 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1426261.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构+算法(第02篇):玩扫雷就是优化算法

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 学习必须往深处挖&…

网安渗透攻击作业(2)

sql注入第一关 一、部署 1、环境安装 &#xff08;1&#xff09;下载phpstudy&#xff0c;下载链接&#xff1a;小皮面板(phpstudy) - 让天下没有难配的服务器环境&#xff01; &#xff0c;安装过后打开软件进入如下界面&#xff0c;接着我们开启nginx和mysql 注意&#x…

Linux--Shell基础

学习笔记&#xff0c;记录以下课程中关于Linux的Shell基础知识。 黑马程序员linux入门到精通&#xff08;下部分&#xff09;_哔哩哔哩_bilibili 目录 1.编写规范 2.变量 2.1 变量的含义 2.2 变量的定义和使用 2.3 只读变量&#xff08;了解&#xff09; 2.4 接收用户输入…

Linux 命令 —— top

Linux 命令 —— top 相对于 ps 是选取一个时间点的进程状态&#xff0c;top 则可以持续检测进程运行的状态。使用方式如下&#xff1a; 用法&#xff1a; top [-d secs] | [-p pid] 选项与参数&#xff1a; -d secs&#xff1a;整个进程界面更新 secs 秒。默认是 5 5 5 秒。…

遇到ubuntu设置交叉编译环境的问题

今天交叉编译器一直没安装成功&#xff0c;环境变量也配置了还是不对&#xff0c;最后发现Ubuntu是64位的要装 然后就好了 另外在进行嵌入式Linux开发的时候&#xff0c;要把主机、虚拟机、以及开发板设置在同一网段下&#xff0c;虚拟机一般设成临时的就可以&#xff0c;但是…

力扣之2648.生成 斐波那契数列(yield)

/*** return {Generator<number>}*/ var fibGenerator function*() {let a 0,b 1;yield 0; // 返回 0&#xff0c;并暂停执行yield 1; // 返回 1&#xff0c;并暂停执行while(true) {yield a b; // 返回 a b&#xff0c;并暂停执行[a, b] [b, a b]; // 更新 a 和 …

使用Pycharm在本地调用chatgpt的接口

目录 1.安装环境 2.建立多轮对话的完整代码&#xff08;根据自己使用的不同代理需要修改端口&#xff08;port&#xff09;&#xff09; 3.修改代码在自己的Pycharm上访问chagpt的api并实现多轮对话&#xff0c;如果不修改是无法成功运行的。需要确定秘钥和端口以保证正常访…

使用pygame建立一个简单的使用键盘方向键移动的方块小游戏

import pygame import sys# 初始化pygame pygame.init()# 设置窗口大小 screen_size (640, 480) # 创建窗口 screen pygame.display.set_mode(screen_size) # 设置窗口标题 pygame.display.set_caption("使用键盘方向键移动的方块的简单小游戏")# 设置颜色 bg_colo…

CHS_08.2.3.6_1+生产者-消费者问题

CHS_08.2.3.6_1生产者-消费者问题 问题描述问题分析思考&#xff1a;能否改变相邻P、V操作的顺序&#xff1f;知识回顾 在这个小节中 我们会学习一个经典的进程同步互斥的问题 问题描述 并且尝试用上个小节学习的p v操作 也就是信号量机制来解决这个生产者消费者问题 问题的描…

基于GAN-CNN-CNN的鲁棒笔迹识别方法(三)

上一篇文章提出了一个用于笔迹识别(鉴别)的三段式模型,同时也提出了一个新数据集HTID_1,本文主要针对模型的最后一部分--笔迹识别,在HTID_1上进行实验. 数据集 实验前先介绍一下HTID_1. HTID_1是用于笔迹识别的数据集,是基于本文提出的模型制作而成的.将互联网上收集的740人笔…

Unity Shader 滚动进度条效果

Unity Shader 滚动进度条效果 前言项目场景布置导入图片修改场景设置修改图片尺寸即可调整进度 ASE连线 前言 UI要实现一个滚动进度&#xff0c;于是使用Shader制作一个。 项目 场景布置 导入图片 修改一下导入图片的格式&#xff0c;这样才能循环起来 WrapMode改为Repea…

2024/2/1学习记录

echarts 为柱条添加背景色&#xff1a; 若想设置折线图的点的样式&#xff0c;设置 series.itemStyle 指定填充颜色就好了&#xff0c;设置线的样式设置 lineStyle 就好了。 在折线图中倘若要设置空数据&#xff0c;用 - 表示即可&#xff0c;这对于其他系列的数据也是 适用的…

Windows11 用 HyperV 安装 Ubuntu-16.04 虚拟机

Windows11 用 HyperV 安装 Ubuntu-16.04 虚拟机 1. 确保已经开启HyperV2. 准备Ubuntu16.04镜像&#xff08;推荐64位的&#xff09;3. HyperV ->快速创建 -> 更改安装源 选刚刚下载的镜像&#xff08;.iso&#xff09;文件就好 -> 创建虚拟机[^1] 前提&#xff1a;VMw…

(硬核中的硬核)链路追踪落地过程中的挑战与解决方案

&#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是蓝胖子&#x1f947; ☁️博客首页&#xff1a;CSDN主页蓝胖子的编程梦 &#x1f304;每日一句&#xff1a;编程中我们会遇到多少挫折&#xff1f;表放弃&#xff0c;沙漠尽头必是绿洲。 大家好&#xff0c;我是蓝胖子…

【Qt加密播放器】登录窗口功能补充

输入框小设计 目的&#xff1a;实现鼠标点击输入框时的聚焦效果。 首先在LoginForm构造函数中为账号和密码输入框添加事件过滤器。关于事件过滤器的具体介绍可以参考这篇博文&#xff1a;Qt消息机制和事件 ui->nameEdit->installEventFilter(this); ui->pwdEdit->…

uniapp+微信小程序+nodejs问题记录

一、前言 通过uniapp进行微信小程序调试。服务端使用NodeJs。 二、报错统计 1、本地调试时微信小程序报错&#xff1a;request:Cannot send network request to localhost 解决方法&#xff1a; 【微信小程序开发平台】-【本地设置】-勾选“不校验合法域名、web-view、TLS版本…

Python完善APC netbotz 250报告功能实现主动式运维。

首先介绍一下APC netbotz 250, 这是施耐德推出的一款机架式监控主机&#xff0c;能够对所有IT环境进行经济有效而且灵活的监控&#xff0c;号称APC史上性价比最高的环境监测方案&#xff0c;这可不是我吹的&#xff0c;是APC官网的介绍&#xff0c;可参考下面的官网截图。 我们…

Visual Studio 2022编译错误 Error MSB8041-此项目需要MFC库解决方案

Visual Studio 2022编译错误 Error MSB8041-此项目需要MFC库 错误原因&#xff1a; Visual Studio 2022安装的MFC库不够。 解决方案&#xff1a; 安装Visual Studio 2022 需要的MFC 库就可以了。 安装方法&#xff1a; 第一步&#xff0c;打开vs2022 工具 ->获取工具和功…

数据可视化Tableau

目录 一.第一次实验课内容 1、熟悉Tableau Desktop的工作环境。 2、熟悉数据导入、维度和度量的区分以及不同数据字段类型的标识符。 3、熟悉工作表的基本操作&#xff0c;主要包括行列功能区&#xff0c;标记卡&#xff0c;筛选器&#xff0c;智能推荐的使用。 4、作业--…

两个链表的第一个重合节点

法一&#xff1a;蛮力法 即顺序遍历第一个链表的每个节点&#xff0c;每遍历到一个节点&#xff0c;就在第二个链表中顺序遍历每个节点&#xff0c;比较是否有节点相同。该方法的时间复杂度是O&#xff08;mn&#xff09;&#xff0c;空间复杂度是O&#xff08;1&#xff09;。…