手记

使用TensorFlow和LSTM注意力机制进行高级股票模式预测:以苹果公司(AAPL)数据为例的分步指南

介绍

在快速变化的金融市场中,准确的预测就像是圣杯一样。当我们寻求更高级的技术来解读市场趋势时,机器学习成为了一线希望。在各种机器学习模型中,长短期记忆网络(LSTM)受到了极大的关注。当与注意力机制结合时,这些模型变得更加强大,尤其是在分析像股票价格这样的时间序列数据时。本文深入探讨了LSTM网络与注意力机制相结合的世界,重点预测苹果公司(AAPL)股票价格的下一个四根K线的模式,使用来自Yahoo Finance(yfinance)的数据。所有数据都在这里

第1部分:理解金融建模中的LSTM和注意力机制
LSTM网络的基础

LSTM 网络是一种特殊的循环神经网络(RNN),专门设计用于长时间记住和处理数据序列。LSTM 与传统 RNN 的区别在于它们能够长时间保存信息,这得益于其独特的结构,包括三个门:输入门、遗忘门和输出门。这些门协同工作,管理信息的流动,决定保留什么和丢弃什么,从而缓解了标准 RNN 中常见的梯度消失问题。

在金融市场中,这种记住并利用长期依赖关系的能力是非常宝贵的。例如,股票价格不仅受到近期趋势的影响,还受到长时间内建立的模式的影响。LSTM网络能够很好地捕捉这些时间依赖关系,使其成为金融时间序列分析的理想选择。

注意力机制:增强LSTM

注意力机制最初在自然语言处理领域流行起来,现在已经应用于包括金融在内的多个领域。它的运作基于一个简单而深刻的概念:输入序列中的各个部分并非同等重要。通过允许模型专注于输入序列的特定部分并忽略其他部分,注意力机制增强了模型的上下文理解能力。

将注意力机制融入LSTM网络中,可以使得模型更加聚焦和理解上下文。在预测股票价格时,某些历史数据点可能比其他数据点更为相关。注意力机制使得LSTM能够对这些点赋予更大的权重,从而产生更准确和细致的预测。

金流模式预测中的相关性

将LSTM与注意力机制结合可以构建一个强大的模型来预测金融模式。金融市场是一个复杂的自适应系统,受到众多因素的影响,并表现出非线性特征。传统模型往往难以捕捉这种复杂性。然而,LSTM网络,尤其是结合了注意力机制的网络,擅长揭示这些模式,提供对未来股票走势更深入的理解和更准确的预测。

当我们着手构建并实现一个带有注意力机制的LSTM模型来预测AAPL股票的下一个四个蜡烛图时,我们深入到了一个复杂的金融分析领域,这一领域有望改变我们解读和应对股市不断变化动态的方式。

第2部分:设置您的环境

为了开始构建我们的带有注意力机制的LSTM模型以预测AAPL股票模式,第一步是设置我们的编码环境在Google Colab中。Google Colab提供了一个基于云的服务,提供了一个带有GPU支持的免费Jupyter笔记本环境,这对于运行深度学习模型非常理想。

    !pip install tensorflow -qqq  
    !pip安装keras -qqq  
    !pip安装yfinance -qqq
设置环境

安装完成后,我们可以将这些库导入到我们的Python环境中。运行以下代码:

    import tensorflow as tf  
    import keras  
    import yfinance as yf  
    import numpy as np  
    import pandas as pd  
    import matplotlib.pyplot as plt  

    # 检查TensorFlow版本  
    print("TensorFlow Version: ", tf.__version__)

此代码不仅导入了所需的库,还检查了 TensorFlow 的版本,以确保一切都是最新的。

从yfinance获取数据
获取历史数据

为了分析AAPL股票的模式,我们需要历史股票价格数据。这里就轮到yfinance登场了。这个库设计用于从Yahoo Finance获取历史市场数据。

数据下载代码

在你的 Colab 笔记本中运行以下代码以下载 AAPL 的历史数据:

    # 获取 AAPL 数据  
    aapl_data = yf.download('AAPL', start='2020-01-01', end='2024-01-01')  

    # 显示数据框的前几行  
    aapl_data.head()

