Keras LSTM股价预测报错:无法将数组重塑为指定形状
问题描述
执行代码中X = np.reshape(X, (1, X.shape[0], X.shape[1]))语句时触发ValueError,提示无法将大小为9200的数组重塑为(1,460,10)。
完整代码
import numpy as np import pandas as pd from sklearn.preprocessing import MinMaxScaler from keras.models import Sequential from keras.layers import LSTM, Dense, Dropout import matplotlib.pyplot as plt import finpy_tse as fpy # 定义股票代码和时间区间 stock_symbol = 'وغدیر' start_date = '1400-01-01' end_date = '1402-01-01' # 从德黑兰证券交易所获取股价数据 stock_data = fpy.Get_Price_History(stock_symbol, start_date, end_date) # 打印获取的数据 print("从站点获取的数据:") print(stock_data) data = pd.DataFrame(stock_data) # 重复获取数据(可删除此冗余代码) stock_data = fpy.Get_Price_History(stock_symbol, start_date, end_date) data = pd.DataFrame(stock_data) # 打印列名检查数据结构 print(data.columns) # 特征工程:创建额外特征 if 'Close' in data.columns and 'Volume' in data.columns: data['DailyReturn'] = data['Close'].pct_change() data['VolumeChange'] = data['Volume'].pct_change() # 删除缺失值 data = data.dropna() # 检查删除后数据集是否为空 if data.empty: print("删除缺失值后数据集为空,无法继续。") else: # 选择训练用特征 features = ['DailyReturn', 'VolumeChange'] dataset = data[features].values # 检查特征工程后数据集是否为空 if dataset.shape[0] == 0: print("特征工程后数据集为空,无法继续。") else: # 数据归一化 scaler = MinMaxScaler(feature_range=(0, 1)) dataset_scaled = scaler.fit_transform(dataset) # 创建时间序列数据集 def create_dataset(dataset, time_steps=1): X, y = [], [] for i in range(len(dataset) - time_steps): a = dataset[i:(i + time_steps), :] X.append(a) y.append(dataset[i + time_steps, 0]) # 预测DailyReturn return np.array(X), np.array(y) # 定义时间步长 time_steps = 10 # 生成数据集 X, y = create_dataset(dataset_scaled, time_steps) # 调试打印形状和大小 print("重塑前 - X形状:", X.shape, "X大小:", X.size) # 错误的重塑语句 X = np.reshape(X, (1, X.shape[0], X.shape[1])) # 构建LSTM模型 model = Sequential() model.add(LSTM(units=100, return_sequences=True, input_shape=(X.shape[1], X.shape[2]))) model.add(Dropout(0.2)) model.add(LSTM(units=100, return_sequences=True)) model.add(Dropout(0.2)) model.add(LSTM(units=50, return_sequences=False)) model.add(Dropout(0.2)) model.add(Dense(units=1)) model.compile(optimizer='adam', loss='mean_squared_error') # 训练模型 model.fit(X, y, epochs=10, batch_size=32, validation_split=0.1) # 测试模型 test_data = dataset_scaled[-time_steps:] test_data = np.reshape(test_data, (1, time_steps, len(features))) predicted_price = model.predict(test_data) # 错误的逆变换逻辑 predicted_price = scaler.inverse_transform(np.reshape(predicted_price, (1, time_steps, len(features)))) print("调试形状:") print("test_data形状:", test_data.shape) print("predicted_price形状:", predicted_price.shape) # 重复逆变换 predicted_price = scaler.inverse_transform(np.reshape(predicted_price, (time_steps, len(features)))) # 提取预测结果 predicted_price = predicted_price[0, :, 0] # 可视化结果 plt.plot(data['Close'].values, label='Actual Stock Price') plt.plot(np.arange(len(data['Close']), len(data['Close']) + time_steps), predicted_price, marker='o', color='red', label='Predicted Stock Price') plt.xlabel('Days') plt.ylabel('Stock Price') plt.title(f'Stock Price Prediction for {stock_symbol} using LSTM') plt.legend() plt.show() else: print("数据中不存在'Close'或'Volume'列。") print("请检查股价数据或提供包含这些列的数据集。")
报错信息
Traceback (most recent call last): File "...:/Users/...../PycharmProjects/untitled1/.....py", line 76, in
X = np.reshape(X, (1, X.shape[0], X.shape[1])) File "<array_function internals>", line 180, in reshape File "....:\Users.....\PycharmProjects\untitled1\venv\lib\site-packages\numpy\core\fromnumeric.py", line 298, in reshape
return _wrapfunc(a, 'reshape', newshape, order=order) File "....:\Users....\PycharmProjects\untitled1\venv\lib\site-packages\numpy\core\fromnumeric.py", line 57, in _wrapfunc
return bound(*args, **kwds) ValueError: cannot reshape array of size 9200 into shape (1,460,10)
问题原因
create_dataset函数生成的X已经是LSTM要求的三维格式[样本数, 时间步长, 特征数]。从报错数据计算:460102=9200,说明X的实际形状是(460,10,2)(460个样本,每个样本包含10个时间步的2个特征)。但你试图将其重塑为(1,460,10),总元素数仅为4600,和原数组大小不匹配,导致报错。
解决步骤
- 删除错误的重塑语句:直接删掉
X = np.reshape(X, (1, X.shape[0], X.shape[1])),因为create_dataset已经输出了正确的三维结构。 - 修正预测部分的逆变换逻辑:模型输出的是单个预测值(DailyReturn),而scaler是基于2个特征训练的,需要将预测值补全为对应特征数的数组后再逆变换。
- 调整可视化代码:模型每次仅预测一个时间步的数值,无需生成多个预测点。
修正后的关键代码片段
# 生成时间序列数据集后,无需额外重塑 X, y = create_dataset(dataset_scaled, time_steps) print("X的正确形状:", X.shape) # 输出应为 (样本数, 10, 2) # 构建模型(input_shape参数保持不变,与X的结构匹配) model = Sequential() model.add(LSTM(units=100, return_sequences=True, input_shape=(X.shape[1], X.shape[2]))) model.add(Dropout(0.2)) model.add(LSTM(units=100, return_sequences=True)) model.add(Dropout(0.2)) model.add(LSTM(units=50, return_sequences=False)) model.add(Dropout(0.2)) model.add(Dense(units=1)) model.compile(optimizer='adam', loss='mean_squared_error') # 训练模型 model.fit(X, y, epochs=10, batch_size=32, validation_split=0.1) # 预测部分修正 test_data = dataset_scaled[-time_steps:] test_data = np.reshape(test_data, (1, time_steps, len(features))) predicted_price = model.predict(test_data) # 逆变换:补全特征维度,匹配scaler的输入要求 predicted_full = np.zeros((1, len(features))) predicted_full[0, 0] = predicted_price[0, 0] # 将预测的DailyReturn放入对应列 predicted_price = scaler.inverse_transform(predicted_full)[0, 0] # 可视化修正 plt.plot(data['Close'].values, label='实际股价') plt.plot(len(data['Close']), predicted_price, marker='o', color='red', label='预测股价') plt.xlabel('天数') plt.ylabel('股价') plt.title(f'{stock_symbol} 股价LSTM预测') plt.legend() plt.show()
内容的提问来源于stack exchange,提问作者sobhan soleimani

