欢迎来到Easy数模!我们致力于分享简明、高质的数学建模知识,以实现数模技术普及和平权,今天我承接上篇CEEMDAN-LSTM算法,来继续聊一聊改进算法CEEMDAN-CNN-LSTM!欢迎关注Easy数模!带你一步步成为数模大佬!
在这个数据驱动的时代,精准预测未来需求、市场趋势甚至是健康状况,已成为各行各业保持竞争力的关键。
无论是电网中的电力负荷,金融市场的股价波动,还是零售行业的销量预测,我们都需要从复杂的时间序列数据中提取潜在规律。
今天,我们将介绍一套被称为“CEEMDAN-CNN-LSTM”的前沿算法,它结合了数据分解和深度学习的优势,让我们一起深入了解,这套“黑科技”算法如何让未来预测更精确、更智能!
算法白话文介绍
我们首先拿电力负荷预测场景来解读,预测电力负荷其实就像天气预报一样,必须得先把各种“天气因素”搞清楚。想象一下,电力负荷的变化就像天气,既有“气温”这种短期波动,也有“季节”这种长期趋势,要让预测精准,得把这两方面的“玄机”都搞透了。
那怎么搞呢?这就是我们今天要说的这套CEEMDAN-CNN-LSTM大法:
-
CEEMDAN:分解隐藏的“天气图”
想象电力负荷的原始数据是个复杂的“天气系统”,CEEMDAN方法相当于一个高科技显微镜,把这个系统层层剖析,分成了多个内在模态函数(IMF),也就是不同频率的“子天气图”。每张“子天气图”代表一个频率的波动,比如有的图显示“日常波动”,有的显示“月度变化”,各司其职又相互独立。这样一来,原本复杂的负荷数据就被拆成几部分,便于分析了。 -
CNN:细细分析每张“天气图”
CNN(卷积神经网络)是数据处理的能手,尤其适合抓住数据的“微妙纹路”。我们让CNN对每张“子天气图”进行处理,把数据中的局部特征挖掘出来。就好比天气预报员通过气压、温度等局部数据来推测天气趋势。这样,CNN帮助我们提取了数据中的短期波动特征,为后续的深度分析奠定了基础。 -
LSTM:记住“昨天的天气”,预测“明天的温度”
这里的LSTM(长短期记忆网络)好比一个超强记忆的天气预报员,它会记住昨天、前天等多天的数据,然后根据这些历史记录推测未来的负荷情况。LSTM尤其擅长处理时间序列,能从时间上的前后关联性中找到规律,用历史信息来更准确地预测未来。 -
多步预测:一口气预测未来几天
电力需求预测往往需要提前预测多个时间点的值,而不仅仅是预测接下来的一个时刻。这就是所谓的多步预测。借助LSTM,我们可以设定未来多个时间步的预测范围,一步一步地推出未来的负荷需求,就像天气预报可以给出未来几天的降水和温度变化。 -
误差评估:预测到底准不准?
最后一步,自然是评估一下预测效果。我们用了MSE、RMSE、MAE、MAPE和 ( R^2 ) 这几个“评分员”来打分,看预测结果是否“接地气”,准不准。预测准确率越高,我们的算法就越靠谱。
模型结构
本算法主要分为三个部分:数据分解、特征提取与时序预测。
-
CEEMDAN数据分解
CEEMDAN(Complete Ensemble Empirical Mode Decomposition with Adaptive Noise)是一种信号分解方法,将复杂时间序列分解成多个内在模态函数(IMFs)。每个IMF代表了不同频率的信息,有助于将数据分解成较为独立的分量,便于特征提取。- 公式:设原始电力负荷时间序列为
X
(
t
)
X(t)
X(t),CEEMDAN分解得到的内在模态函数为
I
M
F
i
(
t
)
IMF_i(t)
IMFi(t),则:
X ( t ) = ∑ i = 1 n I M F i ( t ) + R ( t ) X(t) = \sum_{i=1}^{n} IMF_i(t) + R(t) X(t)=i=1∑nIMFi(t)+R(t)
其中 R ( t ) R(t) R(t) 为残差项,表示分解后的低频趋势部分。
- 公式:设原始电力负荷时间序列为
X
(
t
)
X(t)
X(t),CEEMDAN分解得到的内在模态函数为
I
M
F
i
(
t
)
IMF_i(t)
IMFi(t),则:
-
卷积神经网络(CNN)特征提取
卷积神经网络在图像和序列数据处理中表现优异,尤其适合提取局部特征。本文利用一维卷积层(1D-CNN)提取每个IMF中的局部高频特征,进一步输入至LSTM网络中,以捕捉复杂的短期依赖关系。- 公式:一维卷积计算过程:
y [ i ] = ∑ j = 1 k x [ i + j − 1 ] ⋅ w [ j ] y[i] = \sum_{j=1}^{k} x[i+j-1] \cdot w[j] y[i]=j=1∑kx[i+j−1]⋅w[j]
其中, x x x 为输入数据, w w w 为卷积核, k k k 为卷积核大小。
- 公式:一维卷积计算过程:
-
LSTM网络的时序预测
长短时记忆网络(LSTM)对时序数据中的长短期依赖具有良好记忆和建模能力。模型将从CNN提取的特征传入LSTM,进一步预测未来的电力负荷数值。通过在LSTM中设置多步预测,模型可以逐步输出未来多个时间步的预测值。- 公式:LSTM单元计算公式:
f t = σ ( W f ⋅ [ h t − 1 , x t ] + b f ) f_t = \sigma(W_f \cdot [h_{t-1}, x_t] + b_f) ft=σ(Wf⋅[ht−1,xt]+bf)
i t = σ ( W i ⋅ [ h t − 1 , x t ] + b i ) i_t = \sigma(W_i \cdot [h_{t-1}, x_t] + b_i) it=σ(Wi⋅[ht−1,xt]+bi)
C ~ t = tanh ( W C ⋅ [ h t − 1 , x t ] + b C ) \tilde{C}_t = \tanh(W_C \cdot [h_{t-1}, x_t] + b_C) C~t=tanh(WC⋅[ht−1,xt]+bC)
C t = f t ⋅ C t − 1 + i t ⋅ C ~ t C_t = f_t \cdot C_{t-1} + i_t \cdot \tilde{C}_t Ct=ft⋅Ct−1+it⋅C~t
o t = σ ( W o ⋅ [ h t − 1 , x t ] + b o ) o_t = \sigma(W_o \cdot [h_{t-1}, x_t] + b_o) ot=σ(Wo⋅[ht−1,xt]+bo)
h t = o t ⋅ tanh ( C t ) h_t = o_t \cdot \tanh(C_t) ht=ot⋅tanh(Ct)
其中, f t f_t ft、 i t i_t it、 o t o_t ot 分别为遗忘门、输入门和输出门; h t h_t ht 为隐藏状态, C t C_t Ct 为单元状态。
- 公式:LSTM单元计算公式:
-
误差评估指标
为了评估预测效果,我们采用均方误差(MSE)、均方根误差(RMSE)、平均绝对误差(MAE)、平均绝对百分比误差(MAPE)和 R 2 R^2 R2 评估模型性能。- 均方误差(MSE):
M S E = 1 n ∑ i = 1 n ( y i − y ^ i ) 2 MSE = \frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2 MSE=n1i=1∑n(yi−y^i)2 - 均方根误差(RMSE):
R M S E = 1 n ∑ i = 1 n ( y i − y ^ i ) 2 RMSE = \sqrt{\frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2} RMSE=n1i=1∑n(yi−y^i)2 - 平均绝对误差(MAE):
M A E = 1 n ∑ i = 1 n ∣ y i − y ^ i ∣ MAE = \frac{1}{n} \sum_{i=1}^{n} |y_i - \hat{y}_i| MAE=n1i=1∑n∣yi−y^i∣ - 平均绝对百分比误差(MAPE):
M A P E = 100 % n ∑ i = 1 n ∣ y i − y ^ i y i ∣ MAPE = \frac{100\%}{n} \sum_{i=1}^{n} \left| \frac{y_i - \hat{y}_i}{y_i} \right| MAPE=n100%i=1∑n yiyi−y^i -
R
2
R^2
R2值:衡量模型拟合度,值越接近1表示模型越准确。
R 2 = 1 − ∑ i = 1 n ( y i − y ^ i ) 2 ∑ i = 1 n ( y i − y ˉ ) 2 R^2 = 1 - \frac{\sum_{i=1}^{n} (y_i - \hat{y}_i)^2}{\sum_{i=1}^{n} (y_i - \bar{y})^2} R2=1−∑i=1n(yi−yˉ)2∑i=1n(yi−y^i)2
- 均方误差(MSE):
python代码案例
导入必要库
首先导入各类Python库,包括pandas
、numpy
、matplotlib
、tensorflow.keras
等,用于数据处理、深度学习模型构建、特征预处理和评估等任务。
import os # 系统操作功能
import math # 提供数学计算功能
import pandas as pd # 用于数据处理和分析
import numpy as np # 用于数值计算和数据操作
from math import sqrt # 用于计算平方根
from numpy import concatenate # 数组拼接
import matplotlib.pyplot as plt # 数据可视化
from sklearn.preprocessing import MinMaxScaler, StandardScaler, LabelEncoder # 特征缩放与标签编码
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score # 误差计算
from tensorflow.keras.layers import * # 导入深度学习网络各类层
from tensorflow.keras.models import * # 导入神经网络模型构建工具
from scipy.io import savemat, loadmat # 读取和保存MATLAB文件
from sklearn.neural_network import MLPRegressor # 多层感知器回归模型
from keras.callbacks import LearningRateScheduler # 动态学习率调整
import warnings # 消除警告信息
from prettytable import PrettyTable # 美观打印表格结果
warnings.filterwarnings("ignore") # 取消警告
pandas
和numpy
用于加载和操作数据。tensorflow.keras.layers
中的卷积层(Conv1D
)、池化层(MaxPooling1D
)、LSTM和全连接层(Dense
)用于构建深度学习模型。MinMaxScaler
用于将数据标准化到 [0,1] 区间,mean_squared_error
等用于计算误差。
数据加载与预处理
通过pandas
库加载电力负荷数据的CSV文件和CEEMDAN分解的Excel文件,并确保数据类型一致。
dataset = pd.read_csv("电力负荷预测数据.csv", encoding='gb2312')
dataset_vmd = pd.read_excel("CEEMDAN.xlsx")
values = dataset.values[:, 1:].astype('float32') # 只取特征数据
values_vmd = dataset_vmd.values.astype('float32') # CEEMDAN分解数据
dataset
:加载原始电力负荷数据。dataset_vmd
:加载CEEMDAN分解的IMF数据。values
和values_vmd
分别存储特征数据和分解后的数据,并转换为float32
类型,确保数据一致性。
数据构建函数
data_collation
函数使用滑窗方法处理数据,将多步预测的数据构建为输入和输出对。
def data_collation(data, n_in, n_out, or_dim, scroll_window, num_samples):
res = np.zeros((num_samples, n_in * or_dim + n_out))
for i in range(num_samples):
h1 = data[scroll_window * i: n_in + scroll_window * i, 0:or_dim]
h2 = h1.reshape(1, n_in * or_dim)
h3 = data[n_in + scroll_window * i: n_in + scroll_window * i + n_out, -1].T
res[i, :] = np.hstack((h2, h3))
return res
n_in
:输入的时间步长(可以调节),例如n_in=5
表示使用前5行数据作为模型输入。n_out
:输出的预测步数(可以调节),例如n_out=1
表示预测未来1步的数据。scroll_window
:滑动窗口的移动步长(可以调节),例如scroll_window=1
表示每次滑动1行。- 函数返回二维数组
res
,每一行包含n_in
步的输入和n_out
步的输出。
CNN-LSTM模型构建函数
cnn_lstm_model
函数定义了一个CNN-LSTM结构,用于时序数据的特征提取和预测。
def cnn_lstm_model():
inputs = Input(shape=(vp_train.shape[1], vp_train.shape[2]))
conv1d = Conv1D(filters=32, kernel_size=2, activation='relu')(inputs)
maxpooling = MaxPooling1D(pool_size=2)(conv1d)
reshaped = Reshape((-1, 32))(maxpooling)
lstm = LSTM(128, activation='selu', return_sequences=False)(reshaped)
outputs = Dense(vt_train.shape[1])(lstm)
model = Model(inputs=inputs, outputs=outputs)
model.compile(loss='mse', optimizer='Adam')
model.summary()
return model
Conv1D
:一维卷积层,32个过滤器,卷积核大小为2,activation='relu'
。该层提取局部特征。MaxPooling1D
:最大池化层,pool_size=2
表示池化核大小为2。Reshape
:将数据的形状调整为(-1, 32)
,以匹配LSTM层的输入。LSTM
:LSTM层,128个神经元,activation='selu'
,处理时间序列特征。Dense
:全连接层,输出的神经元数量与vt_train.shape[1]
相同,用于生成预测输出。model.compile(loss='mse', optimizer='Adam')
:指定损失函数为MSE(均方误差),优化器为Adam。
数据构建与归一化
将特征和标签划分为训练集和测试集,且在构建完训练集和测试集后进行归一化处理。
n_train_number = int(num_samples * 0.85) # 85%用于训练
Xtrain = combined_data[:n_train_number, :n_in * or_dim]
Ytrain = combined_data[:n_train_number, n_in * or_dim:]
Xtest = combined_data[n_train_number:, :n_in * or_dim]
Ytest = combined_data[n_train_number:, n_in * or_dim:]
m_in = MinMaxScaler()
vp_train = m_in.fit_transform(Xtrain)
vp_test = m_in.transform(Xtest)
m_out = MinMaxScaler()
vt_train = m_out.fit_transform(Ytrain)
vt_test = m_out.transform(Ytest)
n_train_number
:设置训练集大小(可调),例如85%
表示数据的85%用于训练。Xtrain
、Ytrain
:训练集的输入和输出数据。Xtest
、Ytest
:测试集的输入和输出数据。MinMaxScaler
用于将数据归一化到 [0, 1] 区间,提升模型的训练效果。
模型训练与预测
使用构建好的CNN-LSTM模型进行训练,并对测试集生成预测。
model = cnn_lstm_model()
model.fit(vp_train, vt_train, batch_size=32, epochs=50, validation_split=0.25, verbose=2)
yhat = model.predict(vp_test)
yy = m_out.inverse_transform(yhat.reshape(num_samples - n_train_number, n_out))
predicted_data.append(yy)
actual_data.append(Ytest)
batch_size=32
:每次迭代的样本数(可调),例如batch_size=32
表示每批次处理32个样本。epochs=50
:训练轮数(可调),例如epochs=50
表示数据迭代50次。validation_split=0.25
:25%数据用于验证。yhat
为预测值,反归一化后得到实际预测值。
模型评估
定义evaluate_forecasts
函数,使用多种指标评估模型性能。
def evaluate_forecasts(Ytest, predicted_data, n_out):
table = PrettyTable(['测试集指标','MSE', 'RMSE', 'MAE', 'MAPE','R2'])
for i in range(n_out):
actual = [float(row[i]) for row in Ytest]
predicted = [float(row[i]) for row in predicted_data]
mse = mean_squared_error(actual, predicted)
rmse = sqrt(mse)
mae = mean_absolute_error(actual, predicted)
MApe = mape(actual
, predicted)
r2 = r2_score(actual, predicted)
strr = '预测结果指标:' if n_out == 1 else '第' + str(i + 1) + '步预测结果指标:'
table.add_row([strr, mse, rmse, mae, f"{MApe}%", f"{r2*100}%"])
return table
- 使用MSE、RMSE、MAE、MAPE和 R 2 R^2 R2 评估模型的预测效果。
PrettyTable
以表格形式展示各项指标,直观了解模型性能。
预测结果绘图
使用matplotlib
绘制预测和实际值的对比图,直观展示预测效果。
for ii in range(n_out):
plt.style.use('cyberpunk')
plt.figure(figsize=(10, 2), dpi=300)
x = range(1, len(actual_test) + 1)
plt.xticks(x[::int((len(actual_test)+1))])
plt.plot(x, pre_test[:,ii], linestyle="--", linewidth=0.5, label='predict')
plt.plot(x, actual_test[:,ii], linestyle="-", linewidth=0.5,label='Real')
plt.legend(loc='upper right', frameon=False)
plt.xlabel("Sample points", fontsize=5)
plt.ylabel("value", fontsize=5)
plt.title(f"{ii+1} step of CEEMDAN-CNN-LSTM prediction\nMAPE: {mape(actual_test[:,ii], pre_test[:,ii])} %")
plt.show()
plt.plot
绘制预测值和实际值,linestyle="--"
设置预测值为虚线,实际值为实线。x
轴为样本点,y
轴为值,标题显示预测步数和MAPE误差。
模型优化
最后,模型引入注意力机制(Attention Mechanism)可以提高CEEMDAN-CNN-LSTM算法在预测中的表现。
Attention机制允许模型在处理时间序列数据时,动态分配不同时间步的权重,使模型能够关注对预测结果影响较大的关键数据点。
这在长序列预测中尤其有效,能够缓解信息随时间衰减的问题,提高预测精度。通过在LSTM层后加入Attention层,模型能更好地捕捉数据中的重要特征,优化未来趋势的预测效果。
感兴趣的小伙伴可以大胆尝试一下哦!