2023年第二届全国大学生数据分析B题黄金股价预测分析解题全过程文档及程序

2023年第二届全国大学生数据分析

B题 黄金股价预测分析

原题再现:

  黄金一直被全球投资者视为一种安全资产,特别是在金融市场动荡和全球经济不确定性 增加的情况下, 黄金的价值更加凸显。例如, COVID-19 大流行期间, 全球的经济前景变得 非常不明朗,许多投资者为了避免风险,选择投资黄金,这使得黄金的价格在短期内急剧上 升。然而,尽管黄金被视为安全资产,但其价格也会受到许多因素的影响,如全球经济形势、 货币政策、地缘政治等。因此, 对于投资者来说, 理解并预测黄金价格的变化对于投资决策
  至关重要。本案例的主要目标是预测黄金收盘价的趋势,以帮助投资者在复杂的金融市场环境中做出更加明智的决策。
  请基于附件提供的数据或自行寻找其他数据,解决以下问题:
  1. 数据探索。从数据源导入我们需要的数据,探索数据集的变量特征,并进行可视化展示。
  2. 数据预处理。对收集到的数据进行预处理, 包括清洗数据、整理数据等, 如进行缺失值的清洗,支撑后续进行模型建立。
  3. 模型建立。根据数据选择建立合适的模型, 说明模型的选择和建立过程。
  4. 模型调优。在初步建模的基础上,选择合适的方法进行模型调优,说明调优的过程和依据,最终得到性能最佳的模型。
  5. 模型预测与评估。在测试集上,使用模型对未来四个月的黄金收盘价数据进行预测,通过比较模型的预测结果和实际结果,对模型的性能进行评估。
  6. 结果分析。对模型的预测结果进行分析,了解黄金在复杂金融市场的价值。

整体求解过程概述(摘要)

  黄金作为一种重要的避险资产和投资工具,预测黄金价格的变化对于投资者和金融机构都具有重要的意义。黄金股价预测可以为投资者提供决策的依据,减轻了盲目投资带来的风险,尤其在经济不稳定或金融市场动荡时被广泛认可。预测黄金股价可以帮助投资者更好地管理投资组合风险,合理配置黄金资产,以对冲其他投资的风险。本文根据2021-07-04日至2023-07-04日近2年的黄金股价数据,运用ARIMA、LSTM、Informer算法建立预测模型对黄金收盘价变化趋势进行探索建模。最后提出基于朴素贝叶斯优化的Informer 模型进行超参数寻优以得到黄金收盘价趋势预测的最优模型。
  针对附件data中2021-07-04日至2023-07-04 日近2年的开盘价、收盘价、最高价、最低价、股价涨跌幅度等数据特征进行预处理,包括噪声值检验以及数据清洗等过程,并采用箱形图和盖帽法对异常点进行检验和处理,再对预处理数据通过平稳性和白噪声检验以及差分运算后得到平稳非白噪声序列。由于黄金股价与股价变化点数和百分比具有不同特征的数值范围,因此通过归一化将其映射到统一的范围内,以消除不同特征之间的尺度差异,使得数据在相同的尺度上进行比较和分析。本文选择开盘价、最高价、最低价等3个变量作为输入量,将收盘价作为输出量,共获取1461个黄金股价历史数据作为样本数据集,选取样本数据集的前70%,即 2021-07-04日至2022-11-25日共1023个交易日的数据作为训练样本集。取样本数据集的后20%,即 2022-11-26日至2023-0421 日共292 个交易日作为测试样本集。取样本数据集的最后10%,即2023-04-22日至2023-07-04 日共 146 个交易日作为验证样本集。然后分别建立ARIMA、LSTM、Informer模型对黄金收盘价数据进行预测。针对长时间序列预测模型,为了更加高效的使用随机搜索方法在参数空间中搜索最优超参数以节省大量计算资源和时间,通过在每次迭代中根据模型性能的反馈动态地更新模型的最佳超参数组合。首先确定 Informer 模型的seq_len、label_len、batch_size、train_epochs 等超参数取值范围,其次在验证集上使用平均绝对误差进行模型评估,来评估每组超参数的性能。然后通过迭代优化,直至输出最优预测性能的超参数。最后分别采用均方根误差(RMSE)、平均绝对误差(MAE)和平均绝对百分比误差(MAPE)等三个指标对ARIMA模型、LSTM模型、Informer模型和Bayes-Informer 预测模型的黄金收盘价预测性能进行评价,并对比其预测性能。由于ARIMA和LSTM模型均只能处理单变量和单步预测,而Informer模型支持多变量和多步预测,能够接受多个输入特征,并可一次性进行多步预测,对于黄金收盘价变化趋势预测性能方面具有更强的建模能力和处理复杂的长时间序列预测的能力。同时通过贝叶斯优化后可以更加高效的搜索最优超参数,并在高噪声或不连续时间序列预测中具有更强的鲁棒性。

