多变量时间序列预测:测试集归一化报错求助
问题分析与解决方案
错误原因
你遇到的ValueError核心是训练集和测试集的特征数量不匹配:
- 合并后的训练集包含28个监测站特征(来自train.csv)+10个气象特征(来自weather.csv),共38个数值特征(排除date列),因此
scaler.fit()是基于38个特征计算的归一化参数。 - 但合并后的测试集只有10个气象特征(因为test.csv本身只有date列,没有任何监测站数据),用同一个scaler转换时,特征数从38变为10,自然触发不匹配报错。
解决方案
要解决这个问题,需要调整数据预处理和预测逻辑——测试阶段没有历史监测站数据,需要用训练集的末尾序列初始化预测,再滚动生成后续的监测站数据。以下是修正后的完整代码:
import pandas as pd import numpy as np from sklearn.preprocessing import MinMaxScaler from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense # 加载数据集 train_df = pd.read_csv("train.csv") weather_df = pd.read_csv("weather.csv") test_df = pd.read_csv("test.csv") # 合并数据集 merged_df = pd.merge(train_df, weather_df, on="date", how="inner") merged_test_df = pd.merge(test_df, weather_df, on="date", how="inner") # 整理训练数据(按日期排序) train_data = merged_df.sort_values("date") test_dates = merged_test_df["date"].values test_weather = merged_test_df.drop("date", axis=1).values # 归一化所有特征(28个监测站 + 10个气象 = 38个特征) scaler = MinMaxScaler(feature_range=(0, 1)) scaled_train = scaler.fit_transform(train_data.drop("date", axis=1)) # 定义窗口大小 window_size = 30 # 构建训练序列:输入是30天的完整数据,目标是下一天的监测站数据 train_X, train_y = [], [] for i in range(window_size, len(scaled_train)): train_X.append(scaled_train[i-window_size:i]) # 形状: (30, 38) train_y.append(scaled_train[i, :28]) # 目标是前28列(监测站数据) train_X = np.array(train_X) train_y = np.array(train_y) # 搭建LSTM模型 model = Sequential() model.add(LSTM(50, return_sequences=True, input_shape=(train_X.shape[1], train_X.shape[2]))) model.add(LSTM(50)) model.add(Dense(28)) # 输出28个监测站特征 model.compile(loss='mean_squared_error', optimizer='adam') # 训练模型 model.fit(train_X, train_y, epochs=100, batch_size=32, verbose=1) # --- 测试集预测逻辑 --- # 用训练集的最后30天数据初始化预测序列 current_sequence = scaled_train[-window_size:] predictions = [] for _ in range(len(test_weather)): # 调整序列形状适配模型输入 input_seq = current_sequence.reshape(1, window_size, 38) # 预测当天的监测站数据 pred_station = model.predict(input_seq, verbose=0) # 对当天的气象数据做归一化(构造dummy数组匹配scaler的38特征要求) dummy_station = np.zeros((1,28)) scaled_weather = scaler.transform(np.hstack([dummy_station, test_weather[_].reshape(1,10)]))[:, 28:] # 拼接预测的监测站数据和归一化后的气象数据,形成下一个序列步 next_step = np.hstack([pred_station, scaled_weather]) # 保存预测结果 predictions.append(pred_station[0]) # 更新序列:移除最早的一步,加入新生成的步 current_sequence = np.vstack([current_sequence[1:], next_step]) # 反归一化预测结果,得到真实数值 dummy_weather = np.zeros((len(predictions), 10)) pred_full = np.hstack([predictions, dummy_weather]) pred_actual = scaler.inverse_transform(pred_full)[:, :28] # 保存预测结果到CSV pred_df = pd.DataFrame(pred_actual, columns=train_df.columns[1:]) pred_df.insert(0, "date", test_dates) pred_df.to_csv("predictions.csv", index=False)
关键调整点
- 明确目标变量:训练时只预测28个监测站特征,模型输出层改为
Dense(28),聚焦核心预测目标。 - 滚动预测逻辑:测试阶段用训练集的最后30天数据初始化序列,每预测出一天的监测站数据后,和当天的气象数据拼接,作为下一次预测的输入序列,解决无历史监测数据的问题。
- 归一化适配:对测试集的气象数据单独做归一化时,通过构造包含dummy监测站数据的数组,匹配scaler的38个特征输入要求,确保归一化逻辑一致。
内容的提问来源于stack exchange,提问作者Moe_blg
相关产品推荐
相关产品推荐