此脚本获取了苹果公司(Apple Inc.)从2020年1月1日至2024年1月1日的每日股票价格。您可以根据需要调整开始和结束日期。

数据预处理和特征选择的重要性

一旦数据被获取,预处理和特征选择变得至关重要。预处理包括清理数据并使其适合模型使用。这包括处理缺失值、规范化或缩放数据,以及可能创建额外的特征,如移动平均值或百分比变化,这些都有助于模型更有效地学习。

特征选择是指选择那些对预测变量贡献最大的特征集合。对于股票价格预测,通常使用的特征包括开盘价、收盘价、最高价、最低价和成交量。选择提供相关信息的特征非常重要,以防止模型从噪声中学习。

在接下来的部分中,我们将预处理这些数据,并构建带有注意力层的LSTM模型,开始进行预测。

第3部分:数据预处理和准备

在构建我们的LSTM模型之前,第一步是准备我们的数据集。本节涵盖了数据预处理的必要阶段,以便将来自yfinance的AAPL股票数据准备好用于我们的LSTM模型。

数据清洗

股市数据集常常包含异常值或缺失值。处理这些数据对于防止预测不准确至关重要。

  • 识别缺失值:检查数据集中是否存在任何缺失数据。如果存在,可以选择使用前向填充或后向填充等方法填充这些缺失值,或者直接删除这些行。
    # 检查缺失值  
    aapl_data.isnull().sum()  

    # 填充缺失值,如果有  
    aapl_data.fillna(method='ffill', inplace=True)
  • 处理异常:有时,由于数据收集过程中的故障,数据集中会包含错误值。如果你发现任何异常(例如股票价格中不现实的极端波动),应该对其进行修正或移除。
特征选择

在股票市场数据中,各种特征都可能具有影响力。通常会使用“开盘价”、“最高价”、“最低价”、“收盘价”和“成交量”。

  • 决定特征:对于我们的模型,我们将使用“Close”价格,但你可以尝试使用其他特征,如“Open”,“High”,“Low”和“Volume”。
归一化

归一化是一种用于将数据集中数值列的值转换为同一尺度的技术,同时不扭曲值范围之间的差异。

  • 应用最小-最大缩放:这将数据集缩放,使得所有输入特征的值都在0到1之间。
从 sklearn.preprocessing 导入 MinMaxScaler  

scaler = MinMaxScaler(feature_range=(0,1))  
aapl_data_scaled = scaler.fit_transform(aapl_data['Close'].values.reshape(-1,1))
创建序列

LSTM 模型需要输入以序列格式提供。我们将数据转换为序列格式,以便模型从中学习。

  • 定义序列长度:选择一个序列长度(例如60天)。这意味着,对于每个样本,模型将根据最近60天的数据来进行预测。
    X = []  
    y = []  

    for i in range(60, len(aapl_data_scaled)):  
        X.append(aapl_data_scaled[i-60:i, 0])  
        y.append(aapl_data_scaled[i, 0])
训练-测试拆分

将数据分为训练集和测试集以正确评估模型的性能。

  • 定义分割比例:通常,80%的数据用于训练,20%的数据用于测试。
    train_size = int(len(X) * 0.8)  
    test_size = len(X) - train_size  

    X_train, X_test = X[:train_size], X[train_size:]  
    y_train, y_test = y[:train_size], y[train_size:]
数据重塑以适应LSTM

最后,我们需要将数据重塑为LSTM层所需的3D格式 [样本数, 时间步, 特征]

  • 重塑数据:
    X_train, y_train = np.array(X_train), np.array(y_train)  
    X_train = np.reshape(X_train, (X_train.shape[0], X_train.shape[1], 1))

在下一节中,我们将利用这些预处理的数据来构建和训练带有注意力机制的LSTM模型。

第4部分:构建带有注意力机制的LSTM模型

在本节中,我们将深入构建带有注意力机制的LSTM模型,专门用于预测AAPL股票模式。这需要使用TensorFlow和Keras,这两个库应该已经安装在你的Google Colab环境中。

创建LSTM层