模型假设

  股市交易日一般为法定工作日,不包括周末和节假日。然而,黄金市场的股市交易日对全球投资者来说是开放的,因此不同国家之间可能存在股市交易日的差异,主要是由于法定假期不同。在A股市场,一年的交易日约为250天左右。而港股和美股通常在周一至周五开市,周六和周日休市。如果A股休市,港股和美股可能开市,反之亦然。此外,由于不同国家之间存在时差,全球投资者可以假设黄金市场的交易日为周一至周五,同时周日也被看作交易日,而周六则统一休市。

问题分析

  为预测黄金收盘价的趋势,以2021-07-04 日至 2023-07-04 日近 2 年的开盘价、收盘价、最高价、最低价、股价涨跌幅度为原始数据,通过量化交易的方式建立时间序列预测模型对2023-07-04 日后四个月黄金收盘价进行预测,以便于投资者做出正确决策。
  步骤1:数据预处理。针对附件data中2021-07-04日至2023-07-04日近2年的开盘价、收盘价、最高价、最低价、股价涨跌幅度等数据特征进行预处理,包括噪声值检验以及数据清洗等过程,并采用箱形图和盖帽法对异常点进行检验和处理,再对预处理数据通过平稳性和白噪声检验以及差分运算后得到平稳非白噪声序列。由于黄金股价与股价变化点数和百分比具有不同特征的数值范围,因此通过归一化将其映射到统一的范围内,以消除不同特征之间的尺度差异,使得数据在相同的尺度上进行比较和分析。
  步骤2:黄金股价预测建模。本文选择开盘价、最高价、最低价等3个变量作为输入量,将收盘价作为输出量。共获取 1461 个黄金股价历史数据作为样本数据集,选取样本数据集的前70%,即2021-07-04日至2022-11-25日共1023个交易日的数据作为训练样本集。取样本数据集的后20%,即2022-11-26日至2023-04-21 日共 292 个交易日作为测试样本集。取样本数据集的最后10%,即 2023-04-22日至2023-07-04日共146个交易日作为验证样本集。然后分别建立ARIMA、LSTM、Informer模型对黄金收盘价数据进行预测。
  步骤3:基于Bayes-Informer 模型。针对长时间序列预测模型,为了更加高效的使用传统网格搜索或随机搜索方法在参数空间中搜索最优超参数以节省大量计算资源和时间,通过在每次迭代中根据模型性能的反馈动态地更新模型的超参数搜索空间。首先确定Informer 模型的 seq_len、label_len、batch_size、train_epochs 等超参数取值范围。其次在验证集上使用平均绝对误差进行模型评估,来评估每组超参数的性能。然后通过迭代优化,直至输出最优预测性能的超参数。
  步骤4:黄金股价预测模型性能对比与评估。分别采用均方根误差(RMSE)、平均绝对误差(MAE)和平均绝对百分比误差(MAPE)等三个指标对ARIMA模型、LSTM模型、Informer 模型和 BAYES-INFORMER 预测模型的黄金收盘价预测性能进行评价,并对比其预测性能。由于 ARIMA 和 LSTM 模型均只能处理单变量和单步预测,而Informer 模型支持多变量和多步预测,能够接受多个输入特征,并可一次性进行多步预测,对于黄金收盘价变化趋势预测性能方面具有更强的建模能力和处理复杂的长时间序列预测的能力。同时通过贝叶斯优化后可以更加高效的搜索最优超参数,并在高噪声或不连续时间序列预测中具有更强的鲁棒性。

模型的建立与求解整体论文缩略图

在这里插入图片描述
在这里插入图片描述

全部论文请见下方“ 只会建模 QQ名片” 点击QQ名片即可

部分程序代码:(代码和文档not free)

