我们需要使用股票数据来构建适合LSTM输入的序列数据。
LSTM通常用于处理时间序列数据,其输入数据的形状通常为:(样本数, 时间步长, 特征数)。
也就是说,每个样本是一个时间序列片段,包含连续的时间步,每个时间步有多个特征。
假设我们有一组股票数据,包括开盘价(open)、最高价(high)、最低价(low)、收盘价(close)、成交量(volume)等。我们想要用过去N天的数据(时间步长=N)来预测下一天的收盘价。
那么,我们需要构建的输入数据就是一个个连续的N天窗口,每个窗口有N个时间步,每个时间步有多个特征(例如开盘价、最高价、最低价、收盘价、成交量)。
下面我们通过一个例子来展示如何构建这样的数据。
步骤:
- 加载股票数据(这里我们使用模拟数据)。
- 对数据进行归一化(通常对于LSTM,我们需要对每个特征进行归一化)。
- 构建数据集,将时间序列数据转换为适合LSTM的输入形状。
注意:我们通常将数据组织成多个样本,每个样本是连续的时间步,每个时间步有多个特征。
假设我们有一个包含多个特征的时间序列数据,我们想要用过去10天(时间步长=10)的数据来预测下一天的收盘价。
示例数据格式如下(模拟数据):
我来详细解释LSTM所需的序列数据格式,并用股票数据作为例子展示。
1/LSTM输入数据的基本结构
LSTM需要三维数据,形状为:(样本数, 时间步长, 特征数)
- 样本数:有多少个训练样本
- 时间步长:每个样本包含多少个时间点的数据
- 特征数:每个时间点有多少个特征
2/股票数据示例
假设我们有某股票10天的数据:
import pandas as pd
import numpy as np
# 创建示例股票数据
data = {
'date': pd.date_range('2024-01-01', periods=10, freq='D'),
'open': [100, 101, 102, 99, 98, 103, 105, 107, 106, 108],
'high': [102, 103, 104, 101, 100, 105, 107, 109, 108, 110],
'low': [99, 100, 101, 98, 97, 102, 104, 106, 105, 107],
'close': [101, 102, 103, 100, 99, 104, 106, 108, 107, 109],
'volume': [10000, 12000, 11000, 9000, 8000, 15000, 13000, 14000, 12000, 16000]
}
df = pd.DataFrame(data)
print("原始股票数据:")
print(df)
输出:
date open high low close volume
0 2024-01-01 100 102 99 101 10000
1 2024-01-02 101 103 100 102 12000
2 2024-01-03 102 104 101 103 11000
3 2024-01-04 99 101 98 100 9000
4 2024-01-05 98 100 97 99 8000
5 2024-01-06 103 105 102 104 15000
6 2024-01-07 105 107 104 106 13000
7 2024-01-08 107 109 106 108 14000
8 2024-01-09 106 108 105 107 12000
9 2024-01-10 108 110 107 109 16000
3/构建LSTM输入数据的完整过程
<1>选择特征和预处理
from sklearn.preprocessing import MinMaxScaler # 归一化
# 选择特征列
features = ['open', 'high', 'low', 'close', 'volume'] # 去掉date这一列
feature_data = df[features].values
# 数据归一化(LSTM对输入数据的尺度敏感)
scaler = MinMaxScaler()
scaled_data = scaler.fit_transform(feature_data)
print("\n归一化后的数据:")
print(scaled_data[:5]) # 显示前5行
<2>定义时间步长并创建序列
假设我们用过去3天的数据预测下一天的收盘价:
def create_sequences(data, time_steps=3):
# 创建2个空的列表, 一个存放序列, 一个存放标签
X = []
y = []
for i in range(len(data) - time_steps):
# 获取时间步长内的特征序列
sequence = data[i:(i + time_steps), :] # 包含所有特征, i从0开始
# 下一天的收盘价作为目标(假设收盘价在第3列)
# 这里是预测涨跌的幅度, 而不是预测涨和跌的二分类问题.
target = data[i + time_steps, 3] # 第3列是收盘价
# 把序列数据, 添加到之前定义的空列表中
X.append(sequence)
y.append(target)
# 最后返回, 但是要对x,y转换成数组的形式 , 转换完毕之后, 就是三维的shape了
return np.array(X), np.array(y)
# 创建序列
time_steps = 3
X, y = create_sequences(scaled_data, time_steps)
print(f"\nLSTM输入数据形状: {X.shape}")
print(f"目标数据形状: {y.shape}")
print(f"样本数: {X.shape[0]}")
print(f"时间步长: {X.shape[1]}")
print(f"特征数: {X.shape[2]}")
<3>查看具体的数据结构
print("\n=== 第一个样本 ===")
print("输入X[0] (3天×5个特征):")
print(f"形状: {X[0].shape}")
print(X[0])
print(f"\n对应的目标y[0]: {y[0]}")
print("(这是第4天的收盘价,用前3天的数据预测)")
<4>完整的数据集展示
print("\n=== 所有样本的数据结构 ===")
for i in range(len(X)):
print(f"\n样本 {i}:")
print(f"使用第 {i} 到 {i+2} 天的数据预测第 {i+3} 天的收盘价")
print(f"目标值 (第{i+3}天收盘价): {y[i]:.4f}")
4/实际应用中的完整代码示例
import pandas as pd
import numpy as np
from sklearn.preprocessing import MinMaxScaler
# 模拟更多股票数据
np.random.seed(42)
n_days = 100
dates = pd.date_range('2024-01-01', periods=n_days, freq='D')
# 生成随机股票数据
close_prices = 100 + np.cumsum(np.random.randn(n_days) * 2)
open_prices = close_prices * (1 + np.random.randn(n_days) * 0.01)
high_prices = np.maximum(open_prices, close_prices) * (1 + np.random.rand(n_days) * 0.02)
low_prices = np.minimum(open_prices, close_prices) * (1 - np.random.rand(n_days) * 0.02)
volumes = np.random.randint(5000, 20000, n_days)
df = pd.DataFrame({
'date': dates,
'open': open_prices,
'high': high_prices,
'low': low_prices,
'close': close_prices,
'volume': volumes
})
# 添加技术指标
df['ma5'] = df['close'].rolling(5).mean()
df['ma10'] = df['close'].rolling(10).mean()
df['returns'] = df['close'].pct_change()
df = df.dropna()
print("包含技术指标的股票数据:")
print(df.head(10))
print(f"\n数据形状: {df.shape}")
# 准备LSTM输入
features = ['open', 'high', 'low', 'close', 'volume', 'ma5', 'ma10', 'returns']
feature_data = df[features].values
# 归一化
scaler = MinMaxScaler()
scaled_data = scaler.fit_transform(feature_data)
# 创建序列
def create_sequences_with_labels(data, time_steps=10):
X, y = [], []
for i in range(len(data) - time_steps):
# 输入:过去time_steps天的所有特征
X.append(data[i:(i + time_steps)])
# 输出:下一天的收盘价(假设收盘价在第3列)
y.append(data[i + time_steps, 3])
return np.array(X), np.array(y)
# 创建数据集
time_steps = 10
X, y = create_sequences_with_labels(scaled_data, time_steps)
print(f"\n=== LSTM数据准备完成 ===")
print(f"输入数据 X 形状: {X.shape}")
print(f" 样本数: {X.shape[0]}")
print(f" 时间步长: {X.shape[1]}")
print(f" 特征数: {X.shape[2]}")
print(f"目标数据 y 形状: {y.shape}")
# 分割训练集和测试集
train_size = int(len(X) * 0.8)
X_train, X_test = X[:train_size], X[train_size:]
y_train, y_test = y[:train_size], y[train_size:]
print(f"\n训练集大小: {X_train.shape[0]} 个样本")
print(f"测试集大小: {X_test.shape[0]} 个样本")
5/不同时间序列任务的输入格式
<1>单变量时间序列(预测单变量)
# 只使用收盘价
univariate_data = df['close'].values.reshape(-1, 1)
# 此时输入形状为: (样本数, 时间步长, 1)
<2>多变量时间序列(预测单变量)
# 使用多个特征预测收盘价(如上例)
# 输入形状: (样本数, 时间步长, 特征数)
<3>多变量时间序列(预测多变量)
# 预测多个指标(如收盘价和成交量)
def create_multi_output_sequences(data, time_steps=10, target_features=[3, 4]):
X, y = [], []
for i in range(len(data) - time_steps):
X.append(data[i:(i + time_steps)])
# 预测多个目标
y.append(data[i + time_steps, target_features])
return np.array(X), np.array(y)
# 预测收盘价和成交量
X_multi, y_multi = create_multi_output_sequences(scaled_data, time_steps=10, target_features=[3, 4])
print(f"多输出形状 - X: {X_multi.shape}, y: {y_multi.shape}")
6/关键要点总结
- 三维结构:LSTM输入必须是三维的
(samples, timesteps, features) - 序列连续性:每个样本是连续的时间序列片段
- 时间步长选择:根据问题复杂度确定,股票通常用5-20天
- 特征工程:可以加入技术指标(MA、RSI、MACD等)
- 数据归一化:必须归一化,LSTM对数据尺度敏感
7/验证数据是否正确
def validate_sequences(X, y, original_df, feature_names):
"""验证序列数据的正确性"""
print("\n=== 数据验证 ===")
print(f"第一个样本的时间跨度:")
print(f"使用: {original_df.iloc[0:time_steps]['date'].tolist()}")
print(f"预测: {original_df.iloc[time_steps]['date']}")
print(f"\n第一个样本的特征值 (归一化前):")
print(original_df.iloc[0:time_steps][feature_names].values)
print(f"\n对应的目标值 (归一化前):")
print(original_df.iloc[time_steps]['close'])
这种数据格式可以直接输入到LSTM模型中:
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense
model = Sequential([
LSTM(50, return_sequences=True, input_shape=(time_steps, len(features))),
LSTM(50),
Dense(1)
])
model.compile(optimizer='adam', loss='mse')
model.fit(X_train, y_train, epochs=10, batch_size=32)