第100+33步 ChatGPT学习:时间序列EMD-ARIMA-LSTM模型

news2025/1/27 13:02:27

基于Python 3.9版本演示

 

一、写在前面

上一节,我们学了经验模态分解(Empirical Mode Decomposition,EMD)。

如同结尾所说,“那么,做这些分解有什么作用呢?有大佬基于这些分解出来的序列分别作预测,然后再次合并,达到提升预测性能的作用。”

 

二、EMD&LSTM-ARIMA组合策略

该组合策略主要是将传统的经验模态分解(EMD)方法和现代的机器学习技术(LSTM 和 ARIMA 模型)相结合,用于增强时序数据的预测能力。下面是这个策略的具体描述:

(1)经验模态分解 (EMD):

1)首先,使用 EMD 方法处理原始时序数据,将其分解为多个内模函数(IMF)和一个剩余信号。这一步骤的目的是提取数据中的不同频率成分,每个 IMF 代表原始信号的不同频率层次,而剩余信号包含了趋势信息。

2)EMD 是一种自适应方法,适用于非线性和非平稳时间序列数据分析,可以揭示隐藏在复杂数据集中的简单结构和成分。

(2)LSTM 和 ARIMA 模型的应用:

1)将不同的 IMF 成分分配给不同的预测模型:选定的IMF由 LSTM 模型处理,通常选择那些更具高频和复杂动态的成分;而趋势性较强的成分(包括剩余信号)则交由 ARIMA 模型进行分析。

2)LSTM (长短期记忆网络):适合处理和预测时间序列数据中的长期依赖关系,因此用于捕捉和预测时序数据中的非线性模式和复杂关系。

3)ARIMA (自回归积分滑动平均模型):擅长处理线性关系和趋势变化,适用于具有明显趋势或季节性的时间序列数据。

 

三、EMD&LSTM-ARIMA组合策略代码Pyhton实现

下面,我使用的是之前分享过的肺结核的数据做演示:

311fef53b2d142c087306ca3061bc39a.png

Pyhon代码:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import CubicSpline
import torch
import torch.nn as nn
import torch.optim as optim
from statsmodels.tsa.arima.model import ARIMA
from sklearn.metrics import mean_absolute_error, mean_squared_error

# 读取数据
file_path = 'pone.0277314.s006.xlsx'
data = pd.read_excel(file_path)

# 提取时间和PTB病例数
time_series = data['Time']
ptb_cases = data['PTB cases']

# 将时间转换为数值形式
time_numeric = np.arange(len(time_series))

def get_envelope_mean(signal):
    """计算信号的上包络线和下包络线的均值"""
    maxima = np.where(np.r_[True, signal[1:] > signal[:-1]] & np.r_[signal[:-1] > signal[1:], True])[0]
    minima = np.where(np.r_[True, signal[1:] < signal[:-1]] & np.r_[signal[:-1] < signal[1:], True])[0]
    
    if len(maxima) < 2 or len(minima) < 2:
        return np.zeros_like(signal)
    
    upper_env = CubicSpline(maxima, signal[maxima])(time_numeric)
    lower_env = CubicSpline(minima, signal[minima])(time_numeric)
    
    return (upper_env + lower_env) / 2

def sift(signal, max_iter=1000, tol=1e-6):
    """对信号进行sifting操作,提取IMF"""
    h = signal
    for _ in range(max_iter):
        m = get_envelope_mean(h)
        h1 = h - m
        
        if np.mean(np.abs(h - h1)) < tol:
            break
        h = h1
    
    return h

def emd(signal, max_imfs=6):
    """进行EMD分解"""
    residual = signal
    imfs = []
    for _ in range(max_imfs):
        imf = sift(residual)
        imfs.append(imf)
        residual = residual - imf
        
        if np.all(np.abs(residual) < 1e-6):
            break
    
    return np.array(imfs), residual

# 执行EMD分解
imfs, residual = emd(ptb_cases.values)