我们的LSTM模型将包含几个层次,包括用于处理时间序列数据的LSTM层。基本结构如下:

    from keras.models import Sequential  
    from keras.layers import LSTM, Dense, Dropout, AdditiveAttention, Permute, Reshape, Multiply  

    model = Sequential()  

    # 添加返回序列的LSTM层  
    model.add(LSTM(units=50, return_sequences=True, input_shape=(X_train.shape[1], 1)))  
    model.add(LSTM(units=50, return_sequences=True))

在这个模型中,units 表示每个 LSTM 层中的神经元数量。return_sequences=True 在第一层中非常重要,以确保输出包含序列,这对于堆叠 LSTM 层是必不可少的。最终的 LSTM 层不返回序列,因为我们准备将数据传递给注意力层。

集成注意力机制

注意力机制可以添加以增强模型聚焦于相关时间步的能力:

    # 添加自注意力机制  
    # 注意力机制  
    attention = AdditiveAttention(name='attention_weight')  
    # 调整维度以兼容  
    model.add(Permute((2, 1)))   
    model.add(Reshape((-1, X_train.shape[1])))  
    attention_result = attention([model.output, model.output])  
    multiply_layer = Multiply()([model.output, attention_result])  
    # 恢复原始形状  
    model.add(Permute((2, 1)))   
    model.add(Reshape((-1, 50)))  

    # 在最终 Dense 层之前添加一个 Flatten 层  
    model.add(tf.keras.layers.Flatten())  

    # 最终 Dense 层  
    model.add(Dense(1))  

    # 编译模型  
    # model.compile(optimizer='adam', loss='mean_squared_error')  

    # 训练模型  
    # history = model.fit(X_train, y_train, epochs=100, batch_size=25, validation_split=0.2)

这个自定义层计算输入序列的加权和,使模型能够更关注某些时间步。

优化模型

为了提升模型的表现并降低过拟合的风险,我们加入了Dropout和Batch Normalization。

    from keras.layers import BatchNormalization  

    # 添加Dropout和Batch Normalization  
    model.add(Dropout(0.2))  
    model.add(BatchNormalization())

Dropout 通过在训练过程中随机将一部分输入单元设置为 0 来防止过拟合,而 Batch Normalization 则稳定了学习过程。

模型编译

最后,我们用适合我们回归任务的优化器和损失函数编译模型。

    model.compile(optimizer='adam', loss='mean_squared_error')

adam优化器通常适合用于循环神经网络,均方误差作为损失函数在像我们这样的回归任务中表现良好。

模型摘要

查看模型的摘要有助于理解其结构和参数数量。

    model.summary()

第5部分:训练模型

现在我们的带有注意力机制的LSTM模型已经建立,是时候使用我们准备好的训练集来训练它了。这个过程包括将训练数据输入模型,让它学习如何进行预测。

训练代码

使用以下代码来使用 X_trainy_train 训练你的模型:

    # 假设 X_train 和 y_train 已经定义并预处理  
    history = model.fit(X_train, y_train, epochs=100, batch_size=25, validation_split=0.2)

在这里,我们用一批大小为25的数据训练模型100个周期。validation_split 参数预留了一部分训练数据用于验证,使我们能够在训练过程中监控模型在未见数据上的表现。

过拟合及其避免方法

当模型学习了特定于训练数据的模式,而这些模式无法泛化到新数据时,就会发生过拟合。以下是避免过拟合的方法:

  1. 验证集:使用验证集(就像我们在训练代码中所做的那样)有助于监控模型在未见过的数据上的表现。
  2. 早停法:当模型在验证集上的表现开始下降时,这种方法会停止训练。在Keras中实现早停法很简单:
    从 keras.callbacks 导入 EarlyStopping  

    early_stopping = EarlyStopping(monitor='val_loss', patience=10)  
    history = model.fit(X_train, y_train, epochs=100, batch_size=25, validation_split=0.2, callbacks=[early_stopping])
  1. 这里,patience=10 表示如果验证损失在连续 10 个周期内没有改善,训练将会停止。
  2. 正则化技术:像 Dropout 和 Batch Normalization 这样的技术,已经在我们的模型中包含,也有助于减少过拟合。

