数据集链接
数据链接: 氣候數據
数据集简介
该数据集于想要训练印度气候天气预报模型的开发人员。该数据集提供了印度德里市2013年1月1日至2017年4月24日的数据。这里的4个参数是 平均温度、湿度、风速、平均气压。
工具
使用pytorch作爲工具,構建简单CNN+LSTM的模型对该天气数据集的平均温度时间序列进行预测。
数据分析流程
数据读取-
用pands读取数据,绘制时序图
白噪声检验
对平均温度进行白噪声检验,由以下随机性检验的数据可得,数据具有明显的自相关性,可以进行时序预测
自相关系数
描述性统计
模型训练
数据归一化
1 2 3 4 5
| from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
meantemp = scaler.fit_transform(meantemp.reshape(-1,1))
|
数值范围统一化:
- 将所有数据映射到[0,1]区间
- 有利于消除量纲影响
- 使模型更容易收敛
提高模型训练效果:
- 避免因数值差异过大导致的梯度爆炸或消失
- 加快模型收敛速度
- 提高模型训练的稳定性
创建时间序列滑动窗口数据
1 2 3 4 5 6 7 8 9
| def split_data(data,time_step=12): dataX=[] datay=[] for i in range(len(data)-time_step): dataX.append(data[i:i+time_step]) datay.append(data[i+time_step]) dataX=np.array(dataX).reshape(len(dataX),time_step,-1) datay=np.array(datay) return dataX,datay
|
参数data: 输入的时间序列数据
参数time_step=12: 时间窗口大小,默认使用12个时间步
表示用前12天的数据来预测第13天的数据
这种数据处理方式的优点:
适合时间序列预测
保留了时序依赖关系
符合LSTM等循环神经网络的输入要求
1 2 3 4 5 6 7 8
| 原始数据: [T1, T2, T3, T4, T5, T6, T7, ...]
转换后: 输入X 输出y [T1,T2,T3] -> T4 [T2,T3,T4] -> T5 [T3,T4,T5] -> T6 [T4,T5,T6] -> T7
|
划分训练集和测试集的函数
参数说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| def train_test_split(dataX,datay,shuffle=True,percentage=0.8): """ 将训练数据X和标签y以numpy.array数组的形式传入 划分的比例定为训练集:测试集=8:2 """ if shuffle: random_num=[index for index in range(len(dataX))] np.random.shuffle(random_num) dataX=dataX[random_num] datay=datay[random_num] split_num=int(len(dataX)*percentage) train_X=dataX[:split_num] train_y=datay[:split_num] test_X=dataX[split_num:] test_y=datay[split_num:] return train_X,train_y,test_X,test_y
|
将数据以8比2进行拆分,并且随机打乱索引顺序 ,
构建CNN+LSTM神经网络
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class CNN_LSTM(nn.Module): def __init__(self, conv_input,input_size, hidden_size, num_layers, output_size): super(CNN_LSTM,self).__init__() self.hidden_size = hidden_size self.num_layers = num_layers self.conv=nn.Conv1d(conv_input,conv_input,1) self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True) self.fc = nn.Linear(hidden_size, output_size) def forward(self, x): x=self.conv(x) h0 = torch.zeros(self.num_layers,x.size(0), self.hidden_size) c0 = torch.zeros(self.num_layers,x.size(0), self.hidden_size) out, _ = self.lstm(x, (h0, c0)) out = self.fc(out[:, -1, :]) return out
|
- CNN层用于特征提取
- LSTM层处理时序关系
- 全连接层做最终预测
- 前向传播过程:
输入 x -> CNN -> LSTM -> 取最后时间步 -> 全连接层 -> 输出
- 各层功能:
- CNN层:
- 使用1x1卷积
- 提取局部特征
- 保持输入输出通道数相同
- LSTM层:
- batch_first=True表示输入形状为(batch, seq, feature)
- 处理时序依赖关系
- 多层LSTM叠加
- 全连接层:
- 将LSTM输出映射到目标维度
- 只使用最后一个时间步的输出
- 模型特点:
- 结合了CNN和LSTM的优势
- CNN提取空间特征
- LSTM捕捉时序关系
- 适合时间序列预测任务
输入参数,进行训练
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| test_X1=torch.Tensor(test_X) test_y1=torch.Tensor(test_y)
input_size = 1 conv_input=12 hidden_size = 64 num_layers = 5 output_size = 1
model =CNN_LSTM(conv_input,input_size, hidden_size, num_layers, output_size)
num_epochs=500 batch_size=64
optimizer=optim.Adam(model.parameters(),lr=0.0001,betas=(0.5,0.999))
criterion=nn.MSELoss()
train_losses=[] test_losses=[]
|
数据反归一化+计算mse误差
1 2 3 4 5 6 7 8
| train_X1=torch.Tensor(X_train) train_pred=model(train_X1).detach().numpy() test_pred=model(test_X1).detach().numpy() pred_y=np.concatenate((train_pred,test_pred)) pred_y=scaler.inverse_transform(pred_y).T[0] true_y=np.concatenate((y_train,test_y)) true_y=scaler.inverse_transform(true_y).T[0] print(f"mse(pred_y,true_y):{mse(pred_y,true_y)}")
|
1 2 3 4 5 6
| 训练数据 -> 预测 -> 反归一化 测试数据 -> 预测 -> 反归一化 ↓ 合并结果 ↓ 计算误差
|
1
| mse(pred_y,true_y):5.5372205189883985
|
获取完整的预测结果
将结果转换回原始尺度
评估模型性能
对于天气温度预测:
- MSE < 4: 非常好
- 4 ≤ MSE < 6: 良好(当前模型处于这个范围)
- 6 ≤ MSE < 9: 一般
- MSE ≥ 9: 需要改进
额外测试集测试
挑选了后面未参与模型训练的时间步来检验泛化效果,拟合后如下,蓝色为预测值,橙色为真实值。可观察到趋势基本一致。