1. #导入第三方库
2. import pandas as pd
 3. import numpy as np
 4. import xgboost as xgb
 5. import matplotlib.pyplot as plt
 6. from sklearn.ensemble import (RandomForestRegressor, AdaBoostRegressor,
 7. GradientBoostingReg
 ressor, ExtraTreesRegressor)
 8. from sklearn.tree import DecisionTreeRegressor
 9. from sklearn.model_selection import KFold, train_test_split
 10.
 11. import warnings
 12.
 13. warnings.filterwarnings(action='ignore') #忽略告警
14.
 15. #读取数据
16. df = pd.read_excel('data.xlsx')
 17.
 18. #用Pandas工具查看数据
19. print(df.head())
 20. print('******************************')
 21.
 22. #数据缺失值统计
23. print(df.info())
 24. print('******************************')
 25.
 26. #描述性统计分析
27. print(df.describe().round(4))
 28. print('******************************')
 29.
 30. # y变量分布直方图
31. fig = plt.figure(figsize=(8, 5)) #设置画布大小
32. plt.rcParams['font.sans-serif'] = 'SimHei' #设置中文显示
33. plt.rcParams['axes.unicode_minus'] = False #解决保存图像是负号'-'显示为
方块的问题
34. data_tmp = df['y'] #过滤出y变量的样本
35. #绘制直方图bins:控制直方图中的区间个数auto为自动填充个数color:指定
柱子的填充色
 36. plt.hist(data_tmp, bins='auto', color='g')
 37. plt.xlabel('y')
 38. plt.ylabel('数量')
 39. plt.title('y变量分布直方图')
 40. plt.show()
 41.
 42. #数据的相关性分析
43. import seaborn as sns #导入数据集分布可视化库seaborn是基于
matplotlib的数据集分布可视化库。
44.
 45. sns.heatmap(df.corr(), cmap="YlGnBu", annot=True) #绘制热力图
46. plt.title('相关性分析热力图')
 47. plt.show() #展示图片
48.
 49. #构建特征和标签
50. X = df.drop(columns=['y']) #构建特征
51. y = df['y'] #构建标签
52.
 53. #数据集拆分:划分80%训练集和20%测试集
54. from sklearn.model_selection import train_test_split #导入数据拆分函55.
 56. X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,
 random_state=42) #进行数据拆分
57.
 58. ntrain = X_train.shape[0] #获取样本数
59. ntest = X_test.shape[0] #获取样本数
60. SEED = 0 #随机种子
61. NFOLDS = 5
 62. kf = KFold(n_splits=NFOLDS, shuffle=True, random_state=SEED) # 5折交叉
验证
63.
 64. y_train = y_train.values
 65.
 66.
 67. #定义一个扩展类SklearnHelper
 68. class SklearnHelper(object):
 69. def __init__(self, clf, seed=0, params=None): #定义初始化方70. params['random_state'] = seed
 71. self.clf = clf(**params)
 72.
 73. def train(self, x_train, y_train): #定义训练方法
74. self.clf.fit(x_train, y_train)
75.
 76. def predict(self, x): #定义预测方法
77. return self.clf.predict(x)
 78.
 79. def fit(self, x, y): #定义拟合方法
80. return self.clf.fit(x, y)
 81.
 82. def feature_importances(self, x, y): #定义特征重要性方法
83. return self.clf.fit(x, y).feature_importances_
 84.
 85.
 86. #定义模型训练函数
87. def get_oof(clf, x_train, y_train, x_test):
 88. oof_train = np.zeros((ntrain,)) #训练数据初始化
89. oof_test = np.zeros((ntest,)) #训练数据初始化
90. oof_test_skf = np.empty((NFOLDS, ntest)) #定义空数组
91.
 92. for i, (train_index, test_index) in enumerate(kf.split(x_train, y
 _train)): #循环
93. x_tr = x_train[train_index] #训练集-特征
94. y_tr = y_train[train_index] #训练集-标签
95. x_te = x_train[test_index] #测试集-特征
96.
 97. clf.train(x_tr, y_tr) #训练
98.
 99. oof_train[test_index] = clf.predict(x_te) #预测
100. oof_test_skf[i, :] = clf.predict(x_test) #预测
101.
 102. oof_test[:] = oof_test_skf.mean(axis=0) #取均值
103. return oof_train.reshape(-1, 1), oof_test.reshape(-1, 1) #返回
训练集和测试集预测数据
104.
 105.
 106. #随机森林参数
