13.4 机器学习模型
在本项目中,选择使用LGBMRegressor作为预测价格的机器学习模型,并使用verstack进行调优处理。
(1)函数prediction 用于预测金价,并评估预测性能。首先,它创建一个数据集 data,包含目标列(col)的原始数据。然后,通过调用 Prepare_Data 函数,为目标列添加了滞后期、滚动统计和L-矩等特征。接着,对 'Open'、'Close'、'Volume' 以及与目标列互补的 'Low' 或 'High' 列进行同样的特征工程,最后将所有数据集合并成一个完整的数据集。随后,删除了因为滞后期特征引起的缺失值。接下来,定义训练数据并使用 LGBMTuner 进行超参数调整,最后对数据的最后90天进行预测,并输出预测结果、评估指标和模型调整的超参数。该函数可用于实现金价的时间序列预测和交易策略的评估。
def prediction(Data, col, Lag_list, Roll_window, Lmoment_window):
data = pd.DataFrame({col: Data[col]}, index=Data.index)
# 准备要预测的目标列
data = Prepare_Data(data, col, Lag_list, Roll_window, Lmoment_window)
# 这三列及其新特征添加到最终数据集,无论目标列是什么。
Open = Prepare_Data(pd.DataFrame(Gold['Open']), 'Open', Lag_list, Roll_window, Lmoment_window)
Close = Prepare_Data(pd.DataFrame(Gold['Close']), 'Close', Lag_list, Roll_window, Lmoment_window)
Volume = Prepare_Data(pd.DataFrame(Gold['Volume']), 'Volume', Lag_list, Roll_window, Lmoment_window)
# 由于创建包含所有特征的完整数据集,如果目标是 "High",我们添加 Low 特征,反之亦然。
if col == 'High':
df = Prepare_Data(pd.DataFrame(Gold['Low']), 'Low', Lag_list, Roll_window, Lmoment_window)
elif col == 'Low':
df = Prepare_Data(pd.DataFrame(Gold['High']), 'High', Lag_list, Roll_window, Lmoment_window)
# 现在我们将上面创建的所有数据集合并在一起,以获得完整的数据集
data = pd.concat([Open, Close, Volume, df, data], axis=1)
# 由于使用滞后期会导致存在缺失值的行,因此将这些行删除
tail = data.shape[0] - max(Roll_window, len(Lag_list))
data = data.tail(tail)
# 定义训练数据
X = data.values[:-90, :-1]
Y = data.values[:-90, -1]
# 使用 LGBMTuner 进行超参数调整
tuner = LGBMTuner(metric='rmse', trials=50) # <- the only required argument
# 调整器需要 X 和 Y 的这些数据类型
X = pd.DataFrame(X)
Y = pd.Series(Y)
# 拟合调整后的模型并对数据的最后90天进行预测
tuner.fit(X, Y)
x_test = data.values[-90:, :-1]
x_test = pd.DataFrame(x_test)
predict = tuner.predict(x_test)
y_test = pd.Series(data.values[-90:, -1])
mae = mean_absolute_error(y_test, predict)
rmse = sqrt(mean_squared_error(y_test, predict))
"""以下两者的差异最小,是最佳情况,表明预测准确,交易策略可行。"""
diff_low = []
if col == 'Low':
for i in range(len(predict)):
diff = predict[i] - y_test[i]
diff_low.append(diff)
print ('Mean:', mean(diff_low), 'Variance:', statistics.variance(diff_low))
diff_high = []
if col == 'High':
for i in range(len(predict)):
diff = y_test[i] - predict[i]
diff_high.append(diff)
print ('Mean:', mean(diff_high), 'Variance:', statistics.variance(diff_high))
print('MAE: %f' % mae)
print('RMSE: %f' % rmse)
print('======Summary======')
print('Lag_list:', '===>', Lag_list)
print('Roll_window:', '===>', Roll_window)
print('Lmoment_window:', '===>', Lmoment_window)
print('==============================')
print('predict:\n', ['%.1f' % y for y in predict])
print('Actual:\n', y_test.tolist())
return predict.tolist(), y_test.tolist()
(2)调用上面定义的函数 prediction,对金价数据中的 'Low' 列进行预测。使用滞后期列表 [2, 3, 4, 5],滚动窗口大小为 2,L-矩计算窗口大小为 5 进行特征工程。
low_prediction = prediction(Gold,'Low',[i for i in range(2,6)],2,5)
执行后返回了对 'Low' 列的预测结果、实际值以及评估指标(均方误差、均方根误差等),这个过程有助于了解模型在 'Low' 列上的预测性能和交易策略评估。执行后会输出:
* Initiating LGBMTuner.fit
. Settings:
.. Trying 50 trials
.. Evaluation metric: rmse
.. Study direction: minimize rmse
. Trial number: 0 finished
.. Optimization score (lower-better): rmse: 5.998330355838334
...........................................................................
. Trial number: 1 finished
.. Optimization score (lower-better): rmse: 6.626333981231204
...........................................................................
. Trial number: 2 finished
.. Optimization score (lower-better): rmse: 6.065461698552595
...........................................................................
. Trial number: 3 finished
.. Optimization score (lower-better): rmse: 7.588808362697567
...........................................................................
. Trial number: 4 finished
.. Optimization score (lower-better): rmse: 6.333486651352738
...........................................................................
. Trial number: 20 finished
.. Optimization score (lower-better): rmse: 5.995384306717045
...........................................................................
. Trial number: 23 finished
.. Optimization score (lower-better): rmse: 6.184332265001647
...........................................................................
- Tune n_estimators with early_stopping
Training until validation scores don't improve for 200 rounds
[100] train's lgb_rmse: 183.879 valid's lgb_rmse: 184.244
[200] train's lgb_rmse: 67.4405 valid's lgb_rmse: 67.6122
[300] train's lgb_rmse: 24.9382 valid's lgb_rmse: 25.3642
[400] train's lgb_rmse: 9.60396 valid's lgb_rmse: 10.9218
[500] train's lgb_rmse: 4.33871 valid's lgb_rmse: 7.03234
[600] train's lgb_rmse: 2.70026 valid's lgb_rmse: 6.33645
[700] train's lgb_rmse: 2.14305 valid's lgb_rmse: 6.24522
[800] train's lgb_rmse: 1.85119 valid's lgb_rmse: 6.22872
[900] train's lgb_rmse: 1.64197 valid's lgb_rmse: 6.22763
[1000] train's lgb_rmse: 1.48015 valid's lgb_rmse: 6.23446
Early stopping, best iteration is:
[857] train's lgb_rmse: 1.72606 valid's lgb_rmse: 6.22481
- Fitting optimized model with the follwing params:
learning_rate : 0.01
num_leaves : 252
colsample_bytree : 0.9442916144154508
subsample : 0.7802802926046664
verbosity : -1
random_state : 42
objective : regression
metric : rmse
num_threads : 2
reg_alpha : 0.0030242975914927706
min_sum_hessian_in_leaf : 1.4637072426767108
reg_lambda : 4.869621409735013e-06
n_estimators : 857
另外,还会绘制出对应的可视化图,如图7-8所示。
优化历史图
超参数重要性图
中间值曲线图
功能重要性统计图(总计1)
图7-8 'Low' 列的模型预测可视化图
另外,还会输出展示了 LGBMTuner 在超参数优化过程中的相关信息,包括 Optuna 优化结束后的最佳试验号、最佳迭代次数、RMSE 等信息。接下来,输出了预测结果和实际值,并计算了 MAE(平均绝对误差)和 RMSE(均方根误差)。在 'Low' 列的情况下,还输出了差异的均值和方差。
总之,这些输出信息提供了对模型预测结果和性能评估的全面概览,对于评估模型性能和调整参数提供了重要参考。整
(3)请看下面的这段代码,使用 Matplotlib 绘制了 'Low' 列的预测值(蓝色虚线)和实际值(橙色实心点)曲线图。首先,通过 data[-90:].index 获取最后90天的日期索引,然后通过 pd.DataFrame(Gold.index[-90:]).values 将其转换为 DataFrame 格式。接下来,使用 plt.plot() 分别绘制预测值和实际值,并通过 plt.xticks(rotation=90) 使 x 轴标签旋转90度以提高可读性。最后,通过 plt.legend() 添加图例,通过 plt.show() 显示图表。
x = data[-90:].index
x = pd.DataFrame(Gold.index[-90:]).values
# plot Low prediction and actual price
plt.plot(x, low_prediction[0],'--bo', label = "predict",linestyle = 'dashed')
plt.plot(x, low_prediction[1],marker='o', label = "Actual")
plt.xticks(rotation = 90)
plt.legend()
plt.show()
执行效果如图7-8所示,这个图有助于直观地比较模型的预测结果与实际情况。
图7-8 'Low' 列的预测值(蓝色虚线)和实际值(橙色实心点)曲线图
(3)调用函数prediction,对金价数据中的 'High' 列进行预测。使用滞后期列表 [2, 3, 4, 5],滚动窗口大小为 2,L-矩计算窗口大小为 5 进行特征工程。函数返回了对 'High' 列的预测结果、实际值以及评估指标(均方误差、均方根误差等)。此过程有助于了解模型在 'High' 列上的预测性能和交易策略评估。
high_prediction = prediction(Gold,'High',[i for i in range(2,6)],2,5)
上面的代码类似于前面对 'Low' 列的预测代码,会执行 函数prediction对 'High' 列进行预测时,也会输出与模型性能相关的信息,包括 Optuna 优化结果、MAE、RMSE、差异均值和方差等。同时,预测结果和实际值的可视化图表也会被绘制,以便直观地比较模型的预测效果。如图7-8所示。
优化历史图
超参数重要性图
中间值曲线图
功能重要性统计图(总计1)
图7-8 'High'列的模型预测可视化图
这种输出和可视化的方式有助于全面评估模型在不同列上的表现,为金价预测和交易策略的分析提供参考。
(4)使用Matplotlib 绘制'High' 列的预测值(蓝色虚线)和实际值(橙色实心点)的时间序列图。通过 plt.plot() 分别绘制了预测值和实际值,并通过 plt.xticks(rotation=90) 使 x 轴标签旋转90度以提高可读性。最后,通过 plt.legend() 添加图例,通过 plt.show() 显示图表。
plt.plot(x, high_prediction[0],'--bo', label = "predict",linestyle = 'dashed')
plt.plot(x, high_prediction[1],marker='o', label = "Actual")
plt.xticks(rotation = 90)
plt.legend()
plt.show()
执行效果如图7-8所示,这个可视化图直观地展示了模型对 'High' 列的预测效果,方便比较预测结果与实际情况。
图7-8 'High' 列的预测值和实际值的时间序列图