(15-6)基于时间序列预测的比特币自动交易系统:创建机器学习模型

1.5.6  机器学习模型

1. 数据准备

(1)导入sklearn 库中的两个模块,用于创建机器学习模型。

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler

(2)下面代码创建了一个名为 closedf 的数据框,其中包含了比特币的日期 (Date) 和收盘价 (Close) 两列。通过 BTC_data[['Date','Close']] 选择了原始数据框中的这两列,并使用 print 打印出 closedf 数据框的形状(行数和列数)。这有助于了解所选数据的维度信息。

closedf = BTC_data[['Date','Close']]
print("Forme du dataframe close", closedf.shape)

执行后会输出:

Forme du dataframe close (2587, 2)

(3)下面代码通过筛选操作选择了 closedf 数据框中日期在 '2020-09-13' 之后的数据,并将结果保存在名为 close_stock 的新数据框中。最后通过 print语句打印出了筛选后的数据框形状信息,显示了在 '2020-09-13' 之后的数据总数,用于进行后续的预测任务。

closedf = closedf[closedf['Date'] > '2020-09-13']
close_stock = closedf.copy()
print("Données totales pour la prédiction : ",closedf.shape[0])

执行后会输出:

Données totales pour la prédiction :  504

(4)下面这段代码首先移除了数据框中的日期列,然后使用MinMaxScaler对比特币收盘价进行归一化处理,将其缩放到范围[0, 1]内。最后,打印出处理后的数据框形状,确保数据处理的正确性。这有助于确保在训练模型时,能够更好地理解和处理彼此具有相似数值范围的特征。

del closedf['Date']
scaler=MinMaxScaler(feature_range=(0,1))
closedf=scaler.fit_transform(np.array(closedf).reshape(-1,1))
print(closedf.shape)

执行后会输出:

(504, 1)

(5)下面的代码计算了用于训练和测试的数据集划分大小。首先,根据数据的总长度,将70%作为训练数据的大小,剩余30%作为测试数据的大小。然后,根据这两个大小,从归一化处理后的数据 closedf 中划分出相应的训练数据集 train_data 和测试数据集 test_data。这一步是为了准备数据,以便将其输入到机器学习模型中进行训练和评估。

training_size=int(len(closedf)*0.70)

test_size=len(closedf)-training_size

train_data,test_data=closedf[0:training_size,:],closedf[training_size:len(closedf),:1]

(6)下面这段代码分别打印输出了训练数据集和测试数据集的大小。通过使用 shape[0] 获取数据集的行数,分别输出了训练数据集的大小和测试数据集的大小。这有助于了解在模型训练和评估过程中所使用的数据规模。

print("la taille des données d'entraînement est: ",train_data.shape[0])

print("la taille d'échantillon du test est: ",test_data.shape[0])

执行后会输出:

la taille des données d'entraînement est:  352

la taille d'échantillon du test est:  152

(7)下面这段代码绘制了一个折线图,展示了训练数据集(黑色线段)和测试数据集(红色线段)中比特币的收盘价随时间的变化趋势。通过 train_data.shape[0] 获取训练数据的行数,从而确定在折线图中哪一部分属于训练集。图表的标题为 "Train & Test data",横轴表示日期,纵轴表示比特币的周收盘价。图例说明了黑色线段为训练数据,红色线段为测试数据。

fig, ax = plt.subplots(figsize=(20, 10))
sb.lineplot(x = close_stock['Date'][:train_data.shape[0]], y = close_stock['Close'][:train_data.shape[0]], color = 'black')
sb.lineplot(x = close_stock['Date'][train_data.shape[0]:], y = close_stock['Close'][train_data.shape[0]:], color = 'red')

# Formatting
ax.set_title('Train & Test data', fontsize = 20, loc='center', fontdict=dict(weight='bold'))
ax.set_xlabel('Date', fontsize = 16, fontdict=dict(weight='bold'))
ax.set_ylabel('Weekly Sales', fontsize = 16, fontdict=dict(weight='bold'))
plt.tick_params(axis='y', which='major', labelsize=16)
plt.tick_params(axis='x', which='major', labelsize=16)
plt.legend(loc='upper right' ,labels = ('train', 'test'))

执行效果如图7-8所示,这有助于直观地了解训练和测试数据的分布。

图7-8  比特币的收盘价随时间的变化趋势曲线图

(8)创建一个名为 create_dataset 的函数,用于将时间序列数据转换为适用于监督学习的数据集。函数接受两个参数,dataset 是输入的时间序列数据,time_step 是指定的时间步长(默认为1)。

