十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

天气时序预测实战:从ARIMA到LSTM的完整方案与避坑指南

天气时序预测实战:从ARIMA到LSTM的完整方案与避坑指南 简介基于Transformer架构的北京天气时间序列预测项目面向有一定Python和深度学习基础的开发者解决多变量输入、单变量输出的气象预报问题兼顾模型训练与推理应用两部分。资源包共4个文件约99.77MB包含2个Python脚本、1份Excel气象数据和1个PyTorch模型权重其中模型权重保存了训练中的最优参数脚本分别负责加载模型完成预测、数据预处理与效果评估Excel数据文件则提供日期、温度、湿度、风速等原始气象记录。目前已有1664人学习是深度学习爱好者将注意力机制落地到真实场景的直观参考。读者可直接借助最优权重快速生成预测结果也可沿脚本逐步复盘天气数据清洗、时间特征提取、模型训练及指标验证等关键环节通过调整输入输出配置还能扩展为其他变量的时序预报实验适合用来入门或深入研究Transformer在时间序列领域的应用。 去年接手一个气象数据可视化的项目客户最开始的需求只是把过去十年的温度曲线画出来。真正聊深了之后需求变成了能不能预测未来三天甚至一周的最高最低气温。于是我开始系统性地做时间序列预测天气数据这件事。折腾下来最大的感受是天气预测和股票预测、流量预测这些时序问题有相似之处但又有它非常特殊的一面——周期性极强、噪声极大、极端值无法避免。这篇文章没有空谈原理全部是我在一个真实项目里踩过、试过、改过的方案和代码希望能给准备碰时序预测的人省点弯路。1. 天气数据到底适合哪种时序模型1.1 线性方法为什么不能直接套用网上很多入门教程喜欢拿 ARIMA 讲时间序列预测天气数据因为 ARIMA 对平稳序列表现不错数学上也优雅。但我先说实话温度序列从来不是平稳的。一天之内有昼夜温差一年之内有季节温差再加上寒潮、副热带高压这些气候系统的扰动均值、方差都在变。你可以把温度序列想象成一条带着巨大波浪的河流ARIMA 这种线性工具就像在河面上画直线它抓得住短期一小段趋势却扛不住季节性的周期性摆动。做差分可以消除一部分非平稳但差分的阶数、季节周期长度这些参数在你面对不同城市、不同气候带的站点时调一次就想放弃。初始数据我只拿了某个南方城市近五年逐小时气温ARIMA 调参后的第一版预测在未来 24 小时内的误差还能看一旦往 72 小时以外推预测曲线几乎变成一根横线——因为线性模型本质上只会记住均值。如果你就是想跑个基线ARIMA 可以当参照物但别指望它扛大梁。1.2 Prophet、LSTM、Transformer 的取舍真正在项目里挑模型时我对比了三类方案模型优点缺点适合场景Prophet添加季节项和假期项很快对缺失值容忍度高使用难度低对复杂非线性交互表达有限多变量扩展偏弱快速做一轮基线预测业务汇报用LSTM能捕捉非线性时序依赖适合中等长度历史序列调参成本高数据量不够时容易过拟合训练时间长有两年以上逐小时数据做24~72小时预测Transformer近年时序预测的强手能处理长程依赖和多变量特征实现成本高小数据集上优势不明显容易在推理阶段出诡异结果数据规模大、特征多有多站点联合建模需求我当时没直接上 Transformer原因是项目数据量有限一个站点也就几万行训练集还没有大到能让注意力机制充分发挥。最后的生产方案是双轨制基线输出用 Prophet正式输出用 LSTM。Transformer 留到后面如果接入区域网格数据再升级。真实经验是模型不是越复杂越好而是跟你的数据量、业务精度要求匹配才对。客户要的是未来三天趋势大概准而不是论文里的SOTA数字。2. 从原始气象数据到可训练样本的清洗过程2.1 缺失值与异常站点的处理天气数据不会干干净净躺在数据库里等你。我拿到的 CSV 里最普遍的问题有三个传感器离线导致的整段缺失、自动站维护期间产生的重复记录、还有极端天气下记录到明显超出物理范围的值。比如某站某个小时内气温突跳 30 度这种基本可以判定为采集异常。处理顺序我建议固定成一套管道按时间戳排序后去除完全重复的行对每个站点单独做范围校验比如温度设在 -50℃~60℃ 区间超出直接标空缺失值先不做插补而是先看缺失比例。如果某个站点缺失超过 30%这个站点我不太建议硬留直接剔除对短时间缺失用前后 6 小时滑动均值补千万别用全序列均值补——那会直接吃掉昼夜波动的特征。这里有一个容易犯的错先插补再划分训练集和测试集。标准做法是先划分再插补。否则你在插补时已经偷用了未来窗口的信息后面评估出来的指标全是虚高。2.2 特征拆解让模型“看到”天气的周期性温度不是随机的它强烈依赖一天中的时刻和一年中的哪天。但模型不认识6月15日14点这种格式它们更喜欢连续数字。所以我把时间特征拆成这样hour_sin、hour_cos对一天内小时做正弦/余弦编码dayofyear_sin、dayofyear_cos对一年内天数做正弦/余弦编码is_weekend周末和工作日对城市气温有影响滞后特征temp_lag_1h、temp_lag_24h、temp_lag_168h一周前的同一时刻。为什么不直接用数字 0~23 表示小时因为对模型来说0 点和 23 点在数值上差距很大但物理上它们只隔 1 小时。正弦余弦编码能把循环这个信息真正表达出来。用生活类比来解释小时编码就像钟表盘你关心的是指针角度而不是表盘刻度上的数字差。直接喂 0~23 等于把凌晨和深夜硬生生切成两个互不相邻的孤岛。2.3 训练集与验证集的切分策略时间序列的切分不能用随机打乱。随机打乱等于把未来的信息混进训练集模型会作弊验证结果会好看到不真实。我采用的切分方式是前 36 个月作为训练集接下来 3 个月作为验证集最后 3 个月作为测试集用滚动起点的方式做模型调参时的交叉验证每次训练窗口后移 7 天验证窗口也跟着移。这段逻辑我写成代码后长这样伪代码逻辑def rolling_split(df, train_days36*30, val_days90, step_days7): folds [] start 0 while start train_days val_days len(df): train df[start: start train_days] val df[start train_days: start train_days val_days] folds.append((train, val)) start step_days return folds这样每一折都是严格按时间顺序来的模型永远看不到未来数据。3. 搭建预测模型从零起步的完整代码3.1 基线模型先用线性回归探底不要一上来就堆 LSTM。我先用最简单的线性回归跑了一版目的是确定最笨的方案能到什么水平。这一步非常重要后续所有复杂模型都要跟这个底线比如果 LSTM 连线性回归都打不过说明要么特征没做对要么数据量不够。我用了多步预测策略要预测未来 24 小时就构造一个以当前时刻为基准、特征里包含过去 168 小时滑动统计均值、最大值、最小值的回归模型目标值是未来 1~24 小时的温度序列拆成 24 个输出头。from sklearn.linear_model import LinearRegression from sklearn.multioutput import MultiOutputRegressor X feature_engineering(df) # 自定义函数生成上面提到的特征 y df[[temp_t1, temp_t2, ..., temp_t24]].values model MultiOutputRegressor(LinearRegression()) model.fit(X_train, y_train)线性回归在这个任务上的测试集 MAE平均绝对误差大概是 2.3℃。这个结果其实已经能支撑不少日常业务场景比如明天最高温大致在什么范围。但它的问题也很明显——它对突然冷空气过境几乎毫无反应因为它只学到了历史时刻与未来时刻的平均关系没有学到天气系统的动态演化。3.2 轻量级方案以 Prophet 快速出结果如果只是做业务演示或者快速验证Prophet 的投入产出比很高。它的接口很简洁from prophet import Prophet prophet_df df.rename(columns{datetime: ds, temperature: y}) model Prophet( yearly_seasonalityTrue, daily_seasonalityTrue, weekly_seasonalityFalse ) model.add_country_holidays(country_nameCN) model.fit(prophet_df) future model.make_future_dataframe(periods72, freqH) forecast model.predict(future)Prophet 有个对天气时序特别友好的特性它把节假日作为一种额外影响因子。国庆、春节这些大假期间城市热岛效应和出行结构变化会影响温度观测加上节假日参数后春节期间误差确实降了一些。不过 Prophet 对多变量特征比如湿度、气压的支持比较弱。你想加入前 24 小时的平均气压这种特征时得手动加到额外回归变量里处理起来不如神经网络灵活。3.3 LSTM 怎么构造输入序列LSTM 需要的是三维输入(样本数, 时间步长, 特征数)。我设定时间步长为 168也就是用过去 7 天的逐小时数据预测未来 24 小时。构造滑动窗口的核心逻辑def create_sequences(data, input_steps168, output_steps24): X, y [], [] for i in range(len(data) - input_steps - output_steps): X.append(data[i: i input_steps]) y.append(data[i input_steps: i input_steps output_steps, 0]) # 0 是温度列 return np.array(X), np.array(y)模型主体我搭了三层 LSTM 加两层全连接model Sequential([ LSTM(64, return_sequencesTrue, input_shape(168, n_features)), Dropout(0.2), LSTM(64, return_sequencesFalse), Dropout(0.2), Dense(32, activationrelu), Dense(24) ]) model.compile(optimizeradam, lossmae)训练时我用了早停EarlyStopping和模型检查点ModelCheckpoint。早停的 patience 设置为 10 个 epoch意思是连续 10 轮验证集误差不再下降就终止训练防止过拟合。LSTM 在这个数据集上把测试集 MAE 降到了 1.7℃左右比线性回归的 2.3℃ 好不少。这里要说一个很多人栽过的坑LSTM 对输入特征的量纲非常敏感。温度、气压、湿度不在一个数量级直接塞进网络会让梯度爆炸。我用了 scikit-learn 的StandardScaler做标准化并且在训练完成后预测结果要用同一个 scaler 做逆变换才能得到真实的温度值。这个逆变换很容易被遗忘特别是你保存模型之后重新加载时。4. 评估预测效果时容易被忽略的那些坑4.1 指标选择MAE、RMSE 还是 MAPE天气预测领域MAE 是我最常用的指标因为它直观平均差 1.7℃意思就是平均每次预测偏了 1.7℃。RMSE 对极端误差更敏感偶尔一次冷空气漏报RMSE 会被拉高MAE 相对稳定。MAPE 在温度预测里我不建议用因为温度序列会有接近 0℃ 的情况除以一个接近零的实际值MAPE 直接爆炸。看一个具体的验证集输出日期实际最高温(℃)预测最高温(℃)绝对误差(℃)2024-03-0118.219.51.32024-03-0221.020.10.92024-03-0315.412.82.62024-03-0413.715.92.22024-03-0517.517.10.4从单点误差看不出系统性偏差所以我又额外画了误差分布直方图。真实的误差分布基本符合均值为 0 的正态分布但尾巴略厚说明极端天气来了误差会明显增大。4.2 防止数据泄漏天气预测里的“未来信息”数据泄漏是时间序列预测里最隐蔽的坑。典型场景是你想预测未来 24 小时结果特征工程时不小心把未来 24 小时的平均气压也加进去了。训练时模型会发现哦只要知道未来的气压温度就很好猜验证集精度飞起一旦上线后你拿不到未来数据模型立刻变废物。我的检查方法是每加一个特征就把这个特征在真实预测时刻能不能拿到这个问题重新问一遍。滞后特征可以当日累计降雨量如果统计截止时间早于预测时刻可以但任何来自未来窗口的统计量坚决不用。还有一层泄漏更隐蔽标准化用的均值和方差。StandardScaler如果是在全量数据上 fit 的它已经偷看了测试集的信息。正确做法是只对训练集 fit再分别 transform 验证集和测试集。4.3 滚动预测的长期稳定性我在项目里还做了滚动预测实验每次预测未来 24 小时然后真实值每更新 1 小时就重新预测一次。这样连续跑 7 天得到的是一个滚动误差曲线。结果让我很清醒滚动预测的误差并不是平稳的在某些时段会突然恶化比如强对流天气前后误差能到 4~5℃。这也是时间序列预测天气数据和股票预测最大的不同——股票价格在很多假设下是随机游走天气至少在短时间尺度上有很强的持续性今天的温度大概率接近明天。但强对流系统会打破这种持续性模型看到的是历史模式的延续而大气实际已经切换到了另一种状态。5. 实测经验哪些“意外”最常出现在天气时序预测里5.1 极端天气让模型全面失灵有一次模型在寒潮来临前给出了未来 24 小时 20℃ 的预测实际上第二天最高温只有 8℃。这让我意识到所有训练数据里的极端事件都只是少数样本神经网络对少数样本的记忆很弱。寒潮、台风、暴雨这些转折性天气本来时序模型就很难捕捉因为它们本质上是非线性系统里的强扰动。后来我加了一个突变检测的前置模块计算最近 6 小时温度斜率、气压变化率如果指标超过历史 95 分位数就在预测结果后面加一条不确定性标记提醒业务方未来 24 小时内可能有转折性天气。这是工程上的妥协——模型做不了的事用规则来兜底。5.2 站点迁移与观测仪器更换的数据断层这个坑很少有人提前想到。某个城市的气象站从旧站址迁到新站址后周边环境从开阔郊区变成了城区建筑群同一天的观测温度平均偏高 1℃ 左右。整个序列像突然被抬升了一段。模型去学历史规律时会把前期偏低后期偏高理解成一种长期升温趋势导致未来预测持续偏高。处理这个问题的标准做法是分段建模或者做站点均一化。我把站点迁移日期找出来把迁移前的数据作为独立样本迁移后的数据作另一段或者在特征里加一个is_new_site的哑变量。加上后预测误差下降了不少。5.3 多步预测的误差累积做 1 小时预测LSTM 误差能压到 0.8℃但预测第 24 小时时误差往往放大到 2℃ 以上。这是多步预测的通病——误差会随着步长累积。我试过两种策略递归预测把第 1 小时预测值作为输入再去预测第 2 小时误差会滚雪球不推荐直接多步输出一次输出 24 小时每个输出头共享同一个 encoder 特征误差虽有放大小但可控。我最终选了直接多步输出从业务角度看也更好解释模型一次性给出未来 24 小时的曲线比逐小时滚动预测稳定。6. 这套方案还能往哪些方向延伸6.1 加入外部因素气压、湿度与风场的组合特征温度从来不是被时间变量单独决定的。后来我把气压、相对湿度、风速、降水量的逐小时数据也加入特征矩阵LSTM 的 MAE 又从 1.7℃ 降到了 1.4℃。原因不复杂冷锋过境前气压会明显上升风速加大这些信号出现在温度骤降之前模型学会从这些前兆里预测转折比单纯看温度历史更有效。6.2 从单站点到区域网格预报如果业务需要覆盖多个城市而不是某一个站可以考虑让模型一次性学习整个区域的气象场。把多个站点的温度、气压、湿度作为一个矩阵输入用 Transformer 或图神经网络去建模站点之间的空间相关性。这一步我在项目里只做了预研没有上生产。原因是客户的数据覆盖站点太少空间依赖学不出来。但如果你手上有一整个区域的气象站网数据非常推荐试这个方向因为天气本质上是空间连续场单站点建模浪费了邻近站点的信息。最后说点个人工具层面的体验。调 LSTM 时我经常用的优化技巧是把learning_rate从默认的 0.001 降到 0.0003训练轮数相应增加收敛更慢但最终误差更低。天气预报项目不是比谁跑得快而是比谁结果稳。我现在做时间序列预测天气数据固定流程就是线性回归探底 → Prophet 出业务基线 → LSTM 精细化。遇到明显非平稳、强季节性的数据这套组合基本能覆盖 80% 的需求。本文还有配套的精品资源点击获取
返回列表