# 绘制分解结果
num_imfs = imfs.shape[0]
plt.figure(figsize=(12, 9))
for i in range(num_imfs):
    plt.subplot(num_imfs + 1, 1, i + 1)
    plt.plot(time_series, imfs[i], label=f'IMF {i + 1}')
    plt.legend()

plt.subplot(num_imfs + 1, 1, num_imfs + 1)
plt.plot(time_series, residual, label='Residual')
plt.legend()
plt.tight_layout()
plt.show()

# LSTM模型
class LSTMModel(nn.Module):
    def __init__(self, input_size=1, hidden_layer_size=50, output_size=1):
        super(LSTMModel, self).__init__()
        self.hidden_layer_size = hidden_layer_size
        self.lstm = nn.LSTM(input_size, hidden_layer_size)
        self.linear = nn.Linear(hidden_layer_size, output_size)
        self.hidden_cell = (torch.zeros(1,1,self.hidden_layer_size),
                            torch.zeros(1,1,self.hidden_layer_size))

    def forward(self, input_seq):
        lstm_out, self.hidden_cell = self.lstm(input_seq.view(len(input_seq) ,1, -1), self.hidden_cell)
        predictions = self.linear(lstm_out.view(len(input_seq), -1))
        return predictions[-1]

def train_lstm_model(train_data, n_steps):
    model = LSTMModel()
    loss_function = nn.MSELoss()
    optimizer = optim.Adam(model.parameters(), lr=0.001)
    epochs = 200

    for epoch in range(epochs):
        for seq in range(len(train_data) - n_steps):
            model.hidden_cell = (torch.zeros(1, 1, model.hidden_layer_size),
                                 torch.zeros(1, 1, model.hidden_layer_size))

            seq_train = torch.FloatTensor(train_data[seq:seq + n_steps])
            label = torch.FloatTensor(train_data[seq + n_steps:seq + n_steps + 1])

            optimizer.zero_grad()
            y_pred = model(seq_train)

            single_loss = loss_function(y_pred, label)
            single_loss.backward()
            optimizer.step()
        
        if epoch % 50 == 0:
            print(f'Epoch {epoch+1} loss: {single_loss.item()}')

    return model

def arima_model(train_data, order):
    model = ARIMA(train_data, order=order)
    model_fit = model.fit()
    return model_fit

n_steps = 10
imfs_lstm = [3, 4]  # 分配给LSTM的IMFs索引
imfs_arima = [0, 1, 2]  # 分配给ARIMA的IMFs索引

lstm_predictions = np.zeros(len(time_numeric))
arima_predictions = np.zeros(len(time_numeric))

# LSTM预测
for idx in imfs_lstm:
    print(f'Training LSTM for IMF {idx+1}')
    train_data = imfs[idx].flatten()
    model = train_lstm_model(train_data, n_steps)
    for i in range(n_steps, len(train_data)):
        seq = torch.FloatTensor(train_data[i-n_steps:i])
        with torch.no_grad():
            lstm_predictions[i] += model(seq).item()
    print(f'LSTM predictions for IMF {idx+1} completed')

# ARIMA预测
for idx in imfs_arima:
    print(f'Training ARIMA for IMF {idx+1}')
    train_data = imfs[idx]
    model_fit = arima_model(train_data, order=(5, 1, 0))
    arima_predictions += model_fit.predict(start=0, end=len(train_data) - 1)
    print(f'ARIMA predictions for IMF {idx+1} completed')

# 合并预测结果
final_predictions = lstm_predictions + arima_predictions

# 计算误差
mae = mean_absolute_error(ptb_cases, final_predictions)
mse = mean_squared_error(ptb_cases, final_predictions)
rmse = np.sqrt(mse)
mape = np.mean(np.abs((ptb_cases - final_predictions) / ptb_cases)) * 100

# 打印误差
print(f'MAE: {mae}')
print(f'MSE: {mse}')
print(f'RMSE: {rmse}')
print(f'MAPE: {mape}')

