全文链接:https://tecdat.cn/?p=38224
原文出处:拓端数据部落公众号
分析师:Duqiao Han
股票市场是一个复杂的非线性系统,股价受到许多经济和社会因素的影响。因此,传统的线性或近线性预测模型很难有效、准确地预测股票指数的价格趋势。众所周知,深度学习通过逐层特征转换,将原始空间中样本的特征表示转换为新的特征空间,并提取大量原始时间序列数据的特征,从而使预测更加容易。
KPCA-EMD-CEEMDAN-LSTM的股指收盘价格预测介绍
金融市场中,股指收盘价格的准确预测对于投资者、金融机构等具有重要意义。然而,金融时间序列的不稳定特征往往使得传统预测方法效果欠佳。因此,探索更为有效的预测模型成为研究热点。
相关方法介绍
(一)KPCA(核主成分分析)
在对初始数据进行处理时,我们采用 KPCA 来实现降维操作。其核心在于引入非线性映射函数,以此挖掘数据集中所包含的非线性信息,并且把原始空间中的数据映射到高维空间。具体而言,其包含以下几个关键步骤:
- 计算核矩阵:通过特定的核函数来计算数据点之间的关系矩阵,这一步骤为后续分析奠定基础。
- 集中化核矩阵:对核矩阵进行集中化处理,使得数据在某种程度上更加规整,便于后续的分解等操作。
- 分解特征值:将处理后的核矩阵进行特征值分解,以获取数据的主要特征信息。
- 将特征向量标准化:把得到的特征向量进行标准化操作,确保各特征向量具有可比性。
- 选择主分量的数量:依据一定的标准,从众多的特征分量中挑选出合适数量的主分量,用于后续的计算。
- 计算主非线性分量:基于前面所选的主分量,进一步计算出主非线性分量,从而完成 KPCA 的降维过程。
(二)EMD-CEEMDAN(经验模态分解及改进算法)
首先,利用 EMD 对实验数据进行分解操作。在这个过程中,会通过筛选的方式来选择出那些异常的 IMF(本征模函数)分量。然后,基于 EMD 算法,通过降噪处理得到正常的 IMF 分量,并在对重构残差 IMF 后进行直接分解。最后,提取每个 IMF 分量的能量作为一个特征,以此构造一个特征集。
(三)Regularized LSTM(正则化长短期记忆网络)
深度学习模型尤其是 LSTM 在处理金融时间序列预测时,存在一些问题。由于其本身是一个黑箱模型,有时会出现模型过于复杂以及过拟合的情况,这就导致训练出来的模型预测效果较差。
为此,本文采用 L2 正则化方法在原目标函数上添加一个惩罚项。这个惩罚项的作用是惩罚那些高复杂度的模型,从而减少使模型过于复杂的干扰特性,有效改善过拟合问题,进而提高模型的预测效率。
主要创新点
(一)分解方法创新
引入(1)- 双分解来取代传统的经验模式分解方法来分解金融时间序列趋势。这种创新的分解方法能够更有效地处理金融时间序列中的复杂成分,提取出更有价值的特征信息,相比传统的 EMD 分解方法具有明显优势。
(二)特征因素选择
结合实际投资经验,选择了相对更全面、更合理的特征因素。具体而言,包括 CSI 300 指数的技术分析指标和相应的基础分析指标,并考虑了国内外金融市场的其他交易。选择 CSI 300 指数品种的影响,并选择这些交易品种的市场数据提取特征。通过这种全面合理的特征因素选择,能够使预测模型更好地捕捉到与股指收盘价格相关的各种信息,提高预测的准确性。
(三)LSTM 模型正则化
对 LSTM 模型进行正则化处理,建立 LSTM - 正则模型来预测 CSI 300 指数在下一个交易日的走势趋势,获得比 LSTM 更好的预测精度。通过正则化操作,有效克服了 LSTM 模型过拟合的问题,使得模型在实际预测中能够更加稳定、准确地输出预测结果。
实验设置与结果
在实验中,使用滑动时间窗来构建样本,滑动窗口的宽度为 10。通过这样的样本构建方式,能够更好地利用历史数据,同时兼顾数据的时效性。
在进行各项操作如 KPCA 因子降维、EMD-LSTM 对偶分解以及 LSTM 正则化等之后,对构建的预测模型 KPCA-EMD-LSTM - 正则进行验证。结果表明,模型正则化、KPCA 因子降维、EMD-LSTM 对偶分解操作均起到了优化作用,充分验证了预测模型 KPCA-EMD-LSTM - 正则的优越性。
请注意,在相关实验过程中可能会涉及到一些图表来展示数据和结果
金融时间序列的不稳定特征对其预测效果产生了不利影响。传统的EMD分解方法为缓解这种不利影响提供了思路。本文采用EMD-塞姆丹对偶分解代替传统的EMD分解,并补充了KPCA因子降维和模型正则化,构建了比传统的LSTM模型更准确的KPCA-EMD-LSTM-正则预测模型。本文充分考虑了CSI 300指数的相关因子,构建了一个完整的因子库。在实验中,使用滑动时间窗来构建样本,滑动窗口的宽度为10。最后,验证了模型正则化、KPCA因子降维、EMD-LSTM对偶分解操作的优化,以及预测模型KPCA-EMD-LSTM-正则的优越性。
CEEMDAN-LSTM 及其相关模型(SVR、AR、HAR)在金融数据预测|附数据代码
本文聚焦于金融数据的分析与预测,详细阐述了运用 CEEMDAN-LSTM 模型以及其他相关模型(如 SVR、AR、HAR)进行数据处理和预测的具体流程。通过对原数据的展示、关键指标的计算、数据分解及各模型的构建与评估等环节的深入探讨,并结合相关可视化图像的辅助说明,全面展示了不同模型在金融数据预测中的应用效果,为金融数据分析与预测领域提供了有价值的参考。
在金融市场的研究与实践中,准确预测金融数据的走势对于投资者、金融机构等各类市场参与者具有至关重要的意义。为了实现更精准的预测,本文引入了多种先进的数据处理方法和预测模型,其中重点探讨了 CEEMDAN-LSTM 及其相关模型在金融数据预测中的应用,并对其性能进行了详细分析。
数据准备与初步处理
(一)导入库与设置绘图格式
首先,我们导入了一系列在金融数据分析过程中常用的库。pandas
库主要用于数据的读取、处理和分析操作;numpy
库则提供了强大的数值计算功能,便于进行各种数学运算;matplotlib.pyplot
库用于绘制各类图表,以直观展示数据的特征和变化趋势。同时,还导入了datetime
库用于处理日期相关的操作,并通过warnings.filterwarnings('ignore')
语句忽略了可能出现的警告信息,确保程序运行过程中不会因一些非关键警告而中断。
此外,为了使绘制的图表更加美观、规范,我们设置了绘图的风格为seaborn
,并指定了图形的大小为长 12 单位、宽 6 单位,分辨率为每英寸 300 像素,即通过以下代码实现:
-
plt.style.use('seaborn')
-
plt.rcParams['figure.figsize'] = [12, 6]
-
plt.rcParams['figure.dpi'] = 300
(二)原数据展示
在对数据进行深入分析之前,我们先对原始数据进行了初步展示,通过temp_data.head()
语句可以查看原始数据temp_data
的前几行内容,以便对数据的整体结构和大致情况有一个直观的认识。
(三)计算 RV 值及相关处理
1. RV 值计算函数定义
为了后续分析的需要,我们定义了一个函数RV
用于计算已实现波动率(RV)值。其计算原理是先对输入数据的每个元素进行平方操作,然后求和,最后再对求和结果进行开平方运算,具体代码如下:
-
def RV(x):
-
return np.sqrt(np.sum(x**2))
该函数接受一个数据序列x
作为输入参数,经过上述计算步骤后返回对应的 RV 值。
2. 对数收益率计算与 RV 值按日计算
在金融数据分析中,对数收益率是一个重要的指标。我们通过以下代码计算了数据的对数收益率,并将其存储在新的列'log return'
中:
-
data['log return'] = np.log(data['close'] / data['close'].shift(1))
-
dfr = data.loc[:, 'log return'].copy()
这里,先通过np.log(data['close'] / data['close'].shift(1))
计算出每一行数据相对于上一行数据的对数收益率,然后将其提取出来赋值给dfr
变量以便后续操作。
接着,我们按照一日周期对对数收益率数据进行分组,并应用前面定义的RV
函数来计算每日的 RV 值,最后将计算得到的 RV 值添加到原始数据data
的新列'RV'
中,同时,为了避免数据中可能出现的无穷大值对后续分析造成影响,我们将其替换为 0,具体代码如下:
-
dfrv = dfr.groupby(pd.Grouper(freq='1d')).apply(RV)
-
data['RV'] = dfrv
-
data.replace(np.inf, 0, inplace=True)
在完成 RV 值的计算和处理后,我们还绘制了 RV 值的时间序列图
CEEMDAN 分解与可视化
在对数据进行进一步分析时,我们采用了 CEEMDAN 方法对数据进行分解,并对分解结果进行了可视化展示。首先,我们创建了一个时间序列t
,其取值范围是从 0 到 RV 值数据序列RVs
的长度,步长为 1,即通过t = np.arange(0, len(RVs), 1)
语句实现。
然后,我们调用了Visualisation
类(这里假设该类已经在其他地方定义好,用于数据可视化相关的操作)的相关方法进行数据分解结果的可视化。通过vis.plot_imfs(imfs=imfs_close, residue=res_close, t=t, include_residue=True)
语句,将分解得到的本征模函数(IMFs)和残差按照时间序列t
进行绘制,并设置了包含残差的可视化选项。虽然代码中还存在vis.plot_instant_freq(t, imfs=imfs)
这样的注释行(可能用于绘制即时频率相关的内容,但在当前示例中未启用),最后通过vis.show()
方法将绘制好的图像展示出来
在完成 CEEMDAN 分解的可视化后,我们还对分解后的数据进一步提取了多种特征,如计数、均值、标准差、偏度、峰度、JB 统计量、Q 统计量(这里假设de_count
、de_mean
、de_std
、de_skew
、de_kurtosis
、de_jb
、de_Q
等变量已经在前面的代码中计算得到),并将这些特征整理成数据框decompose_data_feature
进行展示,具体代码如下:
-
de_data_feature = np.vstack((de_count, de_mean, de_std, de_skew, de_kurtosis, de_jb, de_Q)).T
-
decompose_data_feature = pd.DataFrame(de_data_feature, columns = ['count', 'mean', 'std', 'skew', 'kurtosis', 'J-B', 'Q(10)'], index = decompose_data.columns)
通过上述代码,我们将提取的各种特征按照指定的列名和索引进行整理,形成了一个便于查看和分析的数据框
建模与预测
(一)直接 LSTM 建模
1. 数据划分
在构建直接 LSTM 模型进行预测之前,我们首先需要对数据进行划分,确定训练集、验证集和测试集。这里我们设定了窗口大小为26
,通过调用get_tain_val_test
函数(这里假设该函数已经在其他地方定义好,用于按照指定窗口大小划分数据)对 RV 值数据RVs
进行处理,划分出训练集、验证集和测试集,分别得到x_train_all
、y_train_all
、x_val_all
、y_val_all
、x_test_all
、y_test_all
,具体代码如下:
-
window_size = 26
-
x_train_all, y_train_all, x_val_all, y_val_all, x_test_all, y_test_all = get_tain_val_test(RVs, window_size)
2. LSTM 模型构建与训练
在完成数据划分后,我们调用implement_LSTM
函数(同样假设该函数已在其他地方定义好,用于构建和训练 LSTM 模型),使用划分好的训练集和验证集数据构建并训练 LSTM 模型,得到训练历史信息history
和训练好的模型model
,具体代码如下:
history, model = implement_LSTM(x_train_all, y_train_all, x_val_all, y_val_all)
3. 预测与可视化
利用训练好的模型对测试集数据x_test_all
进行预测,通过model.predict(x_test_all).reshape(-1)
语句得到预测结果y_pre_all
,并将其转换为一维数组形式以便后续分析。同时,提供了相关的可视化图像
deecman + LSTM 建模
1. 数据处理与模型训练
针对经过 CEEMDAN 分解后的数据decompose_data
的每一列数据,我们分别进行如下操作:首先提取每列数据作为时间序列数据serie_data
,然后按照设定的窗口大小window_size
,通过调用get_tain_val_test
函数划分出训练集、验证集和测试集,再调用implement_LSTM
函数构建并训练 LSTM 模型,得到每列数据的预测结果y_pre
并添加到列表y_pre_list
中,同时将对应的测试集数据添加到列表y_test_list
中。具体代码如下:
-
y_pre_list = []
-
y_test_list = []
-
for column in decompose_data.columns:
-
serie_data = decompose_data[column]
-
x_train, y_train, x_val, y_val, x_test, y_test = get_tain_val_test(serie_data, window_size)
-
history, model = implement_LSTM(x_train, y_train, x_val, y_val)
-
y_pre = model.predict(x_test)
-
y_pre_list.append(y_pre)
-
y_test_list.append(y_test)
2. 预测结果可视化与汇总
为了更直观地展示每列数据的预测结果与实际值的对比情况,我们通过绘制多个子图的方式进行可视化。首先创建一个指定大小的图形对象fig
,然后通过循环遍历decompose_data.columns
,在每个子图中分别绘制对应列数据的实际值和预测值,并添加相应的图例说明,具体代码如下:
-
fig = plt.figure(figsize=(10, 20))
-
for i, column in enumerate(decompose_data.columns):
-
axes = fig.add_subplot(len(decompose_data.columns), 1, i + 1)
-
axes.plot(y_test_list[i], 'b-', linewidth = '1', label='实际')
-
axes.plot(y_pre_list[i], 'r-', linewidth = '1', label='预测')
-
plt.legend()
对应的可视化
最后,我们将所有列数据的预测结果进行求和汇总,通过y_pre_total = np.sum(np.array(y_pre_list), axis = 0).reshape(-1)
语句得到总的预测结果y_pre_total
,并计算了该预测结果与原始测试集数据y_test_all
对比的多种评估指标,如平均绝对误差(MAE)、均方误差(MSE)、分层平均绝对误差(HMAE)、分层均方误差(HMSE)等,通过以下代码输出这些评估指标的值:
-
print("MAE:", mean_absolute_error(y_test_all, y_pre_total))
-
print("MSE:", mean_squared_error(y_test_all, y_pre_total))
-
print("HMAE:", h_mean_absolute_error(y_test_all, y_pre_total))
-
print("HMSE:", h_mean_squared_error(y_test_all, y_pre_total))
对应的评估结果可视化图像
其他相关模型
SVR 模型
对于 SVR 模型,我们分别对训练集、验证集和测试集数据(x_train_all
、x_val_all
、x_test_all
)使用 SVR 模型进行预测,通过svr.predict
函数得到预测结果y_pre_all_svr1
、y_pre_all_svr2
、y_pre_all_svr3
,然后将这些预测结果进行水平拼接得到总的预测结果y_pre_all_svr
,同时将对应的真实标签数据y_train_all
、y_val_all
、y_test_all
也进行水平拼接得到y_all_label
。具体代码如下:
-
y_pre_all_svr1 = svr.predict(x_train_all)
-
y_pre_all_svr2 = svr.predict(x_val_all)
-
y_pre_all_svr3 = svr.predict(x_test_all)
-
y_pre_all_svr = np.hstack((y_pre_all_svr1, y_pre_all_svr2, y_pre_all_svr3))
-
y_all_label = np.hstack((y_train_all, y_val_all, y_test_all))
并提供了相关的可视化图像
AR 模型
1. 模型拟合
从statsmodels.tsa.ar_model
导入AutoReg
类,首先确定训练数据的长度(取 RVs 数据长度的 90%),然后使用二阶 AR 模型对训练数据RVs[:train_lenth]
进行拟合,得到拟合好的 AR 模型AR_model
,具体代码如下:
-
from statsmodels.tsa.ar_model import AutoReg
-
import numpy as np
-
-
train_lenth = int(len(RVs) * 0.9)
-
AR_model = AutoReg(RVs[:train_lenth], 2).fit()
2. 预测与数据拼接
使用拟合好的 AR 模型分别对训练数据范围内和后续测试数据范围进行预测,通过AR_model.predict(0, train_lenth).values
和AR_model.forecast(len(y_test_all)).values
得到预测结果predict_AR_1
和predict_AR_2
,再将这两个预测结果进行水平拼接得到总的预测结果predict_all_ar
,同时将对应的真实标签数据y_train_all
、y_val_all
、y_test_all
也进行水平拼接得到y_all_label
。具体代码如下:
-
predict_AR_1 = AR_model.predict(0, train_lenth).values
-
predict_AR_2 = AR_model.forecast(len(y_test_all)).values
-
predict_all_ar = np.hstack((predict_AR_1, predict_AR_2))
-
y_all_label = np.hstack((y_train_all, y_val_all, y_test_all))
并提供了相关的可视化图像
HAR 模型
1. 数据准备
首先将 RVs 数据进行移位操作(RVs.shift(-1)
),目的是为了预测下一天的 RV 值,得到目标数据RVs_target
。
然后将原始 RV
s 数据(除最后一个数据点)作为特征数据X
,对应的移位后的数据(除最后一个数据点)作为目标数据y
,具体代码如下:
-
RVs_target = RVs.shift(-1) # 这里是为了预测下一天的RV值
-
X = RVs[:-1]
-
y = RVs_target[:-1]
2. 数据划分与预测
按照 90% 的比例划分训练集和测试集,通过split = int(0.90 * RVs.shape[0])
确定划分点,然后得到X_train
、X_test
、y_train
、y_test
,分别作为训练集的特征数据、测试集的特征数据、训练集的目标数据、测试集的目标数据。虽然文中未明确给出后续基于 HAR 模型的具体预测操作及结果展示,但通过前面的数据准备和划分步骤,为进一步使用 HAR 模型进行预测奠定了基础。同时,也提供了相关的可视化图像
结论
本文详细介绍了基于 CEEMDAN-LSTM 及其相关模型(SVR、AR、HAR)在金融数据预测中的应用流程。从数据的初步处理,包括原数据展示、RV 值计算等,到采用 CEEMDAN 方法进行数据分解与可视化,再到各模型的构建、训练、预测以及性能评估等环节,都进行了深入探讨。
通过对不同模型的分析可知,每种模型都有其特点和适用场景。直接 LSTM 模型在处理整体数据时能够给出一定的预测结果;CEEMDAN + LSTM 模型结合了数据分解的优势,对分解后的各部分数据分别进行预测并汇总,能更细致地捕捉数据特征,其评估指标可反映出预测性能;SVR 模型、AR 模型和 HAR 模型也各自通过不同的方式对数据进行处理和预测,相应的可视化图像和数据拼接等操作有助于我们直观了解其预测效果。
然而,各模型在实际应用中也存在一定的局限性,例如某些模型可能对数据的特定分布或趋势较为敏感,导致在不同数据集上的预测效果有所差异。未来的研究可以进一步探索如何更好地结合这些模型的优势,或者对模型进行改进以适应更复杂的金融数据环境,从而提高金融数据预测的准确性和可靠性,为金融市场参与者提供更有价值的决策参考。
CEEMDAN_VMD_GRU 在股票数据预测中的应用|附数据代码
本文详细介绍了一种基于 CEEMDAN(完全集成经验模态分解与自适应噪声)、VMD(变分模态分解)和 GRU(门控循环单元)的股票数据预测方法。通过对原始股票数据进行一系列分解、聚类、建模及预测操作,展示了该方法在处理股票价格预测问题上的流程及优势,为相关领域的研究与实践提供了参考。
股票市场的价格预测一直是金融领域的研究热点,准确的预测对于投资者制定合理的投资策略具有重要意义。随着数据挖掘和机器学习技术的发展,多种方法被应用于股票价格预测。本文所探讨的 CEEMDAN_VMD_GRU 方法旨在综合多种先进的数据处理和预测技术,提高股票价格预测的准确性。
相关方法及函数实现
(一)数据预处理与分解函数
- ceemdan_decompose 函数(CEEMDAN 分解)
-
def ceemdan_decompose(series=None, trials=10, num_clusters = 3): # CEEMDAN分解函数
-
decom = CEEMDAN()
-
decom.trials = trials # 输入的白噪声数量
-
df_ceemdan = pd.DataFrame(decom(series.values).T)
-
df_ceemdan.columns = ['imf'+str(i) for i in range(len(df_ceemdan.columns))]
-
return df_ceemdan
该函数用于对输入的时间序列数据(如股票价格数据)进行 CEEMDAN 分解。首先创建 CEEMDAN 对象并设置白噪声输入的次数,然后对数据进行分解操作,将结果转换为 DataFrame 格式并为各列命名,最终返回分解后的结果。通过这种分解,可以将原始数据分解为多个本征模函数(IMF)分量,以便后续进一步分析和处理。
- sample_entropy 函数(样本熵计算)
-
def sample_entropy(df_ceemdan=None, mm=1, r=0.1): # 样本熵计算函数;mm取值为1或2;r取值为0.1或0.2
-
np_sampen = []
-
for i in range(len(df_ceemdan.columns)):
-
sample_entropy = sampen2(list(df_ceemdan['imf'+str(i)].values),mm=mm,r=r,normalize=True)
-
np_sampen.append(sample_entropy[1][1])
-
df_sampen = pd.DataFrame(np_sampen, index=['imf'+str(i) for i in range(len(df_ceemdan.columns))], columns=['CODE'])
-
return df_sampen
此函数用于计算 CEEMDAN 分解后各 IMF 分量的样本熵。通过遍历各 IMF 分量,调用sampen2
函数计算其样本熵,并将结果整理为 DataFrame 格式返回。样本熵可用于衡量时间序列的复杂性和不规则性,为后续基于熵值的聚类等操作提供依据。
- kmeans_cluster 函数(基于样本熵的 K-Means 聚类)
-
def kmeans_cluster(df_sampen=None, num_clusters=3): # 基于样本熵进行K-Means聚类
-
np_integrate_form = KMeans(n_clusters=num_clusters, random_state=9).fit_predict(df_sampen)
-
df_integrate_form = pd.DataFrame(np_integrate_form, index=['imf'+str(i) for i in range(len(df_sampen.index))], columns=['Cluster'])
-
return df_integrate_form
该函数依据前面计算得到的样本熵数据,使用 K-Means 算法进行聚类操作。设置聚类的簇数并通过fit_predict
方法得到聚类结果,将其整理为 DataFrame 格式返回,其中包含了各 IMF 分量所属的聚类信息,有助于进一步分析数据的内在结构。
- integrate_imfs 函数(整合 IMF 分量)
-
def integrate_imfs(df_integrate_form=None, df_ceemdan=None): # 整合IMF分量和残差为3个协同IMF
-
df_tmp = pd.DataFrame()
-
for i in range(df_integrate_form.values.max()+1):
-
df_tmp['imf'+str(i)] = df_ceemdan[df_integrate_form[(df_integrate_form['Cluster']==i)].index].sum(axis=1)
-
df_integrate_result = df_tmp.T # 根据样本熵对协同IMF进行排序
-
df_integrate_result['sampen'] = sample_entropy(df_tmp).values
-
df_integrate_result.sort_values(by=['sampen'], ascending=False, inplace=True)
-
df_integrate_result.index = ['co-imf'+str(i) for i in range(df_integrate_form.values.max()+1)]
-
df_integrate_result = df_integrate_result.drop('sampen', axis=1, inplace=False)
-
return df_integrate_result.T
此函数的目的是将经过聚类后的 IMF 分量进行整合,形成协同 IMF(Co-IMFs)。通过遍历不同的聚类,对属于同一聚类的 IMF 分量进行求和操作,得到整合后的结果。然后根据样本熵对协同 IMF 进行排序,并去除用于排序的样本熵列,最终返回整合后的协同 IMF 数据,以便后续进行进一步的分解和预测操作。
- vmd_decompose 函数(VMD 分解)
-
def vmd_decompose(series=None, alpha=2000, tau=0, K=10, DC=0, init=1, tol=1e-7, draw=True): # VMD分解函数
-
imfs_vmd, imfs_hat, omega = VMD(series, alpha, tau, K, DC, init, tol)
-
df_vmd = pd.DataFrame(imfs_vmd.T)
-
df_vmd.columns = ['imf'+str(i) for i in range(K)]
-
return df_vmd
该函数用于对特定的协同 IMF(如co-imf0
)进行 VMD 分解。设置 VMD 分解的相关参数,如正则化参数alpha
、模态数量K
等,通过调用VMD
函数进行分解操作,得到分解后的 IMF 分量,并将其转换为 DataFrame 格式返回,各列对应不同的 IMF 分量,为后续基于 VMD 分解结果的预测提供数据基础。
(二)预测相关函数
- GRU_model 函数(构建 GRU 模型)
-
def GRU_model(trainset_shape):# 构建GRU模型
-
model = Sequential()
-
model.add(GRU(128, input_shape=(trainset_shape[1], trainset_shape[2]), activation='tanh', return_sequences=True))
-
model.add(Dropout(0.2))
-
model.add(GRU(64,activation='tanh',return_sequences=True))
-
model.add(Dropout(0.2))
-
model.add(GRU(32,activation='tanh',return_sequences=False))
-
model.add(Dropout(0.2))
-
model.add(Dense(1,activation='tanh'))
-
model.compile(loss='mse', optimizer='adam')
-
return model
此函数用于构建 GRU 模型,这是一种常用于处理时间序列数据的循环神经网络模型。在模型构建过程中,设置了不同层的 GRU 单元数量、激活函数以及 Dropout 比例等参数,以防止过拟合。最后编译模型,指定损失函数为均方误差(MSE),优化器为adam
,并返回构建好的模型,该模型可用于对股票价格数据进行预测。
- evaluation_model 函数(模型评估)
-
def evaluation_model(y_test, y_pred): # 模型评估函数
-
y_test,y_pred = np.array(y_test).ravel(),np.array(y_pred).ravel()
-
r2 = r2_score(y_test, y_pred)
-
rmse = mean_squared_error(y_test, y_pred, squared=False) # MSE和MAE在不同尺度上有所不同
-
mae = mean_absolute_error(y_test, y_pred)
-
mape = mean_absolute_percentage_error(y_test, y_pred)
-
df_evaluation = pd.DataFrame({'r2': r2, 'rmse': rmse, 'mae': mae, 'mape': mape}, index = range(1))
-
return df_evaluation
该函数用于对预测模型的性能进行评估。输入测试集的真实值和预测值,通过计算相关评估指标,如决定系数(R2)、均方根误差(RMSE)、平均绝对误差(MAE)和平均绝对百分比误差(MAPE)等,并将这些指标整理为 DataFrame 格式返回,以便直观地了解模型的预测效果。
- create_train_test_set 函数(创建训练集和测试集)
-
def create_train_test_set(data=None, timestep=30, co_imf_predict_for_fitting=None): # 创建带有归一化的训练集和测试集
-
if isinstance(data, pd.DataFrame): # 初始化DataFrame格式的训练集和测试集
-
dataY = data['sum'].values.reshape(-1, 1)
-
dataX = data.drop('sum', axis=1, inplace=False)
-
else: # 初始化Series
-
dataY = data.values.reshape(-1, 1)
-
dataX = dataY
-
-
scalarX = MinMaxScaler(feature_range=(0,1)) # 通过sklearn进行归一化
-
dataX = scalarX.fit_transform(dataX)
-
if co_imf_predict_for_fitting is not None: co_imf_ppredict_for_fitting = scalarX.transform(co_imf_predict_for_fitting)
-
-
scalarY = MinMaxScaler(feature_range=(0,1))
-
dataY = scalarY.fit_transform(dataY)
-
-
trainX, trainY = [], [] # 创建训练集和测试集
-
for i in range(len(dataY)-timestep):
-
trainX.append(np.array(dataX[i:(i+timestep)]))
-
trainY.append(np.array(dataY[i+timestep]))
-
if co_imf_predict_for_fitting is not None: # 拟合时,使用今日的预测结果
-
if i<(len(dataY)-timestep-len(co_imf_predict_for_fitting)): trainX[i] = np.insert(trainX[i], timestep, dataX[i+timestep], 0)
-
else: trainX[i] = np.insert(trainX[i], timestep, co_imf_predict_for_fitting[i-(len(dataY)-timestep-len(co_imf_predict_for_fitting))], 0)
-
-
return np.array(trainX), np.array(trainY), scalarY
此函数的主要作用是创建用于模型训练和测试的数据集。根据输入数据的格式(DataFrame 或 Series)进行相应的处理,通过MinMaxScaler
对数据进行归一化操作,然后按照指定的时间步长将数据划分为训练集和测试集,并根据是否有拟合相关的数据进行相应的插入操作,最终返回处理好的训练集、测试集以及用于反归一化的scalarY
对象。
- GRU_predict 函数(GRU 预测函数)
-
def GRU_predict(data=None, epochs=100, predict_duration=100, fitting=None): # GRU预测函数
-
trainX,trainY,scalarY = create_train_test_set(data, co_imf_predict_for_fitting=fitting) # 获取训练集和测试集的X、Y
-
x_train,x_test = trainX[:-predict_duration],trainX[-predict_duration:] # 划分训练集和测试集
-
y_train,y_test = trainY[:-predict_duration],trainY[-predict_duration:]
-
train_X = x_train.reshape((x_train.shape[0], x_train.shape[1], x_train.shape[2])) # 转换为张量
-
test_X = x_test.reshape((x_test.shape[0], x_test.shape[1], x_test.shape[2])) # 转换为张量
-
-
model = GRU_model(train_X.shape) # 构建模型 # 使用model.summary()可查看模型结构
-
patience = epochs//10
-
EarlyStop = EarlyStopping(monitor='val_loss', patience=5*patience, verbose=0, mode='auto') # 在小学习率时提前停止
-
Reduce = ReduceLROnPlateau(monitor='val_loss', patience=patience, verbose=0, mode='auto') # 自适应学习率
-
history = model.fit(train_X, y_train, epochs=epochs, batch_size=16, validation_split=0.1, verbose=0, shuffle=True, callbacks=[EarlyStop,Reduce]) # 训练模型
-
-
y_test_predict = model.predict(test_X) # 预测
-
df_gru_evaluation = evaluation_model(y_test, y_test_predict) # 评估模型
-
y_test_predict = y_test_predict.ravel().reshape(-1,1)
-
y_test_predict_result = scalarY.inverse_transform(y_test_predict) # 反归一化
-
y_test_raw = scalarY.inverse_transform(y_test)
-
df_predict_raw = pd.DataFrame({'raw': y_test_raw.ravel(), 'predict': y_test_predict_result.ravel()}, index=range(len(y_test_raw))) # 输出
-
df_train_loss= pd.DataFrame({'loss': history.history['loss'], 'val_loss': history.history['val_loss']}, index=range(len(history.history['val_loss'])))
-
return df_predict_raw, df_gru_evaluation, df_train_loss
该函数实现了基于 GRU 模型的预测流程。首先通过create_train_test_set
函数获取训练集和测试集,然后对数据进行形状调整以便输入模型。接着构建 GRU 模型,并设置提前停止和自适应学习率等机制以优化训练过程。通过模型对测试集进行预测,之后对预测结果进行评估、反归一化等操作,最终返回预测结果、模型评估指标以及训练过程中的损失信息等。
主函数及整体流程
在主函数中,主要执行了以下步骤:
(一)数据加载
-
if __name__ == '__main__':
-
start = time.time()
-
CODE, PATH ='sh.000001', 'D:\\Stock-LSTM\\' # 如'sh.000001'这样的代码
-
-
# 1.加载原始数据
-
df_raw_data = pd.read_csv(PATH+CODE+'.csv', header=0, parse_dates=['date'], date_parser=lambda x: datetime.datetime.strptime(x, '%Y%m%d'))
-
series_close = pd.Series(df_raw_data['close'].values,index = df_raw_data['date'])
首先设置股票代码和数据存储路径,然后通过pd.read_csv
函数读取指定路径下的股票原始数据文件,并提取出收盘价数据序列,为后续的分析和预测做准备。
(二)数据分解与处理
- CEEMDAN 分解
-
# 2.CEEMDAN分解
-
df_ceemdan = ceemdan_decompose(series_close)
-
# df_ceemdan.plot(title='CEEMDAN分解', subplots=True)
对收盘价数据序列进行 CEEMDAN 分解,得到各 IMF 分量。
- 样本熵计算与聚类
-
# 3.样本熵计算
-
df_sampen = sample_entropy(df_ceemdan)
-
# df_sampen.plot(title='样本熵')
-
-
# 4.K-Means聚类(基于样本熵)
-
df_integrate_form = kmeans_cluster(df_sampen)
-
# print(df_integrate_form)
接着计算 CEEMDAN 分解后各 IMF 分量的样本熵,并基于样本熵进行 K-Means 聚类。
- 整合 IMF 分量
-
# 5.整合IMF分量和残差为3个协同IMF
-
df_integrate_result = integrate_imfs(df_integrate_form, df_ceemdan)
-
# df_integrate_result.plot(title='整合的IMF(协同IMF)的CEEMDAN', subplots=True)
将经过聚类后的 IMF 分量进行整合,形成协同 IMF。若执行df_integrate_result.plot(title='整合的IMF(协同IMF)的CEEMDAN', subplots=True)
,可绘制出整合后的协同 IMF 情况图,以便直观了解!
- VMD 分解
-
# 6.对高频协同IMF0进行VMD二次分解
-
df_vmd_co_imf0 = vmd_decompose(df_integrate_result['co-imf0']) # vmd分解(数据集数量必须为偶数)
-
# df_vmd_co_imf0.plot(title='协同IMF0的VMD分解', subplots=True)
对特定的协同 IMF0 进行 VMD 分解,分解后可通过执行df_vmd_co_imf0.plot(title='协同IMF0的VMD分解', subplots=True)
绘制出 VMD 分解结果图。
预测与结果汇总
关于分析师
在此对 Duqiao Han 对本文所作的贡献表示诚挚感谢,他在哈尔滨工业大学完成了本科阶段的学习,专业为海洋技术与财务管理。擅长 Python、Stata、SPSS,在数据采集、数据分析方面有着丰富的经验。