无法绘制LSTM模型预测结果,报IndexError错误如何解决?
解决LSTM股票价格预测代码中的IndexError问题
错误原因
触发IndexError的核心问题是:代码中将data转换为了numpy数组,而numpy数组不支持用字符串列名(如valid['Predictions'])来添加新列——numpy数组仅接受整数、切片、布尔数组等类型的索引,这和错误提示完全对应。
另外代码还存在两个隐性问题:
- 预测值
predictions的长度与验证集valid的长度不匹配(预测值是从验证集第60天开始生成的,比验证集短60个数据点) - RMSE计算时,
y_test仍处于归一化尺度,与逆变换后的predictions尺度不一致,导致误差计算无效
修改步骤
- 保留DataFrame格式:不要过早将
data转换为numpy数组,保留pandas DataFrame结构,方便后续添加列和绘图 - 对齐预测值与验证集长度:由于预测值需要前60天数据生成,给验证集的前60天填充
NaN,再拼接预测值,保证长度匹配 - 修正RMSE计算逻辑:先将归一化后的
y_test逆变换回原始尺度,再和predictions计算误差
修正后的完整代码
import numpy as np import pandas as pd import matplotlib.pyplot as plt import tensorflow as tf from sklearn.preprocessing import MinMaxScaler from datetime import datetime, timedelta import yfinance as yf # 下载AAPL股票数据 symbol = 'AAPL' start_date = datetime.now() - timedelta(days=365 * 2) end_date = datetime.now() df = yf.download(symbol, start=start_date, end=end_date) # 保留DataFrame格式,不转numpy数组 data = df.filter(['Adj Close']) # 归一化数据(用values获取numpy数组进行处理) scaler = MinMaxScaler(feature_range=(0, 1)) scaled_data = scaler.fit_transform(data.values) # 划分训练集和测试集 training_data_len = int(len(data) * 0.8) train_data = scaled_data[:training_data_len, :] test_data = scaled_data[training_data_len:, :] # 准备训练数据 x_train = [] y_train = [] for i in range(60, len(train_data)): x_train.append(train_data[i-60:i, 0]) y_train.append(train_data[i, 0]) x_train, y_train = np.array(x_train), np.array(y_train) # 调整LSTM输入形状 x_train = np.reshape(x_train, (x_train.shape[0], x_train.shape[1], 1)) # 构建LSTM模型 model = tf.keras.models.Sequential() model.add(tf.keras.layers.LSTM(50, return_sequences=True, input_shape=(x_train.shape[1], 1))) model.add(tf.keras.layers.LSTM(50, return_sequences=False)) model.add(tf.keras.layers.Dense(25)) model.add(tf.keras.layers.Dense(1)) # 编译并训练模型 model.compile(optimizer='adam', loss='mean_squared_error') model.fit(x_train, y_train, batch_size=1, epochs=1) # 准备测试数据 x_test = [] y_test = scaled_data[training_data_len + 60:, :] for i in range(60, len(test_data)): x_test.append(test_data[i-60:i, 0]) x_test = np.array(x_test) x_test = np.reshape(x_test, (x_test.shape[0], x_test.shape[1], 1)) # 获取预测值并逆变换回原始尺度 predictions = model.predict(x_test) predictions = scaler.inverse_transform(predictions) # 修正RMSE计算:先将y_test逆变换 y_test_unscaled = scaler.inverse_transform(y_test) rmse = np.sqrt(np.mean((predictions - y_test_unscaled)**2)) print(f"RMSE: {rmse}") # 绘图部分:用DataFrame处理,对齐长度 train = data[:training_data_len] valid = data[training_data_len:].copy() # 前60天无预测值,填充NaN,再拼接预测值 valid['Predictions'] = np.concatenate([np.full(60, np.nan), predictions]) plt.figure(figsize=(16,8)) plt.title('LSTM股票价格预测模型') plt.xlabel('日期') plt.ylabel('调整后收盘价(美元)') plt.plot(train['Adj Close']) plt.plot(valid[['Adj Close', 'Predictions']]) plt.legend(['训练集', '验证集', '预测值'], loc='lower right') plt.show() # 预测未来1天价格 last_60_days = data[-60:].values last_60_days_scaled = scaler.transform(last_60_days) X_test = [] X_test.append(last_60_days_scaled) X_test = np.array(X_test) X_test = np.reshape(X_test, (X_test.shape[0], X_test.shape[1], 1)) predicted_price = model.predict(X_test) predicted_price = scaler.inverse_transform(predicted_price) print(f"次日预测价格: ${predicted_price[0][0]:.2f}")
关键修改点说明
- 将
data = df.filter(['Adj Close']).values改为data = df.filter(['Adj Close']),保留DataFrame结构 - 给
valid添加Predictions列时,用np.concatenate填充前60天的NaN,保证和验证集长度一致 - RMSE计算前先对
y_test做逆变换,确保和predictions尺度统一 - 修复了最后打印语句的引号缺失问题
内容的提问来源于stack exchange,提问作者junkone
相关产品推荐
相关产品推荐