# 绘制预测结果
plt.figure(figsize=(12, 6))
plt.plot(time_numeric, ptb_cases, label='Original Data')
plt.plot(time_numeric, final_predictions, label='Predicted Data')
plt.legend()
plt.show()

输出:

d132d76bacaf4b23a1b55c63857090db.png

跟原图对比:

发现了没,似乎是整体向下偏移了一波。让GPT帮忙优化一下算法。

 

五、优化后

根据每个模型的误差(MAE)微调一下试试:

Pyhon代码:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import CubicSpline
import torch
import torch.nn as nn
import torch.optim as optim
from statsmodels.tsa.arima.model import ARIMA
from sklearn.metrics import mean_absolute_error, mean_squared_error

# 读取数据
file_path = 'pone.0277314.s006.xlsx'
data = pd.read_excel(file_path)

# 提取时间和PTB病例数
time_series = data['Time']
ptb_cases = data['PTB cases']

# 将时间转换为数值形式
time_numeric = np.arange(len(time_series))

def get_envelope_mean(signal):
    """计算信号的上包络线和下包络线的均值"""
    maxima = np.where(np.r_[True, signal[1:] > signal[:-1]] & np.r_[signal[:-1] > signal[1:], True])[0]
    minima = np.where(np.r_[True, signal[1:] < signal[:-1]] & np.r_[signal[:-1] < signal[1:], True])[0]
    
    if len(maxima) < 2 or len(minima) < 2:
        return np.zeros_like(signal)
    
    upper_env = CubicSpline(maxima, signal[maxima])(time_numeric)
    lower_env = CubicSpline(minima, signal[minima])(time_numeric)
    
    return (upper_env + lower_env) / 2

def sift(signal, max_iter=1000, tol=1e-6):
    """对信号进行sifting操作,提取IMF"""
    h = signal
    for _ in range(max_iter):
        m = get_envelope_mean(h)
        h1 = h - m
        
        if np.mean(np.abs(h - h1)) < tol:
            break
        h = h1
    
    return h

def emd(signal, max_imfs=6):
    """进行EMD分解"""
    residual = signal
    imfs = []
    for _ in range(max_imfs):
        imf = sift(residual)
        imfs.append(imf)
        residual = residual - imf
        
        if np.all(np.abs(residual) < 1e-6):
            break
    
    return np.array(imfs), residual

# 执行EMD分解
imfs, residual = emd(ptb_cases.values)

# 绘制分解结果
num_imfs = imfs.shape[0]
plt.figure(figsize=(12, 9))
for i in range(num_imfs):
    plt.subplot(num_imfs + 1, 1, i + 1)
    plt.plot(time_series, imfs[i], label=f'IMF {i + 1}')
    plt.legend()

plt.subplot(num_imfs + 1, 1, num_imfs + 1)
plt.plot(time_series, residual, label='Residual')
plt.legend()
plt.tight_layout()
plt.show()

# LSTM模型
class LSTMModel(nn.Module):
    def __init__(self, input_size=1, hidden_layer_size=50, output_size=1):
        super(LSTMModel, self).__init__()
        self.hidden_layer_size = hidden_layer_size
        self.lstm = nn.LSTM(input_size, hidden_layer_size)
        self.linear = nn.Linear(hidden_layer_size, output_size)
        self.hidden_cell = (torch.zeros(1,1,self.hidden_layer_size),
                            torch.zeros(1,1,self.hidden_layer_size))

    def forward(self, input_seq):
        lstm_out, self.hidden_cell = self.lstm(input_seq.view(len(input_seq) ,1, -1), self.hidden_cell)
        predictions = self.linear(lstm_out.view(len(input_seq), -1))
        return predictions[-1]

