
简介本资源是一份基于LSTM神经网络的未来气温预测实践项目面向机器学习初学者与时间序列建模学习者聚焦于用深度学习方法解决气象数据短期趋势预测问题。压缩包共3个文件2个Python脚本1个CSV数据集总大小仅9KB轻量易上手其中主训练脚本new.py实现LSTM模型构建与5折交叉验证训练流程另一脚本56029.py含数据预处理与评估逻辑CSV文件为实测气温时序数据。已有1432人学习下载说明其在入门级时序预测实践中具备较强参考价值。读者可直接复现完整预测流程深入理解LSTM在单变量时间序列中的应用细节掌握MSE/MAE评估指标计算、早停机制monitoracc、min_delta0.003%、patience动态设置等关键调参策略并获得适用于小规模气象数据建模的轻量化代码模板。1. 为什么用 LSTM 预测气温不是“玄学”而是气象工程师日常压箱底的时序建模手段你手头有一份连续 5 年、每小时记录的本地气象站温度数据想提前 72 小时预估未来三天的逐小时气温——这不是天气预报 App 的后台逻辑而是电力调度、农业灌溉、建筑 HVAC 系统优化的真实输入需求。LSTM长短期记忆网络在这里不是炫技的黑匣子而是目前工业界处理非平稳、带周期性、存在长程依赖的气温时间序列最成熟、可解释性相对可控的深度学习方案。它比 ARIMA 更能捕捉突变拐点比如冷空气南下导致的断崖式降温比普通 RNN 更稳定地记住“上周同一天的温差规律”这类跨周模式也比 Prophet 更容易嵌入多源特征如湿度、气压、风速、日照时长。本文不讲 LSTM 数学推导只聚焦一个目标用纯 Python PyTorch 在本地跑通一个可调参、可验证、能部署的气温预测 pipeline。适合刚学完 PyTorch 基础、手里有 CSV 气温数据、想立刻看到预测曲线的工程师或研究生。我们从原始数据清洗开始到模型训练、滚动预测、误差分析全程代码可复制粘贴所有参数都标注了物理含义和调优方向。2. 数据准备与特征工程气温不是数字是带时空语义的信号气温数据绝不能直接喂给 LSTM 当作一串数字。原始 CSV 中的“温度”列背后藏着三重结构日周期昼夜、年周期四季、突发扰动锋面过境。直接归一化后训练模型大概率学不会“凌晨 4 点必是低温谷值”这种强先验。必须把时间戳拆解为可学习的特征向量。2.1 时间特征编码用正弦/余弦函数显式注入周期性LSTM 本身不理解“23:00 和 00:00 相邻”但 sin/cos 可以把时间映射到单位圆上让模型天然感知距离。我们对小时、日、月分别做周期编码import numpy as np import pandas as pd def time_features(df, time_coldatetime): df df.copy() df[time_col] pd.to_datetime(df[time_col]) # 小时周期24 小时制 → sin/cos 编码 df[hour_sin] np.sin(2 * np.pi * df[time_col].dt.hour / 24) df[hour_cos] np.cos(2 * np.pi * df[time_col].dt.hour / 24) # 日周期一年 365 天 → sin/cos 编码忽略闰年 day_of_year df[time_col].dt.dayofyear df[day_sin] np.sin(2 * np.pi * day_of_year / 365) df[day_cos] np.cos(2 * np.pi * day_of_year / 365) # 月周期12 个月 → sin/cos 编码更粗粒度辅助年周期 df[month_sin] np.sin(2 * np.pi * df[time_col].dt.month / 12) df[month_cos] np.cos(2 * np.pi * df[time_col].dt.month / 12) return df # 示例假设你的数据 CSV 包含 datetime 和 temperature 列 df pd.read_csv(weather_data.csv) df time_features(df, datetime) print(新增时间特征列, [c for c in df.columns if sin in c or cos in c])逻辑说明sin(2π·t/T)和cos(2π·t/T)构成一组正交基能无损表示周期为 T 的信号。这里 t 是小时数0–23、年中第几天1–365、月份1–12T 分别为 24、365、12。模型通过线性组合这两个分量就能重建任意相位的周期模式。参数说明24/365/12是硬编码的周期长度若数据跨多年且需考虑闰年可改用df[time_col].dt.daysinyear动态获取若数据采样频率不是小时级如 15 分钟则需按实际间隔重算T例如 15 分钟数据T 24*4 96。2.2 多变量特征构建气温从来不是孤立存在的单靠历史温度预测未来温度效果必然受限。真实场景中气温变化受气压梯度、湿度饱和度、风速平流等共同驱动。即使你只有温度数据也要构造滞后特征lag features来模拟物理惯性def build_lag_features(df, target_coltemperature, lags[1, 2, 3, 24, 48, 168]): 构造滞后特征1h, 2h, 3h, 24h(1天), 48h(2天), 168h(7天) 这些 lag 对应大气热惯性、锋面移动速度等物理过程 for lag in lags: df[f{target_col}_lag_{lag}] df[target_col].shift(lag) return df # 添加滞后温度特征 df build_lag_features(df, temperature, lags[1, 2, 3, 24, 48, 168]) # 若你有其他气象变量如 humidity, pressure直接加入即可 # df df[[temperature, humidity, pressure, hour_sin, ...]] # 所有输入特征列逻辑说明shift(24)表示取 24 小时前的温度值这相当于告诉模型“昨天同一时刻的温度是当前状态的重要参考”。168 小时7 天滞后则捕获中尺度天气系统如副高西伸的影响。这些 lag 不是随意选的而是对应典型天气过程的时间尺度。参数说明lags[1,2,3]捕捉短时惯性24捕捉日循环168捕捉周尺度天气型。若你的数据是分钟级需按比例缩放如 15 分钟数据24h96 个点168h672 个点。2.3 归一化与滑动窗口切片LSTM 输入必须是三维张量LSTM 要求输入形状为(batch_size, seq_len, feature_dim)。我们需要将一维时间序列切片为固定长度的窗口并对每个特征独立归一化避免温度数值大主导训练from sklearn.preprocessing import StandardScaler def create_sequences(df, target_coltemperature, seq_len96, pred_len24, feature_colsNone): 构建滑动窗口序列 seq_len: 输入序列长度如用过去 96 小时预测未来 24 小时 pred_len: 预测步长输出长度 feature_cols: 用于输入的特征列名列表若为 None 则使用除 target_col 外的所有列 if feature_cols is None: feature_cols [c for c in df.columns if c ! target_col] # 仅对输入特征归一化target_col 单独归一化便于反变换 scaler_X StandardScaler() scaler_y StandardScaler() X_scaled scaler_X.fit_transform(df[feature_cols].values) y_scaled scaler_y.fit_transform(df[[target_col]].values) X, y [], [] for i in range(len(X_scaled) - seq_len - pred_len 1): X.append(X_scaled[i:(i seq_len)]) y.append(y_scaled[i seq_len:i seq_len pred_len]) return np.array(X), np.array(y), scaler_X, scaler_y # 构建训练数据用过去 96 小时4 天预测未来 24 小时1 天 X, y, scaler_X, scaler_y create_sequences( df, target_coltemperature, seq_len96, pred_len24, feature_cols[temperature, hour_sin, hour_cos, day_sin, day_cos, temperature_lag_1, temperature_lag_24, temperature_lag_168] ) print(f输入 X shape: {X.shape} - (样本数, 时间步, 特征数)) print(f输出 y shape: {y.shape} - (样本数, 预测步长))逻辑说明seq_len96意味着模型每次接收 96 个连续时间点的特征向量每个向量含 8 个维度输出未来 24 个时间点的温度预测。滑动窗口步长默认为 1即每个新样本偏移 1 小时。参数说明seq_len过小48无法捕获日周期过大192易引入无关噪声且增加显存压力pred_len24是常见业务需求1 天滚动预报若需 72 小时则设为 72但需同步调整y的切片逻辑。3. LSTM 模型构建与训练PyTorch 实现细节决定收敛速度用 PyTorch 从零写 LSTM 不是为了炫技而是为了完全掌控 dropout 位置、层间连接、损失函数权重——这些细节在气温预测中直接影响模型鲁棒性。我们采用双层 LSTM 全连接头结构关键在于 dropout 的施加位置和 teacher forcing 的开关逻辑。3.1 定义可配置的 LSTM 模型类import torch import torch.nn as nn class TemperatureLSTM(nn.Module): def __init__(self, input_size, hidden_size128, num_layers2, output_size24, dropout0.2, bidirectionalFalse): super().__init__() self.hidden_size hidden_size self.num_layers num_layers self.bidirectional bidirectional self.dropout dropout # LSTM 层注意 dropout 仅作用于层间不作用于最后一层输出 self.lstm nn.LSTM( input_sizeinput_size, hidden_sizehidden_size, num_layersnum_layers, batch_firstTrue, dropoutdropout if num_layers 1 else 0, # 多层才启用 dropout bidirectionalbidirectional ) # 输出层双向 LSTM 的 hidden_size 需翻倍 lstm_output_size hidden_size * (2 if bidirectional else 1) self.fc nn.Sequential( nn.Linear(lstm_output_size, 64), nn.ReLU(), nn.Dropout(dropout), nn.Linear(64, output_size) ) def forward(self, x): # x shape: (batch, seq_len, input_size) lstm_out, _ self.lstm(x) # lstm_out shape: (batch, seq_len, hidden_size * num_directions) # 取最后一个时间步的输出seq_len 维度上取 [-1] last_output lstm_out[:, -1, :] # shape: (batch, hidden_size * num_directions) # 全连接层预测未来 output_size 个点 out self.fc(last_output) # shape: (batch, output_size) return out # 初始化模型 model TemperatureLSTM( input_sizeX.shape[2], # 特征数如 8 hidden_size128, # 隐藏层神经元数128 是平衡精度与速度的起点 num_layers2, # 2 层 LSTM 已足够捕获多尺度依赖 output_size24, # 预测未来 24 小时 dropout0.2, # 防止过拟合气温数据易受噪声干扰 bidirectionalFalse # 单向更符合因果逻辑过去影响未来 ) print(model)逻辑说明lstm_out[:, -1, :]取最后一个时间步的隐藏状态这是标准的 sequence-to-vector 编码方式。若需 sequence-to-sequence如每步预测一个值需改用lstm_out全部输出并接nn.Linear但气温预测通常只需最终状态因长期依赖已压缩进隐藏态。参数说明hidden_size128是经验值显存允许时可试 256num_layers2比 1 层更能建模复杂动态但超过 3 层易梯度消失dropout0.2在气温数据上效果稳定过高0.3会导致训练不稳定。3.2 训练循环带早停、学习率衰减和验证集监控import torch.optim as optim from torch.utils.data import TensorDataset, DataLoader # 数据转为 Tensor X_tensor torch.tensor(X, dtypetorch.float32) y_tensor torch.tensor(y, dtypetorch.float32) # 划分训练/验证集按时间顺序不可随机打乱 train_ratio 0.8 split_idx int(len(X_tensor) * train_ratio) X_train, X_val X_tensor[:split_idx], X_tensor[split_idx:] y_train, y_val y_tensor[:split_idx], y_tensor[split_idx:] train_dataset TensorDataset(X_train, y_train) val_dataset TensorDataset(X_val, y_val) train_loader DataLoader(train_dataset, batch_size32, shuffleTrue) # 训练可 shuffle val_loader DataLoader(val_dataset, batch_size32, shuffleFalse) # 验证必须按序 # 损失函数MAE 对异常值更鲁棒气温突变常见 criterion nn.L1Loss() # 即 MAE optimizer optim.Adam(model.parameters(), lr0.001) scheduler optim.lr_scheduler.ReduceLROnPlateau(optimizer, modemin, factor0.5, patience5) # 早停参数 best_val_loss float(inf) patience_counter 0 patience_limit 15 for epoch in range(100): model.train() train_loss 0.0 for batch_x, batch_y in train_loader: optimizer.zero_grad() outputs model(batch_x) loss criterion(outputs, batch_y) loss.backward() torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm1.0) # 梯度裁剪防爆炸 optimizer.step() train_loss loss.item() # 验证 model.eval() val_loss 0.0 with torch.no_grad(): for batch_x, batch_y in val_loader: outputs model(batch_x) loss criterion(outputs, batch_y) val_loss loss.item() avg_train_loss train_loss / len(train_loader) avg_val_loss val_loss / len(val_loader) scheduler.step(avg_val_loss) # 早停逻辑 if avg_val_loss best_val_loss: best_val_loss avg_val_loss patience_counter 0 torch.save(model.state_dict(), best_lstm_model.pth) # 保存最佳模型 else: patience_counter 1 if patience_counter patience_limit: print(fEarly stopping at epoch {epoch1}) break if (epoch 1) % 10 0: print(fEpoch {epoch1}, Train Loss: {avg_train_loss:.4f}, Val Loss: {avg_val_loss:.4f})逻辑说明torch.nn.utils.clip_grad_norm_是气温预测的后悔药——原始温度数据常含传感器跳变如-5℃突变到 30℃导致梯度爆炸此行代码能保住训练不崩。ReduceLROnPlateau在验证损失 5 轮不降时自动减半学习率比固定学习率更适应气温数据的阶段性平稳/突变特性。参数说明batch_size32是 GPU 显存与收敛速度的平衡点lr0.001是 Adam 默认值若训练初期 loss 下降慢可提至 0.002patience_limit15防止过早停止因气温数据验证损失常有小幅震荡。4. 预测与评估如何判断模型真能用而不是在拟合噪声训练完模型只是开始。真正决定能否上线的是滚动预测能力rolling forecast和误差分解error decomposition。气温预测的 RMSE 数值本身意义有限必须看误差在什么时间尺度、什么天气条件下集中爆发。4.1 滚动预测模拟真实业务场景的递推式预测训练时是“给 96 小时预测 24 小时”但业务中需要“每小时更新一次预测覆盖未来 24 小时”。这就要求模型具备滚动推理能力def rolling_forecast(model, scaler_X, scaler_y, initial_seq, pred_steps24, devicecpu): 滚动预测用最新观测不断更新输入序列 initial_seq: 形状为 (1, seq_len, feature_dim) 的初始输入序列 pred_steps: 总共预测多少步如 24 小时 model.eval() model.to(device) initial_seq initial_seq.to(device) predictions [] current_seq initial_seq.clone() # 当前输入序列随预测逐步更新 for step in range(pred_steps): # 预测下一步 with torch.no_grad(): pred model(current_seq) # pred shape: (1, 1) 或 (1, pred_steps) —— 此处为单步输出 # 反归一化 pred_unscaled scaler_y.inverse_transform(pred.cpu().numpy()).flatten()[0] predictions.append(pred_unscaled) # 更新输入序列移除最旧时间步添加新预测作为新特征的一部分 # 注意此处仅更新 temperature 特征其他特征sin/cos需按时间推算 # 简化版假设只预测 temperature且其他特征可精确计算如 hour_sin/hour_cos 可推导 new_row current_seq[0, -1, :].clone() # 将预测的 temperature 填入新行对应位置假设 temperature 是第 0 列 new_row[0] torch.tensor(pred[0, 0].item()) # 填入归一化后的预测值 # 其他特征如 hour_sin需根据时间推算此处省略具体实现 # 实际中建议维护一个 feature_generator 函数动态生成 # 滑动窗口丢弃第一个时间步追加新行 current_seq torch.cat([current_seq[:, 1:, :], new_row.unsqueeze(0).unsqueeze(0)], dim1) return np.array(predictions) # 示例用最后一条训练样本作为初始序列 last_train_sample X_tensor[-1:].to(cpu) # (1, 96, 8) pred_24h rolling_forecast(model, scaler_X, scaler_y, last_train_sample, pred_steps24) print(滚动预测的未来 24 小时气温, pred_24h.round(2))逻辑说明滚动预测的核心是状态维持——每次预测后需用新预测值更新输入序列的最末端并丢弃最旧时间步。难点在于非温度特征如hour_sin必须随时间推移动态重算不能简单复制。生产环境建议封装FeatureGenerator类输入当前时间戳输出完整特征向量。参数说明pred_steps24是单次滚动的目标步长若需 72 小时则调用三次每次 24 步或修改模型输出为 72 维devicecpu因滚动预测是单样本CPU 足够GPU 反而有启动开销。4.2 误差分析按天气类型和时间粒度拆解 RMSE单纯报告整体 RMSE 1.5℃ 毫无意义。必须定位误差来源import matplotlib.pyplot as plt def analyze_errors(y_true, y_pred, time_index, weather_labelsNone): y_true/y_pred: 一维数组长度相同 time_index: pd.DatetimeIndex对应每个预测点的时间 weather_labels: 可选外部标注的天气类型如 cold_front, heat_wave errors y_true - y_pred abs_errors np.abs(errors) # 1. 按小时段统计误差验证日周期建模效果 hour_errors pd.DataFrame({error: abs_errors, hour: time_index.hour}) hour_rmse hour_errors.groupby(hour)[error].apply(lambda x: np.sqrt(np.mean(x**2))) # 2. 按季节统计验证年周期建模效果 season_errors pd.DataFrame({ error: abs_errors, season: time_index.month.map({1: Winter, 2: Winter, 3: Spring, 4: Spring, 5: Spring, 6: Summer, 7: Summer, 8: Summer, 9: Autumn, 10: Autumn, 11: Autumn, 12: Winter}) }) season_rmse season_errors.groupby(season)[error].apply(lambda x: np.sqrt(np.mean(x**2))) # 3. 若有天气标签按类型统计 if weather_labels is not None: label_errors pd.DataFrame({error: abs_errors, label: weather_labels}) label_rmse label_errors.groupby(label)[error].apply(lambda x: np.sqrt(np.mean(x**2))) print(按天气类型 RMSE:\n, label_rmse.round(3)) # 可视化 fig, axes plt.subplots(1, 2, figsize(12, 4)) hour_rmse.plot(axaxes[0], markero) axes[0].set_title(RMSE by Hour of Day) axes[0].set_xlabel(Hour) axes[0].set_ylabel(RMSE (°C)) season_rmse.plot(axaxes[1], kindbar) axes[1].set_title(RMSE by Season) axes[1].set_ylabel(RMSE (°C)) plt.tight_layout() plt.show() # 假设你有验证集的真实值和预测值 # y_val_true scaler_y.inverse_transform(y_val.numpy()) # 反归一化 # y_val_pred scaler_y.inverse_transform(model(X_val).detach().numpy()) # analyze_errors(y_val_true.flatten(), y_val_pred.flatten(), val_time_index)逻辑说明如果hour_rmse在凌晨 4–6 点显著升高说明模型未充分学习辐射冷却过程如果season_rmse在夏季最高可能是训练数据中高温样本不足或湿度特征缺失。这些洞察直接指导下一步迭代加数据、加特征、调结构。参数说明weather_labels需外部提供如用 NCEP 再分析数据匹配锋面信息若无则跳过该部分time_index必须与预测点严格对齐否则小时/季节统计失效。5. 避坑指南气温预测 LSTM 的 4 个血泪经验气温预测看似简单实则处处是坑。以下是我踩过的、文档里几乎不提、但线上部署必遇的问题按现象→原因→解决三步给出可执行方案5.1 现象训练 loss 快速下降但验证 loss 卡在高位不动且预测曲线完全偏离真实值原因时间特征hour_sin/hour_cos未随预测时间动态更新。模型在训练时看到的是“完美对齐”的 sin/cos但滚动预测时若仍用训练期的固定值会导致相位错乱。例如训练时hour_sin对应 14:00 是 0.9但预测 15:00 时若仍填 0.9而非计算sin(2π×15/24)0.97模型就失去了时间锚点。解决在rolling_forecast函数中必须为每个预测步重新计算时间特征。不要缓存不要插值直接用pd.Timestamp推算# 在滚动预测循环内每次生成 new_row 前 next_time current_time pd.Timedelta(hours1) # 假设 current_time 是当前时间戳 new_hour_sin np.sin(2 * np.pi * next_time.hour / 24) new_hour_cos np.cos(2 * np.pi * next_time.hour / 24) # ... 其他时间特征同理5.2 现象模型对寒潮/热浪等极端事件预测严重滞后升温/降温斜率远小于实际原因LSTM 的梯度流难以捕捉突变点且 MAE 损失函数对大误差惩罚不足模型倾向于“保守预测”平滑输出。解决损失函数升级改用nn.MSELoss()或混合损失0.7*MAE 0.3*MSEMSE 强制模型关注大误差标签平滑对真实温度标签做轻微高斯模糊scipy.ndimage.gaussian_filter1d(y_true, sigma0.5)降低突变尖锐度让模型先学趋势再学细节添加突变检测特征在输入特征中加入np.abs(np.diff(y_true))的滑动标准差显式提示模型“此处可能突变”。5.3 现象不同气象站数据训练的模型迁移到新站点时性能断崖式下跌原因模型过拟合了原站点的绝对温度范围和噪声模式未学习通用气象物理规律。解决输入标准化升级不用StandardScaler改用RobustScaler基于中位数和四分位距对离群值不敏感特征工程泛化放弃绝对温度改用temperature - rolling_mean(temperature, window24)距 24 小时均值的偏差使模型学习“异常程度”而非“绝对值”多任务预训练用全国 100 个站点数据联合训练主任务预测温度辅助任务预测“是否降水”二分类迫使模型提取共享气象表征。5.4 现象模型在测试集上 RMSE 优秀但部署后首周预测准确率骤降原因数据漂移data drift——训练数据来自 2019–2023 年而部署时进入 2024 年气候态已变化如城市热岛效应加剧模型未感知分布偏移。解决在线监控部署后每 24 小时计算新预测的abs_error标准差若连续 3 天 历史均值 2σ触发告警轻量重训机制保留最近 30 天的预测-真实值对每周用X_new np.vstack([X[-1000:], new_X])微调最后两层lr0.00015 个 epoch 即可模型融合兜底LSTM 预测为主但当监控指标超标时自动切换至物理模型如简化的能量平衡方程输出保证服务不中断。6. 进阶技巧用 LSTM 预测结果反哺物理模型形成闭环校准LSTM 预测的价值不仅在于输出数字更在于其残差prediction error是物理模型偏差的绝佳指示器。我在线上系统中实践了一套“LSTM-物理模型协同校准”流程将纯数据驱动的预测转化为可解释、可追溯的决策支持。6.1 残差驱动的物理参数在线校准假设你有一个简化的城市冠层模型UCM其关键参数albedo地表反照率和anthropogenic_heat人为热排放在传统方法中需人工标定。现在我们将 LSTM 残差作为反馈信号# 假设 UCM 模型封装为 ucm_simulate(time, albedo, heat) def calibrate_ucm_with_lstm_residual(lstm_pred, true_temp, time_window, ucm_params): 利用 LSTM 残差优化 UCM 参数 lstm_pred: LSTM 对 time_window 的预测数组 true_temp: 对应的真实温度数组 ucm_params: 字典含 albedo, anthropogenic_heat residuals true_temp - lstm_pred # LSTM 残差代表“数据未捕获的物理过程” # 残差正相关于人为热排放不足 → 提高 anthropogenic_heat if np.corrcoef(residuals, true_temp)[0,1] 0.6: # 残差与温度正相关 ucm_params[anthropogenic_heat] * 1.05 # 微调 5% # 残差在晴天正、阴天负 → 调整 albedo晴天反射不足 sunny_mask (cloud_cover[time_window] 0.2) if np.mean(residuals[sunny_mask]) 1.0: # 晴天残差持续为正 ucm_params[albedo] min(0.3, ucm_params[albedo] 0.02) # 提高反照率 return ucm_params # 在每日数据入库后执行 ucm_params calibrate_ucm_with_lstm_residual( lstm_daily_pred, true_daily_temp, time_windowslice(-24, None), ucm_params{albedo: 0.22, anthropogenic_heat: 25} )逻辑说明LSTM 擅长拟合统计规律但无法表达“太阳辐射→地表吸收→长波辐射”的物理链路。其残差恰恰暴露了物理模型缺失的环节。上述代码将残差符号、相关性、条件分布转化为物理参数的修正方向实现了数据驱动与机理模型的闭环。参数说明correlation threshold0.6是经验值过高则响应迟钝过低则噪声干扰albedo上限0.3是城市沥青路面的物理极限防止参数发散。6.2 预测不确定性量化不只是点估计还要给置信区间业务方真正需要的不是“明天 14:00 28.3℃”而是“28.3℃ ± 1.2℃95% 置信度”。我们用Monte Carlo Dropout在推理时估计不确定性def mc_dropout_predict(model, x, n_samples100, dropout_p0.2): Monte Carlo Dropout训练时开启 dropout推理时也开启多次采样得分布 model.train() # 关键让 dropout 生效 predictions [] for _ in range(n_samples): with torch.no_grad(): pred model(x) predictions.append(pred.cpu().numpy()) predictions np.array(predictions) # shape: (n_samples, batch, pred_len) mean_pred np.mean(predictions, axis0) std_pred np.std(predictions, axis0) return mean_pred, std_pred # 获取不确定性 x_sample X_tensor[0:1] # 取一个样本 mean, std mc_dropout_predict(model, x_sample, n_samples50) upper_bound mean 1.96 * std # 95% 置信区间 lower_bound mean - 1.96 * std print(95% 置信区间:, lower_bound.round(2), to, upper_bound.round(2))逻辑说明MC Dropout 的理论依据是开启 dropout 的模型等价于多个子模型的集成。50 次前向传播得到的预测标准差就是模型自身认知的不确定性。若某小时std 2.0℃说明该时段天气系统混沌性强如锋面过境应提醒用户谨慎使用预测。参数说明n_samples50是精度与速度的平衡dropout_p0.2必须与训练时一致若模型训练时未用 dropout此方法无效需改用Deep Ensemble训练 5 个不同初始化的 LSTM。我坚持在每个新项目启动时先用本方案跑通一个 baseline再逐步叠加物理约束、多源数据融合、在线学习。因为气温预测的本质不是拟合曲线而是在数据噪声中识别物理规律在模型偏差里发现系统缺陷。LSTM 是工具不是答案它的价值永远在你如何用它追问“为什么预测错了”。希望帮到你。本文还有配套的精品资源点击获取