107. rf_params = {
 108. 'n_jobs':-1,
 109. 'n_estimators': 500,
 110. 'max_depth': 6,
 111. 'min_samples_leaf': 2,
 112. 'verbose': 0
 113. }
 114.
 115. #极端随机数参数
116. et_params = {
117. 'n_jobs':-1,
 118. 'n_estimators': 500,
 119. 'max_depth': 8,
 120. 'min_samples_leaf': 2,
 121. 'verbose': 0
 122. }
 123.
 124. # AdaBoost参数
125. ada_params = {
 126. 'n_estimators': 500,
 127. 'learning_rate': 1.0
 128. }
 129.
 130. #梯度提升树参数
131. gb_params = {
 132. 'n_estimators': 500,
 133. 'max_depth': 3,
 134. 'verbose': 0
 135. }
 136.
 137. #决策树参数
138. dtr_params = {
 139. 'max_depth': 5,
 140. 'min_samples_split': 2
 141. }
 142.
 143. #创建5个对象代表5个模型
144. rf = SklearnHelper(clf=RandomForestRegressor, seed=SEED, params=rf_params)
 145. et = SklearnHelper(clf=ExtraTreesRegressor, seed=SEED, params=et_params)
 146. ada = SklearnHelper(clf=AdaBoostRegressor, seed=SEED, params=ada_params)
 147. gb = SklearnHelper(clf=GradientBoostingRegressor, seed=SEED, params=gb_para
 ms)
 148. dtr = SklearnHelper(clf=DecisionTreeRegressor, seed=SEED, params=dtr_params)
 149.
 150. #把数据框转为数组
151. train = X_train
 152. x_train = train.values
 153. x_test = X_test.values
 154.
 155. #模型训练
 156. et_oof_train, et_oof_test = get_oof(et, x_train, y_train, x_test) #
极端随机树
157. rf_oof_train, rf_oof_test = get_oof(rf, x_train, y_train, x_test) #
随机森林
158. ada_oof_train, ada_oof_test = get_oof(ada, x_train, y_train, x_test) #
 AdaBoost
 159. gb_oof_train, gb_oof_test = get_oof(gb, x_train, y_train, x_test) #
梯度提升树
160. dtr_oof_train, svc_oof_test = get_oof(dtr, x_train, y_train, x_test) #
决策树
161.
 162. #特征重要性分析
163. rf_feature = rf.feature_importances(x_train, y_train)
 164. et_feature = et.feature_importances(x_train, y_train)
 165. ada_feature = ada.feature_importances(x_train, y_train)
 166. gb_feature = gb.feature_importances(x_train, y_train)
 167.
 168. rf_features = list(rf_feature)
 169.
 170. et_features = list(et_feature)
 171. ada_features = list(ada_feature)
 172. gb_features = list(gb_feature)
 173. cols = train.columns.values
 174.
 175. #创建一个特征的DataFrame框架
176. feature_dataframe = pd.DataFrame({'features': cols,
 177. 'Random Fo
 rest feature importances': rf_features,
 178. 'Extra Tre
 es feature importances': et_features,
 179. 'AdaBoost
 feature importances': ada_features,
 180. 'Gradient
 Boost feature importances': gb_features
 181. })
 182.
 183. #支持中文