def train_lstm_model(train_data, n_steps):
    model = LSTMModel(hidden_layer_size=100)  # 调整隐藏层大小
    loss_function = nn.MSELoss()
    optimizer = optim.Adam(model.parameters(), lr=0.001)  # 调整学习率
    epochs = 300  # 增加训练轮数

    for epoch in range(epochs):
        for seq in range(len(train_data) - n_steps):
            model.hidden_cell = (torch.zeros(1, 1, model.hidden_layer_size),
                                 torch.zeros(1, 1, model.hidden_layer_size))

            seq_train = torch.FloatTensor(train_data[seq:seq + n_steps])
            label = torch.FloatTensor(train_data[seq + n_steps:seq + n_steps + 1])

            optimizer.zero_grad()
            y_pred = model(seq_train)

            single_loss = loss_function(y_pred, label)
            single_loss.backward()
            optimizer.step()
        
        if epoch % 50 == 0:
            print(f'Epoch {epoch+1} loss: {single_loss.item()}')

    return model

def arima_model(train_data, order):
    model = ARIMA(train_data, order=order)
    model_fit = model.fit()
    return model_fit

n_steps = 10
imfs_lstm = [3, 4]  # 分配给LSTM的IMFs索引
imfs_arima = [0, 1, 2]  # 分配给ARIMA的IMFs索引

lstm_predictions = np.zeros(len(time_numeric))
arima_predictions = np.zeros(len(time_numeric))

# LSTM预测
for idx in imfs_lstm:
    print(f'Training LSTM for IMF {idx+1}')
    train_data = imfs[idx].flatten()
    model = train_lstm_model(train_data, n_steps)
    for i in range(n_steps, len(train_data)):
        seq = torch.FloatTensor(train_data[i-n_steps:i])
        with torch.no_grad():
            lstm_predictions[i] += model(seq).item()
    print(f'LSTM predictions for IMF {idx+1} completed')

# ARIMA预测
for idx in imfs_arima:
    print(f'Training ARIMA for IMF {idx+1}')
    train_data = imfs[idx]
    model_fit = arima_model(train_data, order=(5, 1, 0))
    arima_predictions += model_fit.predict(start=0, end=len(train_data) - 1)
    print(f'ARIMA predictions for IMF {idx+1} completed')

# 合并预测结果
final_predictions = lstm_predictions + arima_predictions

# 计算LSTM和ARIMA模型的误差
lstm_error = np.mean(ptb_cases - lstm_predictions)
arima_error = np.mean(ptb_cases - arima_predictions)

# 根据误差平移预测结果
final_predictions += (lstm_error + arima_error) / 2

# 计算误差
mae = mean_absolute_error(ptb_cases, final_predictions)
mse = mean_squared_error(ptb_cases, final_predictions)
rmse = np.sqrt(mse)
mape = np.mean(np.abs((ptb_cases - final_predictions) / ptb_cases)) * 100

# 打印误差
print(f'MAE: {mae}')
print(f'MSE: {mse}')
print(f'RMSE: {rmse}')
print(f'MAPE: {mape}')

# 绘制预测结果
plt.figure(figsize=(12, 6))
plt.plot(time_numeric, ptb_cases, label='Original Data')
plt.plot(time_numeric, final_predictions, label='Predicted Data')
plt.legend()
plt.show()

看看结果:

a16746d0046246e6b010ed115f534fd9.png

效果也不是太好。

 

六、最后

下一期,我们来测试一下其他矫正方法。

 

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

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

相关文章

vulnhub靶场【DriftingBlues】之7

前言 靶机&#xff1a;DriftingBlues-6&#xff0c;IP地址192.168.1.65 攻击&#xff1a;kali&#xff0c;IP地址192.168.1.16 都采用虚拟机&#xff0c;网卡为桥接模式 主机发现 使用arp-scan -l或netdiscover -r 192.168.1.1/24 信息收集 使用nmap扫描端口 SSH服务&…

[Unity]在unity 中输出调试安卓真机日志

添加包 Android Logcat com.unity.mobile.android-logcat 简单介绍常用的用法&#xff1a; 手机USB连接unity&#xff0c;下图可以看到手机型号 可以过滤具体软件的日志