可选:这些是更多的回调

    from keras.callbacks import ModelCheckpoint, ReduceLROnPlateau, TensorBoard, CSVLogger  

    # 回调以定期保存模型  
    model_checkpoint = ModelCheckpoint('best_model.h5', save_best_only=True, monitor='val_loss')  

    # 回调以在指标停止改善时降低学习率  
    reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=5)  

    # TensorBoard 回调  
    tensorboard = TensorBoard(log_dir='./logs')  

    # 回调以将详细信息记录到 CSV 文件  
    csv_logger = CSVLogger('training_log.csv')  

    # 结合所有回调  
    callbacks_list = [early_stopping, model_checkpoint, reduce_lr, tensorboard, csv_logger]  

    # 使用回调拟合模型  
    history = model.fit(X_train, y_train, epochs=100, batch_size=25, validation_split=0.2, callbacks=callbacks_list)
第6节:评估模型性能

训练模型之后,下一步是使用测试集来评估其性能。这将使我们了解模型对新、未见过的数据的一般化能力如何。

使用测试集进行评估

为了评估模型,我们首先需要像处理训练数据一样准备测试数据 (X_test)。然后,我们可以使用模型的 evaluate 函数:

    # 将 X_test 和 y_test 转换为 Numpy 数组(如果它们还不是)
    X_test = np.array(X_test)  
    y_test = np.array(y_test)  

    # 确保 X_test 的形状与 X_train 的形状一致
    # 这取决于你如何预处理训练数据
    X_test = np.reshape(X_test, (X_test.shape[0], X_test.shape[1], 1))  

    # 现在在测试数据上评估模型
    test_loss = model.evaluate(X_test, y_test)  
    print("测试损失: ", test_loss)

性能指标

除了损失之外,其他指标可以提供更多关于模型性能的见解。对于像我们这样的回归任务,常见的指标包括:

  1. 平均绝对误差(MAE):这用于衡量一组预测的误差的平均幅度,不考虑误差的方向。

  2. 均方根误差(RMSE):这是预测值和实际观察值之间平方差的平均值的平方根。

为了计算这些指标,我们可以使用我们的模型进行预测,并将其与实际值进行比较:

    from sklearn.metrics import mean_absolute_error, mean_squared_error  

    # 进行预测  
    y_pred = model.predict(X_test)  

    # 计算MAE和RMSE  
    mae = mean_absolute_error(y_test, y_pred)  
    rmse = mean_squared_error(y_test, y_pred, squared=False)  

    print("平均绝对误差: ", mae)  
    print("均方根误差: ", rmse)

模型:

  • 平均绝对误差 (MAE): 0.0724(大约)
  • 均方根误差 (RMSE): 0.0753(大约)

均方误差(MAE)和均方根误差(RMSE)都是回归模型预测准确性的衡量标准。它们表示如下:

MAE 测量一组预测的误差的平均幅度,而不考虑误差的方向。它是测试样本中预测值与实际观察值之间绝对差异的平均值,其中所有个别差异具有相同的权重。MAE 为 0.0724 表示模型的预测值平均来说与实际值相差约 0.0724 个单位。

RMSE 是一种二次评分规则,也用于衡量误差的平均幅度。它是预测值与实际观察值之间平方差的平均值的平方根。RMSE 对较大的误差给予相对较高的权重。这意味着当较大的误差特别不可接受时,RMSE 更为有用。RMSE 为 0.0753 表示模型的预测值与实际值的平均差距为 0.0753 个单位,且较大的误差被惩罚得更多。

这些指标将帮助你了解模型的准确性以及它需要改进的地方。通过分析这些指标,你可以做出明智的决策,进一步调整模型或改变方法。

在下一节中,我们将讨论如何使用该模型进行实际的股票模式预测以及在实际应用中部署此模型时需要考虑的实际问题。

第7节:预测接下来的4根K线

经过训练和评估带有注意力机制的LSTM模型后,最后一步是利用它来预测AAPL股票价格的下一个4根K线(天)。

进行预测