184. plt.bar(feature_dataframe['features'].values, feature_dataframe['Random Fores
 t feature importances'].values,
 185. color=['b', 'r', 'g', 'y', 'c', 'm', 'y', 'k', 'c', 'g
 ', 'b'])
 186. plt.rcParams['font.sans-serif'] = ['SimHei'] #用来正常显示中文标签
187. plt.rcParams['axes.unicode_minus'] = False #用来正常显示负号
188. plt.title("随机森林模型特征重要性图", fontsize=15) #设置标题
 189. plt.xlabel("特征名字", fontsize=10) #设置x轴
190. plt.ylabel("重要性", fontsize=10) #设置y轴
191. plt.show() #展示图片
192.
 193. plt.bar(feature_dataframe['features'].values, feature_dataframe['Extra Trees
 feature importances'].values,
 194. color=['b', 'r', 'g', 'y', 'c', 'm', 'y', 'k', 'c', 'g
 ', 'b'])
 195. plt.title("Extra Trees模型特征重要性图", fontsize=15) #设置标题
196. plt.xlabel("特征名字", fontsize=10) #设置x轴
197. plt.ylabel("重要性", fontsize=10) #设置y轴
198. plt.show() #展示图片
199.
 200. plt.bar(feature_dataframe['features'].values, feature_dataframe['AdaBoost fea
 ture importances'].values,
 201. color=['b', 'r', 'g', 'y', 'c', 'm', 'y', 'k', 'c', 'g
 ', 'b'])
 202. plt.title("AdaBoost模型特征重要性图", fontsize=15) #设置标题
203. plt.xlabel("特征名字", fontsize=10) #设置x轴
204. plt.ylabel("重要性", fontsize=10) #设置y轴
205. plt.show() #展示图片
206.
 207. plt.bar(feature_dataframe['features'].values, feature_dataframe['Gradient Boo
 st feature importances'].values,
 208. color=['b', 'r', 'g', 'y', 'c', 'm', 'y', 'k', 'c', 'g
 ', 'b'])
 209. plt.title("Gradient Boost模型特征重要性图", fontsize=15) #设置标题
210. plt.xlabel("特征名字", fontsize=10) #设置x轴
211. plt.ylabel("重要性", fontsize=10) #设置y轴
212. plt.show() #展示图片
213.
 214. #所有模型平均特征重要性
215.
 216. feature_dataframe['mean'] = feature_dataframe.mean(axis=1) # axis = 1
 computes the mean row-wise
 217. print(feature_dataframe.head(3))
 218.
 219. plt.bar(feature_dataframe['features'].values, feature_dataframe['mean'].values,
 220. color=['b', 'r', 'g', 'y', 'c', 'm', 'y', 'k', 'c', 'g
 ', 'b'])
 221. plt.title("所有模型平均特征重要性图", fontsize=15) #设置标题
222. plt.xlabel("特征名字", fontsize=10) #设置x轴
223. plt.ylabel("重要性", fontsize=10) #设置y轴
 224. plt.show() #展示图片
225.
 226. base_predictions_train = pd.DataFrame({'RandomForest': rf_oof_train.ravel(),
 227. '
 ExtraTrees': et_oof_train.ravel(),
 228. '
 AdaBoost': ada_oof_train.ravel(),
 229. '
 GradientBoost': gb_oof_train.ravel(),
 230. '
 DecisionTree': dtr_oof_train.ravel()
 231. })
 232. print(base_predictions_train.head())
 233.
 234. #相关性分析
235. df_tmp1 = base_predictions_train[
 236. ['RandomForest', 'ExtraTrees', 'AdaBoost', 'GradientBoost', 'Decisi
 onTree']] #获取数据项
237. plt.rcParams['font.sans-serif'] = ['SimHei'] #用来正常显示中文标签
238. plt.rcParams['axes.unicode_minus'] = False #用来正常显示负号
239. sns.heatmap(df_tmp1.corr(), cmap="YlGnBu", annot=True) #画相关性热力240. plt.title("五种模型预测结果相关性分析图", fontsize=15) #设置标题
241. plt.show() #展示图片
242.
 243. x_train = np.concatenate((et_oof_train, rf_oof_train, ada_oof_train, gb_oo
 f_train, dtr_oof_train), axis=1)
 244. x_test = np.concatenate((et_oof_test, rf_oof_test, ada_oof_test, gb_oof_te
 st, svc_oof_test), axis=1)
 245.
 246. #建模
247. gbm = xgb.XGBRegressor().fit(x_train, y_train)
 248. y_pred = gbm.predict(x_test)
 249.
 250. #模型评估
251. from sklearn.metrics import mean_squared_error, explained_variance_score,
 mean_absolute_error, r2_score
 252.
 253.
 254.
 255. #真实值与预测值比对图
256. plt.rcParams['font.sans-serif'] = ['SimHei'] #用来正常显示中文标签
 257. plt.rcParams['axes.unicode_minus'] = False #用来正常显示负号
258. plt.plot(range(len(y_test)), y_test, color="blue", linewidth=1.5, linestyle
 ="-")
 259. plt.plot(range(len(y_pred)), y_pred, color="red", linewidth=1.5, linestyle=
 "-.")
 260. plt.legend(['真实值', '预测值'])
 261. plt.title("Stacking回归模型真实值与预测值比对图")
全部论文请见下方“ 只会建模 QQ名片” 点击QQ名片即可
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值