def create_dataset(dataset, time_step=1):
    dataX, dataY = [], []
    for i in range(len(dataset)-time_step-1):
        a = dataset[i:(i+time_step), 0]   #i=0, 0,1,2,3-----99   100 
        dataX.append(a)
        dataY.append(dataset[i + time_step, 0])
    return np.array(dataX), np.array(dataY)

在函数create_dataset的内部,通过循环遍历数据集,对于每个时间步长,提取出一个输入序列 dataX 和相应的目标值 dataY。最终,将这些序列整理成 NumPy 数组并返回。这种数据集的创建适用于训练监督学习模型,其中每个样本包括过去的一段时间步的观测作为输入,而下一个时间步的观测作为输出。

(9)下面代码调用了上面定义的函数,将训练数据集和测试数据集分别转换为适用于监督学习的数据集。参数 time_step 指定了时间步长,表示每个样本包含的过去时间步数。

time_step = 15
X_train, y_train = create_dataset(train_data, time_step)
X_test, y_test = create_dataset(test_data, time_step)


print("X_train: ", X_train.shape)
print("y_train: ", y_train.shape)
print("X_test: ", X_test.shape)
print("y_test", y_test.shape)

在上述代码中,通过调用 create_dataset 函数,得到训练集的输入 X_train 和输出 y_train,以及测试集的输入 X_test 和输出 y_test。打印出各个数据集的形状信息,以确认数据集的正确创建。执行后会输出:

X_train:  (336, 15)
y_train:  (336,)
X_test:  (136, 15)
y_test (136,)

2. 模型构建

(1)下面这段代码创建了三个不同的回归模型:线性回归模型 (LinearRegression)、XGBoost回归模型 (XGBRegressor) 和随机森林回归模型 (RandomForestRegressor)。这些模型分别被命名为 LR、XGBoost 和 RFR。最后,将这些模型存储在一个名为 models 的字典中,其中键为模型名称,值为相应的模型对象。这有助于在后续的步骤中方便地引用和使用这些模型。

LR=LinearRegression()

XGBoost = XGBRegressor(n_estimators=100, learning_rate=0.3,
                     max_delta_step=0, max_depth=6, n_jobs=4,
                     num_parallel_tree=1, random_state=0)

RFR = RandomForestRegressor(max_depth=1000)
models = {"Linear Regression":LR, "XGBoost Regressor":XGBoost, "Random Forest Regressor":RFR}

(2)定义函数train_model,用于训练指定模型并在测试集上进行预测。函数train_model接受一个模型名称作为参数,然后使用该模型对训练数据进行拟合,并在测试数据上进行预测。最后,输出该模型的预测性能评估指标,包括平均绝对误差(MAE)和均方根误差(RMSE)。

def train_model(model_name):
    models[model_name].fit(X_train,y_train)
    predictions = models[model_name].predict(X_test)
    print("\n---------------"+model+"---------------\n")
    print("Mean Absolute Error - MAE : " + str(mean_absolute_error(y_test, predictions)))
    print("Root Mean squared Error - RMSE : " + str(math.sqrt(mean_squared_error(y_test, predictions)))+"\n")

(3)在循环中,模型字典中的每个模型调用 train_model 函数,实现了对所有模型的训练和评估。这有助于比较不同模型在给定任务上的性能表现。

for model in models:
    train_model(model)

执行后会输出:

---------------Linear Regression---------------

Mean Absolute Error - MAE : 0.02468877316851655
Root Mean squared Error - RMSE : 0.03204950005533036


---------------XGBoost Regressor---------------

Mean Absolute Error - MAE : 0.047398661971883777
Root Mean squared Error - RMSE : 0.06095256391999026


---------------Random Forest Regressor---------------

Mean Absolute Error - MAE : 0.030420887668338583
Root Mean squared Error - RMSE : 0.03881724290350216

(4)下面的这段代码定义了一个名为 predict 的函数,用于使用指定的模型进行训练集和测试集的预测。函数predict接受一个模型名称作为参数,然后使用该模型对训练数据和测试数据进行预测。在预测之后,将预测结果进行逆转换,将其还原回原始的数据范围。

def predict(model_name):
    train_predict=models[model_name].predict(X_train)
    test_predict=models[model_name].predict(X_test)

    # Transform back to original form
    train_predict = train_predict.reshape(-1,1)
    test_predict = test_predict.reshape(-1,1)

    train_predict = scaler.inverse_transform(train_predict)
    test_predict = scaler.inverse_transform(test_predict)
    
    return train_predict, test_predict