centos stream 8下载安装遇到的坑

早在2020年12月。CentOS 官方发文宣称&#xff1a;“CentOS项目的未来是 CentOS Stream 明年我们会将重点从CentOS Linux 转移到CentOS Stream 它紧随当前 RHEL 版本之前。CentOS Linux 8 作为 RHEL 8 的重建&#xff0c;将于 2021 年底结束。CentOS Stream 在该日期之后继续&a…

信息安全实训室网络攻防靶场实战核心平台解决方案

一、引言 网络安全靶场&#xff0c;作为一种融合了虚拟与现实环境的综合性平台&#xff0c;专为基础设施、应用程序及物理系统等目标设计&#xff0c;旨在向系统用户提供全方位的安全服务&#xff0c;涵盖教学、研究、训练及测试等多个维度。随着网络空间对抗态势的日益复杂化…

视频孪生在景区文件场景中的应用

视频孪生技术在景区的应用主要体现在提升景区的智能化管理和游客的沉浸式体验上‌。依托于视频孪生时空承载平台&#xff0c;可在景区实景三维孪生场景中直观展示景区文物资源、建筑景观、自然景观等资源的类型、数量、空间分布等信息&#xff0c;并可详细查询单体景观详细资料…

电脑excel词典(xllex.dll)文件丢失是或损坏是什么原因?“xllex.dll文件缺失“要怎么解决?

Excel词典&#xff08;xllex.dll&#xff09;文件丢失或损坏&#xff1f;别担心&#xff0c;这里有解决之道&#xff01; 在日常的电脑使用和办公软件操作中&#xff0c;我们偶尔会碰到一些让人头疼的问题&#xff0c;比如Excel突然提示“Excel词典&#xff08;xllex.dll&…

【MySQL】优雅的使用MySQL实现分布式锁

MySQL实现分布式锁 引言二、基于唯一索引2.1、实现思路2.2、代码实现2.3、 测试代码2.4、小结 三、基于悲观锁3.1 、实现思路3.2、代码实现3.3、测试代码3.4、小结 四、基于乐观锁4.1 、实现思路4.2 、代码实现4.3 、测试代码4.4、小结 总结 引言 在文章《Redis实现分布式锁详…

Elasticsearch:使用 Open Crawler 和 semantic text 进行语义搜索

作者&#xff1a;来自 Elastic Jeff Vestal 了解如何使用开放爬虫与 semantic text 字段结合来轻松抓取网站并使其可进行语义搜索。 Elastic Open Crawler 演练 我们在这里要做什么&#xff1f; Elastic Open Crawler 是 Elastic 托管爬虫的后继者。 Semantic text 是 Elasti…

健康养生:拥抱生活的艺术

健康养生&#xff1a;拥抱生活的艺术 在快节奏的现代生活中&#xff0c;健康已成为我们最宝贵的财富。健康养生&#xff0c;不仅仅是一种生活方式的选择&#xff0c;更是一种对待生活的态度&#xff0c;它关乎于如何在日常中寻找到平衡&#xff0c;让身心得以滋养&#xff0c;…

零基础开始学习鸿蒙开发-交友软件页面设计

目录 1.找一张网图&#xff0c;确定大致页面设计 2.页面布局代码详细介绍 3.完整的代码如下 4.最终的运行效果如下图所示 5.总结 1.找一张网图&#xff0c;确定大致页面设计 2.页面布局代码详细介绍 2.1 顶部文字与搜索框布局&#xff0c;在顶部采用行Row组件布局&#xf…

大数据之Hbase环境安装

Hbase软件版本下载地址&#xff1a; http://mirror.bit.edu.cn/apache/hbase/ 1. 集群环境 Master 172.16.11.97 Slave1 172.16.11.98 Slave2 172.16.11.99 2. 下载软件包 #Master wget http://archive.apache.org/dist/hbase/0.98.24/hbase-0.98.24-hadoop1-bin.tar.gz…