为了预测未来的股票价格,我们需要给模型提供最新的数据点。假设我们已经准备好了最近60天的数据,格式与 X_train 相同,并且我们想要预测接下来一天的价格:

    import yfinance as yf  
    import numpy as np  
    from sklearn.preprocessing import MinMaxScaler  

    # 获取最近60天的AAPL股票数据  
    data = yf.download('AAPL', period='60d', interval='1d')  

    # 选择收盘价并转换为numpy数组  
    closing_prices = data['Close'].values  

    # 数据缩放  
    scaler = MinMaxScaler(feature_range=(0,1))  
    scaled_data = scaler.fit_transform(closing_prices.reshape(-1,1))  

    # 由于我们需要最后60天的数据来预测下一天,因此我们需要相应地重塑数据  
    X_latest = np.array([scaled_data[-60:].reshape(60)])  

    # 重塑数据以适应模型(添加批量维度)  
    X_latest = np.reshape(X_latest, (X_latest.shape[0], X_latest.shape[1], 1))  

    # 预测接下来4根K线的价格  
    predicted_stock_price = model.predict(X_latest)  
    predicted_stock_price = scaler.inverse_transform(predicted_stock_price)  

    print("预测的未来4天的股票价格: ", predicted_stock_price)

让我们预测接下来4天的价格:

    import yfinance as yf  
    import numpy as np  
    from sklearn.preprocessing import MinMaxScaler  

    # 获取最近60天的AAPL股票数据  
    data = yf.download('AAPL', period='60d', interval='1d')  

    # 选择收盘价并进行缩放  
    closing_prices = data['Close'].values.reshape(-1, 1)  
    scaler = MinMaxScaler(feature_range=(0, 1))  
    scaled_data = scaler.fit_transform(closing_prices)  

    # 逐天迭代预测接下来的4天  
    predicted_prices = []  
    current_batch = scaled_data[-60:].reshape(1, 60, 1)  # 最近60天的数据  

    for i in range(4):  # 预测4天  
        # 获取预测结果(下一天的价格)  
        next_prediction = model.predict(current_batch)  

        # 将预测结果重塑以适应批量维度  
        next_prediction_reshaped = next_prediction.reshape(1, 1, 1)  

        # 将预测结果添加到预测批量中  
        current_batch = np.append(current_batch[:, 1:, :], next_prediction_reshaped, axis=1)  

        # 将预测结果逆向转换为原始价格尺度  
        predicted_prices.append(scaler.inverse_transform(next_prediction)[0, 0])  

    print("预测的未来4天的股票价格:", predicted_prices)

预测可视化

将预测值与实际股价进行可视化比较可以非常有启发性。以下是绘制预测股价与实际数据的代码:

    !pip install mplfinance -qqq  
    import pandas as pd  
    import mplfinance as mpf  
    import matplotlib.dates as mpl_dates  
    import matplotlib.pyplot as plt  

    # 假设 'data' 是你获取的 AAPL 股票数据的 DataFrame  
    # 确保它包含 Open, High, Low, Close 和 Volume 列  

    # 为预测创建日期列表  
    last_date = data.index[-1]  
    next_day = last_date + pd.Timedelta(days=1)  
    prediction_dates = pd.date_range(start=next_day, periods=4)  

    # 假设 'predicted_prices' 是你预测的未来 4 天的股价列表  
    predictions_df = pd.DataFrame(index=prediction_dates, data=predicted_prices, columns=['Close'])  

    # 使用 mplfinance 绘制实际数据  
    mpf.plot(data, type='candle', style='charles', volume=True)  

    # 叠加预测数据  
    plt.figure(figsize=(10,6))  
    plt.plot(predictions_df.index, predictions_df['Close'], linestyle='dashed', marker='o', color='red')  

    plt.title("AAPL 股价及未来 4 天预测")  
    plt.show()