具体而言,上述代码的功能是将训练集和测试集的预测结果从归一化的形式转换回原始的货币单位(USD),这样可以更好地理解模型的预测结果,并进行进一步的分析。

3. 评估模型

(1)定义一个名为 eval 的函数,用于评估指定模型的性能,并展示模型在训练集和测试集上的预测结果。函数eval接受一个模型名称作为参数,首先通过调用 predict 函数获取训练集和测试集的预测结果,然后将这些结果进行逆转换,将其还原回原始的货币单位(USD)。接着,通过使用库Plotly创建交互式的线形图,将原始的关闭价格、训练集的预测关闭价格和测试集的预测关闭价格进行可视化比较。最后,输出了一些回归评价指标,包括训练数据和测试数据的解释方差回归分数以及R方分数。

rom itertools import cycle
def eval(model):
    train_predict, test_predict = predict(model)
    # shift train predictions for plotting
    look_back=time_step
    trainPredictPlot = np.empty_like(closedf)
    trainPredictPlot[:, :] = np.nan
    trainPredictPlot[look_back:len(train_predict)+look_back, :] = train_predict

    # shift test predictions for plotting
    testPredictPlot = np.empty_like(closedf)
    testPredictPlot[:, :] = np.nan
    testPredictPlot[len(train_predict)+(look_back*2)+1:len(closedf)-1, :] = test_predict
    
    original_ytrain = scaler.inverse_transform(y_train.reshape(-1,1)) 
    original_ytest = scaler.inverse_transform(y_test.reshape(-1,1)) 

    names = cycle(['Original close price','Train predicted close price','Test predicted close price'])

    plotdf = pd.DataFrame({'date': close_stock['Date'],
                           'original_close': close_stock['Close'],
                          'train_predicted_close': trainPredictPlot.reshape(1,-1)[0].tolist(),
                          'test_predicted_close': testPredictPlot.reshape(1,-1)[0].tolist()})

    fig = px.line(plotdf,x=plotdf['date'], y=[plotdf['original_close'],plotdf['train_predicted_close'],
                                              plotdf['test_predicted_close']],
                  labels={'value':'Close price','date': 'Date'})
    fig.update_layout(title_text='Prediction avec le '+model,
                      plot_bgcolor='white', font_size=15, font_color='black',legend_title_text='Close Price')
    fig.for_each_trace(lambda t:  t.update(name = next(names)))

    fig.update_xaxes(showgrid=False)
    fig.update_yaxes(showgrid=False)
    fig.show()
    
    ## Variance Regression Score
    print("\n\nTrain data explained variance regression score:", 
          explained_variance_score(original_ytrain, train_predict))
    print("Test data explained variance regression score:", 
          explained_variance_score(original_ytest, test_predict))

    ## R square score for regression
    print("\nTrain data R2 score:", r2_score(original_ytrain, train_predict))
    print("Test data R2 score:", r2_score(original_ytest, test_predict))

函数eval有助于全面了解模型在不同数据集上的表现,并通过可视化方式直观地比较模型的预测结果。

(2)通过for循环对每个模型调用 eval 函数,评估了线性回归(Linear Regression)、XGBoost 回归(XGBoost Regressor)和随机森林回归(Random Forest Regressor)在训练集和测试集上的性能表现。该过程包括可视化原始关闭价格与训练集、测试集的预测关闭价格的比较,以及输出解释方差回归分数和R方分数等回归评价指标。

for model in models:
    eval(model)

执行后,对于每个模型(Linear Regression模型、XGBoost Regressor 模型、Random Forest Regressor 模型),将绘制一个交互式的线形图,展示原始的比特币关闭价格(Close Price)、训练集的预测关闭价格和测试集的预测关闭价格。例如针对Linear Regression 模型,绘制如图7-8所示的线形图。图中会有三条线,具体说明如下所示。

  1. 原始的比特币关闭价格(Original close price):显示原始的比特币价格随时间的变化。
  2. 训练集的预测关闭价格(Train predicted close price):显示模型在训练集上的预测结果。
  3. 测试集的预测关闭价格(Test predicted close price):显示模型在测试集上的预测结果。

图7-8  Linear Regression 模型的线形图

并输出下面的得分信息,这些分数说明模型在训练集和测试集上都表现得非常好,具有很高的拟合度和预测准确度。解释方差回归分数越接近1,表示模型对数据的解释能力越强,而 R2 分数也越接近1,表示模型的预测效果越好。

Train data explained variance regression score: 0.9884835588523104
Test data explained variance regression score: 0.9522424065346115

Train data R2 score: 0.9884835588523104
Test data R2 score: 0.9522347837752287

未完待续

  • 29
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农三叔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值