【Java服务端开发】深入理解Java中的Server 层的详细分析

目录 1. 什么是服务端&#xff08;Server&#xff09;层&#xff1f; 2. 设计 Server 层的基本原则 2.1 单一职责原则 2.2 面向接口编程 2.3 事务管理 3. 基于 Spring 的 Server 层实现 3.1 示例&#xff1a;创建一个简单的订单服务 3.2 编写 OrderService 3.3 编写 O…

JAVA:代理模式(Proxy Pattern)的技术指南

1、简述 代理模式(Proxy Pattern)是一种结构型设计模式,用于为其他对象提供一种代理,以控制对这个对象的访问。通过代理模式,我们可以在不修改目标对象代码的情况下扩展功能,满足特定的需求。 设计模式样例:https://gitee.com/lhdxhl/design-pattern-example.git 2、什…

XXE练习

pikachu-XXE靶场 1.POC:攻击测试 <?xml version"1.0"?> <!DOCTYPE foo [ <!ENTITY xxe "a">]> <foo>&xxe;</foo> 2.EXP:查看文件 <?xml version"1.0"?> <!DOCTYPE foo [ <!ENTITY xxe SY…

Leetcode打卡:形成目标字符串需要的最少字符串数II

执行结果&#xff1a;通过 题目&#xff1a;3292 形成目标字符串需要的最少字符串数II 给你一个字符串数组 words 和一个字符串 target。 如果字符串 x 是 words 中 任意 字符串的 前缀 &#xff0c;则认为 x 是一个 有效 字符串。 现计划通过 连接 有效字符串形成 targ…

【蓝桥杯】49362.《视频相关度计算》

视频相关性计算 问题描述 小蓝作为异世界最大流媒体网站 LanTube 的高级算法工程师&#xff0c;他想要实现更加精准的视频推荐服务来满足用户的喜好。 其中&#xff0c;**“视频的相关性”**是一个重要指标&#xff0c;它代表了两个视频 A 到 B 的关联程度&#xff0c;记作 f…

ASP.NET|日常开发中数据集合详解

ASP.NET&#xff5c;日常开发中数据集合详解 前言一、数组&#xff08;Array&#xff09;1.1 定义和基本概念1.2 数组的操作 二、列表&#xff08;List<T>&#xff09;2.1 特点和优势2.2 常用操作 三、字典&#xff08;Dictionary<K, V>&#xff09;3.1 概念和用途…

如何将多张图片合并为一个pdf?多张图片合并成一个PDF文件的方法

如何将多张图片合并为一个pdf&#xff1f;当我们需要将多张图片合并为一个PDF文件时&#xff0c;通常是因为我们希望将这些图片整理成一个统一的文档&#xff0c;方便查看、分享或打印。无论是工作中需要提交的报告、学生们需要整理的作业&#xff0c;还是个人收藏的照片、旅行…

【html网页页面013】html+css制作节日主题圣诞节网页含视频、留言表单(独创首发-5页面附效果及源码)

节日主题圣诞节网页制作 &#x1f964;1、写在前面&#x1f367;2、涉及知识&#x1f333;3、网页效果完整效果(5页)&#xff1a;代码目录结构&#xff1a;page1、首页page2、庆祝page3、影响page4、起源page5、留言板 &#x1f308;4、网页源码4.1 html4.2 CSS4.3 源码获取圣诞…

直播预告 | 蓝卓生态说,解锁supOS在化工领域的无限可能

生态是蓝卓生命力的体现&#xff0c;为全方位赋能生态伙伴使用supOS并从中获益&#xff0c;蓝卓打造生态说系列栏目&#xff0c;通过生态沙龙、直播对话、案例剖析、产品解读等&#xff0c;持续展现“12N”的智能工厂创新路径&#xff0c;加速推进工业数字化转型。 嘉宾介绍 朱…