预测最终可视化:
    import pandas as pd  
    import mplfinance as mpf  
    import matplotlib.dates as mpl_dates  
    import matplotlib.pyplot as plt  

    # 获取最近60天的AAPL股票数据  
    data = yf.download('AAPL', period='64d', interval='1d') # 获取64天数据以在图表中显示最后60天  

    # 选择收盘价并进行缩放  
    closing_prices = data['Close'].values.reshape(-1, 1)  
    scaler = MinMaxScaler(feature_range=(0, 1))  
    scaled_data = scaler.fit_transform(closing_prices)  

    # 迭代预测接下来的4天  
    predicted_prices = []  
    current_batch = scaled_data[-60:].reshape(1, 60, 1)  # 最近60天  

    for i in range(4):  # 预测4天  
        next_prediction = model.predict(current_batch)  
        next_prediction_reshaped = next_prediction.reshape(1, 1, 1)  
        current_batch = np.append(current_batch[:, 1:, :], next_prediction_reshaped, axis=1)  
        predicted_prices.append(scaler.inverse_transform(next_prediction)[0, 0])  

    # 创建预测日期列表  
    last_date = data.index[-1]  
    next_day = last_date + pd.Timedelta(days=1)  
    prediction_dates = pd.date_range(start=next_day, periods=4)  

    # 将预测添加到DataFrame中  
    predicted_data = pd.DataFrame(index=prediction_dates, data=predicted_prices, columns=['Close'])  

    # 合并实际和预测数据  
    combined_data = pd.concat([data['Close'], predicted_data['Close']])  
    combined_data = combined_data[-64:] # 最近60天的实际数据 + 4天的预测数据  

    # 绘制实际数据  
    plt.figure(figsize=(10,6))  
    plt.plot(data.index[-60:], data['Close'][-60:], linestyle='-', marker='o', color='blue', label='实际数据')  

    # 绘制预测数据  
    plt.plot(prediction_dates, predicted_prices, linestyle='-', marker='o', color='red', label='预测数据')  

    plt.title("AAPL股票价格:最后60天和接下来4天的预测")  
    plt.xlabel('日期')  
    plt.ylabel('价格')  
    plt.legend()  
    plt.show()

结论

在本指南中,我们探讨了使用LSTM网络结合注意力机制进行股票价格预测的复杂而迷人的任务,特别是针对苹果公司(AAPL)。关键点包括:

  • LSTM 捕捉时间序列数据中长期依赖关系的能力。
  • 注意机制在聚焦相关数据点上的额外优势。
  • 构建、训练和评估 LSTM 模型的详细过程。

虽然带有注意力机制的LSTM模型非常强大,但它们也存在一些局限性:

  • 假设历史模式会在类似的方式中重复可能是有问题的,特别是在波动的市场中。
  • 外部因素如市场新闻和全球事件,这些因素未包含在历史价格数据中,可以显著影响股票价格。
参考资料

本指南应作为那些有兴趣在金融市场中应用深度学习技术的入门点。鼓励持续探索和实验,以精炼和适应这些方法,使其适用于更复杂的应用。

附加说明:从任意日期计算:

    import yfinance as yf  
    import numpy as np  
    import pandas as pd  
    from sklearn.preprocessing import MinMaxScaler  
    from datetime import datetime, timedelta  

    def predict_stock_price(input_date):  
        # 检查输入日期是否为有效日期格式  
        try:  
            input_date = pd.to_datetime(input_date)  
        except ValueError:  
            print("无效的日期格式。请输入 YYYY-MM-DD 格式的日期。")  
            return  

        # 从 yfinance 获取数据  
        end_date = input_date  
        start_date = input_date - timedelta(days=90)  # 获取更多天数以确保我们有 60 个交易日  
        data = yf.download('AAPL', start=start_date, end=end_date)  

        if len(data) < 60:  
            print("没有足够的历史数据进行预测。请尝试更早的日期。")  
            return  

        # 准备数据  
        closing_prices = data['Close'].values[-60:]  # 最近 60 天  
        scaler = MinMaxScaler(feature_range=(0, 1))  
        scaled_data = scaler.fit_transform(closing_prices.reshape(-1, 1))  

        # 进行预测  
        predicted_prices = []  
        current_batch = scaled_data.reshape(1, 60, 1)  

        for i in range(4):  # 预测 4 天  
            next_prediction = model.predict(current_batch)  
            next_prediction_reshaped = next_prediction.reshape(1, 1, 1)  
            current_batch = np.append(current_batch[:, 1:, :], next_prediction_reshaped, axis=1)  
            predicted_prices.append(scaler.inverse_transform(next_prediction)[0, 0])  

        # 输出预测结果  
        for i, price in enumerate(predicted_prices, 1):  
            print(f"第 {i} 天预测:{price}")  

    # 示例用法  
    user_input = input("输入一个日期(YYYY-MM-DD)来预测苹果股票接下来 4 天的价格:")  
    predict_stock_price(user_input)
0人推荐
随时随地看视频
慕课网APP