资讯详情

LSTM降雨径流预测Matlab实现:数据归一化与预测评估

📅 2026/10/25 10:09:36 | 华诺云谱 👁 阅读
LSTM降雨径流预测Matlab实现:数据归一化与预测评估
简介基于LSTM网络实现降雨径流预测的Matlab代码包适合水文水资源、环境工程等领域的研究生、工程师及入门深度学习的算法学习者。资源围绕长短期记忆网络对降雨与径流时序关系的建模展开提供完整可运行的主程序与归一化等预处理函数并附带示例数据与文字说明便于快速复现和二次开发。压缩包共4个文件以2个m脚本为主负责模型搭建、训练与预测流程2个txt文件则提供数据输入和操作备注整体仅290KB轻量易用。目前已有220人学习下载适合需要掌握LSTM在水文预测中具体实现方法或希望在此基础上调整模型结构、更换数据集的读者可直接对照代码理解数据划分、归一化及预测输出等关键环节。1. 降雨径流预测遇上LSTM这份Matlab代码包到底能解决什么做水文预报的人估计都遇到过这种尴尬手里有一段日径流数据想用LSTM做降雨径流预测翻遍论文发现不是TensorFlow就是PyTorch能在Matlab里直接跑通的很少。这份基于LSTM网络进行降雨径流预测附matlab代码的压缩包就是为了填这个空。解压后一共四个文件Normalization.m、说明.txt、main.m、01127000.txt结构非常干净。01127000是一个公开水文站点编号txt里放的是实测径流序列Normalization.m负责数据归一化main.m把读数据、建网络、训练、预测全部串起来。不需要额外折腾Python环境有一台装着Matlab深度学习工具箱的电脑就能复现。适合正在做毕业设计或课程设计的水文、土木、资源环境方向学生也适合想在Matlab里把LSTM时序预测链路完整走一遍的工程师。它不追求网络结构多深而是把“数据怎么喂、参数怎么定、预测结果怎么反算”这条链路讲明白属于能直接落地跑通的参考实现。2. 拆包看结构从四个文件看懂这份LSTM降雨径流工程拿到压缩包别急着双击main.m我习惯先把每个文件的职责摸一遍不然出了问题都不知道去哪一行改。这个工程只有四个文件分工却非常明确01127000.txt是数据源Normalization.m是数据预处理main.m是主流程说明.txt是运行说明。下面挨个拆开说。2.1 01127000.txt一段公开站点的径流序列能承载多少信息01127000这个编号一看就是USGS水文站点编号国内做水文的人对这类公开数据不陌生它代表一个具体测站txt里通常是按日采样的实测径流序列。这类数据的价值在于可复现、有据可查用来验证算法非常合适不用自己去河道上架设备测数据。从任务边界看这份资源的输入是一维的只有一个径流序列没有降雨、蒸散发、气温这些外强迫变量。所以它建模的是“历史径流到未来径流”的自回归关系而不是严格意义上的多变量降雨-径流模型。把LSTM当黑匣子用过去一段窗口的流量去预测下一时刻流量这个思路在这个数据集上完全成立但如果要预报一场具体暴雨引发的洪水单靠历史流量是不够的需要把降雨序列作为输入特征拼进去。认清这个边界你才知道这份代码能回答什么问题、回答不了什么问题。拿到txt我先做三件事打开文件看前10行确认格式统计缺失值和负值再看数值量级判断单位。USGS的流量单位可能是ft³/s也可能是m³/s量级差得不是一星半点单位弄错后面所有预测结果都是错的而且很难排查。这里列一下常见的txt文件内部形态遇到哪种形态就知道该怎么处理文件内容形态典型示例读取策略纯数值单列123.4readmatrix直接读最省事日期数值2020-01-01,123.4需处理日期列带表头说明STATION: 01127000跳过非数值行多列混合数据多年多列显式取需要的流量列为什么要花篇幅说这个因为水文数据的原始文件几乎不会长得一模一样80%的复现失败不是模型塌了而是数据没读对。2.2 Normalization.m为什么第一步是归一化而不是差分降雨径流数据最大的特点是量级跨度大枯水期可能只有几个立方米每秒汛期能涨到几千差了两三个数量级。LSTM内部用的是tanh激活函数输出范围在[-1,1]之间输入差异过大时神经元很容易饱和梯度变得极小网络基本学不动。所以归一化不是可有可无的预处理而是LSTM能不能收敛的前提。常见做法是min-max归一化把序列线性映射到[0,1]公式是x(x-x_min)/(x_max-x_min)。但这个公式有个容易被忽视的前提x_min和x_max必须在训练集上计算再拿这组统计量去归一化测试集。如果偷懒用全序列的min和max测试集的信息在训练阶段就通过归一化参数泄露出去了测试指标会虚高换一段新数据立刻露馅这个坑在第5章会专门展开。也有人说要不要先差分再做归一化因为径流序列往往有很强的季节趋势。我的做法是先试min-max如果预测曲线呈现出明显的滞后或趋势跟随再考虑对序列做一阶差分把非平稳性处理掉。差分解决的是均值非平稳归一化解决的是量纲和尺度两者不是同一类问题。这份工程的Normalization.m从命名和分工来看就是干min-max归一化这件事先跑它再进main.m执行顺序是合理的。选哪种归一化方式可以参考下面这个对比归一化方式Matlab实现输出范围适用场景手写min-max(x-min)/(max-min)[0,1]单序列、统计量可控mapminmaxmapminmax(x)[-1,1]默认快速验证z-score(x-mean)/std无固定范围数据近似正态分布2.3 main.m读数据、建网络、训练、预测一条主线main.m是唯一的启动入口正常执行顺序是读入01127000.txt、调用或内联归一化逻辑、按滑动窗口切样本、定义LSTM网络结构、配置训练参数、执行trainNetwork、用训练好的网络做预测、反归一化、画图对比实测与预测。六个环节缺一不可每一步的写法都影响最终预测形态。这类脚本还有个特点它不是函数式封装参数全写在脚本开头。好处是新手看起来直观改一个数字就能重新跑一遍坏处是跑完工作区变量全留着二次开发要小心命名冲突。我一般跑通之后会把它改造成函数把数据路径、归一化开关、隐藏单元数、滞后步长全部提成输入参数以后换站点、换数据就不用满脚本找常量去改。说明.txt在这个工程里承担的是运行说明角色一般会写清数据来源、Matlab版本要求、先跑哪个文件。我每次拿到这类资源都先看说明再动手能省掉大量试错时间因为lstmLayer这些接口只有在装了Deep Learning Toolbox的Matlab里才有版本太旧直接报错。从资源价值看这套代码胜在完整闭环尤其是“预测结果反归一化回物理量”这一步写进了主线对初学者最友好很多人卡在模型能跑、但不知道预测值怎么和实测流量对比这份资源把最后一公里补齐了。3. 数据预处理复现从txt原始序列到能喂进LSTM的干净样本上一章讲的是文件职责这一章开始动手。不管模型结构怎么变数据侧有三步绕不开读原始文件、归一化、按时间切分。每一步都有固定套路也有固定坑。3.1 读取01127000.txt的正确姿势与表头陷阱老教程喜欢用textread它读纯数值矩阵方便但一遇到表头、单位行、空行就报错非常脆弱。我现在统一用readmatrixR2019a之后的Matlab都有能自动跳过非数值行适合处理带说明的导出文件。% 读取径流数据readmatrix会自动跳过非数值行 data readmatrix(01127000.txt); % 如果txt只有一列数值data就是列向量多列则取需要的列 q data(:, 1);这段的逻辑是先让readmatrix把文件读成矩阵再显式取出流量列。注意readmatrix的默认行为是跳过非数值行这个特性很多人不知道知道后能少踩一个坑。如果文件前几行是站点信息可以再加NumHeaderLines参数% 如果文件前两行是站点信息和单位显式跳过 data readmatrix(01127000.txt, NumHeaderLines, 2);读进来先做数据质量检查我习惯用几行命令确认序列能不能用fprintf(缺失值数量%d\n, sum(isnan(q))); fprintf(负值数量%d\n, sum(q 0)); fprintf(序列长度%d\n, length(q));逻辑说明isnan统计NaN负值检查是判断是否存在异常记录length确认样本量。如果缺失值数量不为0需要先插值或删除否则LSTM训练时NaN会直接传染梯度训练过程会非常难看。单位换算再强调一次。USGS数据很多是cfs也就是立方英尺每秒转m³/s要乘0.0283168。判断方法很简单看数值量级如果日常流量在几十到几百之间大概率是cfs如果流量在几到几百、峰值能过千可能是m³/s。拿不准就先按两种单位分别跑一次看预测曲线是否合理这个习惯能救你一命。3.2 min-max归一化的Matlab实现与统计量边界归一化这一步我不太建议用mapminmax直接怼全序列虽然写起来最短但它会把整个输入序列的统计信息都算进去埋下数据泄漏隐患。更可控的做法是手写min-max并且明确只在训练集上计算统计量。% 用训练集计算归一化统计量 q_min min(q_train); q_max max(q_train); % 归一化训练集和测试集测试集复用训练集统计量 q_train_norm (q_train - q_min) / (q_max - q_min); q_test_norm (q_test - q_min) / (q_max - q_min);逻辑说明前两行统计的是训练集的最小值和最大值后面两行分别对训练集和测试集做映射。关键是q_test_norm复用了训练集的q_min、q_max而不是重新统计测试集这样测试集信息才不会提前进入模型。测试集归一化后落在[0,1]之外是正常的比如-0.05或1.1不用慌只要训练集覆盖了全局极值越界幅度不会太大。如果坚持用mapminmax必须保留返回的ps结构体并用apply模式处理测试集[q_train_norm, ps] mapminmax(q_train, -1, 1); q_test_norm mapminmax(apply, q_test, ps);apply的作用就是用训练集统计出的ps去处理测试集避免重新统计。很多人漏掉第二行导致训练集和测试集用了不同的归一化基准预测结果和实测尺度对不上这个问题在论文里经常看到属于典型的数据泄漏。预测结果反归一化同样用同一组统计量q_pred_real q_pred .* (q_max - q_min) q_min;参数说明q_pred是模型输出的归一化预测值反算回物理单位后才能和实测流量对比。必须用点乘因为q_pred通常是列向量用矩阵乘会直接报维度错误。注意归一化的统计量只允许来自训练集这是时序预测的底线。谁用全序列算min/max谁就该被请去重新读一遍数据泄漏的定义。3.3 按时序切分训练/测试集时间序列不能随机洗牌分类任务里数据可以随机打乱时序任务绝对不行。LSTM学的是时间依赖一旦把顺序打乱过去和未来的信息混在一起模型学到的是“靠未来预测过去”的假规律。所以切分只能按时间顺序前80%训练、后20%测试是最常见配置。ratio 0.8; idx round(ratio * length(q_norm)); q_train q_norm(1:idx); q_test q_norm(idx1:end);逻辑说明idx是切分点前80%做训练后20%做测试。参数说明ratio0.8是常用起点数据量小可以放到0.85但测试集至少要留出一个完整水文年否则看不到季节性表现。切分清楚之后下一步才是滑窗构造样本。还有一个实操细节切分之后把归一化参数保存成mat文件这个习惯在工程上很重要因为系统上线预测时不可能重新拿旧训练数据算一遍min和max。save(norm_params.mat, q_min, q_max);这样写的好处是预测脚本只依赖norm_params.mat不依赖原始训练数据代码更干净。另外注意切分前不要做任何用到全序列统计信息的操作包括均值填充、整体去趋势这些都要在切分之后、只基于训练集来做否则一样构成泄漏。4. main.m复现LSTM网络搭建、训练选项与滚动预测数据准备好之后进入模型侧。这一章按main.m最常见的组织方式拆开讲网络结构、训练参数、滑动窗口、预测写法四个部分每一部分都有能直接抄走的代码和对应参数。4.1 网络结构sequenceInputLayer到regressionLayer怎么拼Matlab深度学习工具箱里LSTM回归网络的标准拼法是四层序列输入层、LSTM层、全连接层、回归层。这份资源是单变量预测输入特征数就是1。numFeatures 1; % 输入特征数这里是单变量流量 hiddenUnits 50; % LSTM隐藏单元数 layers [ sequenceInputLayer(numFeatures) lstmLayer(hiddenUnits, OutputMode, last) fullyConnectedLayer(1) regressionLayer];逻辑说明sequenceInputLayer接收序列数据每个样本是1×lag的向量lstmLayer是模型核心hiddenUnits50是对单变量日径流序列的常用起点OutputMode,last表示只输出最后一个时间步的隐藏状态正好匹配“用过去lag天预测下一天”的任务fullyConnectedLayer(1)把隐状态压缩成1维输出regressionLayer计算回归损失。参数说明hiddenUnits不是越大越好我在这类尺度数据上的经验范围是50到100再大容易过拟合。径流序列本身噪声很大过拟合的表现就是训练Loss很低、测试集预测曲线却平得像条直线。如果你的数据和这份资源量级差不多先按50跑通再试100对比。4.2 trainingOptionsAdam、学习率、梯度裁剪怎么定训练配置决定模型能不能收敛以及收敛到哪。我一般这样设options trainingOptions(adam, ... MaxEpochs, 100, ... MiniBatchSize, 64, ... InitialLearnRate, 0.005, ... GradientThreshold, 1, ... Verbose, 1, ... Plots, training-progress);参数说明逐条说求解器选adam而不是sgdm是因为径流序列变化剧烈adam的自适应学习率更稳sgdm在这个任务上容易Loss震荡MaxEpochs100是起点Loss还在明显下降就加到150超过200没变化就要考虑模型结构或数据问题而不是继续加算力MiniBatchSize64在几千到几万样本规模下比较合适InitialLearnRate0.005是LSTM训练的经验区间0.01偏激进、0.001偏保守建议先0.005跑一次看Loss曲线GradientThreshold1是防梯度爆炸的保险丝LSTM在长序列上很容易梯度爆炸这个参数能显著提升训练稳定性。注意别盯着控制台的数字看要看训练进度图里Loss曲线的形态。锯齿状上下乱跳就降学习率水平线就检查数据归一化和OutputMode。4.3 构造训练样本滑动窗口切分与cell数组格式LSTM在Matlab里的输入格式和普通机器学习不一样X必须是cell数组每个cell里面是[特征数, 时间步数]的矩阵。初学者第一次写十有八九栽在这里。常见做法是用循环构造lag 12; % 用过去12天预测下一天 X {}; Y []; for i lag 1 : length(q_train_norm) X{end 1, 1} q_train_norm(i - lag : i - 1); Y(end 1, 1) q_train_norm(i); end逻辑说明循环从第lag1个样本开始每次取前lag个值作为输入窗口当前第i个值作为目标输出。X{end1,1}是在cell数组末尾追加每个元素是1×lag的行向量。Y是列向量长度和X的cell数严格一致。参数说明lag12对日尺度数据是合理起点12天窗口能覆盖一次中小洪水过程的涨落如果做小时尺度预测lag可能要拉到24以上。lag越大样本数量越少太小模型学不到过程形态这个参数值得单独做一组对照实验。训练调用一行就够了net trainNetwork(X, Y, layers, options);这里有个容易犯的错X和Y长度不一致十有八九是循环边界写错比如把lag1写成了lag或者把i-lag写成了i调试的时候先打印length(X)和length(Y)。4.4 单步滚动预测与反归一化对齐预测阶段最容易出的问题不是模型而是维度对不上。测试集要按训练集完全一样的方式构造XTest {}; YTest []; for i lag 1 : length(q_test_norm) XTest{end 1, 1} q_test_norm(i - lag : i - 1); YTest(end 1, 1) q_test_norm(i); end YPred predict(net, XTest); YPredReal YPred .* (q_max - q_min) q_min; YTestReal YTest .* (q_max - q_min) q_min;逻辑说明测试集构造方式和训练集完全一致保证predict输入的维度格式正确。predict返回的YPred是列向量和YTest对齐后反归一化得到和原始流量同量纲的预测值与实测值画图对比才有意义。这里要提醒一个概念上面这段是“单步滚动预测”每个测试样本的输入窗口都由真实历史值构成评估的是模型在已知历史条件下的短期预测能力。但实际水文预报更关心多步预报比如提前3天、7天预报那需要把预测值当成下一步的输入窗口形成真正的滚动外推把模型输出回填到窗口尾部。纯预测模式误差会累积但更接近工程实际。两种模式算出来的指标差别很大评价模型效果时一定要说清楚用的是哪种模式不然报告写出来都站不住脚。5. 避坑记录LSTM径流预测最常翻车的五个现场模型能跑通只是开始真正让人头秃的是结果不对。下面五个问题在各类水文LSTM代码里反复出现有的修起来是一行的差别有的要重写预测逻辑。全部按“现象→原因→解决”写方便直接对着检查。5.1 预测形态类滞后、水平线、虚高指标坑1预测曲线整体滞后实测一天洪峰对不上。现象画图对比时预测峰总比实测峰晚1个时间步峰值也明显偏小曲线像是被向右平移了。 原因模型学到的是“把上一天的值搬过来”这是单变量径流预测最常见的病相说明网络没有真正学到涨落过程的形态或者输入窗口和目标有重叠。 解决一是把lag从12提到24给模型更长上下文二是检查滑窗边界输入窗口应该是i-lag到i-1千万不能让第i个值自己出现在输入窗口里。输入和输出重叠时模型会走捷径预测自然滞后。坑2训练Loss很低但预测输出接近一条水平线。现象训练过程loss曲线平滑下降且数值很小但测试集预测结果是一条接近均值的直线算下来NSE是负的。 原因典型的过拟合或欠拟合同时发生的假象。隐藏单元数太少时网络退化成学习输出均值学习率太低时Loss卡在平缓区模型根本没学进去。 解决先把hiddenUnits提到100InitialLearnRate调到0.01MaxEpochs提到150看曲线是否松动。如果仍然是一条直线回去检查q_train_norm归一化时如果除以0会得到NaNNaN传进LSTM等于白训。坑3测试集NSE高达0.99换个站点立刻崩。现象当前数据上指标好得夸张NSE接近1但相同代码换到另一段数据上完全不行。 原因九成是数据泄漏最典型的是mapminmax用了全序列统计量或者切分前对整段序列做了归一化相当于模型提前偷看了测试答案。 解决严格只用训练集算q_min、q_max测试集和预测阶段复用同一组统计量。再教一个笨但有效的验证方法在main.m开头临时把训练集截短一半如果指标明显变化说明模型真学到了规律如果指标几乎不变大概率是泄漏。5.2 运行环境与读取类连代码都跑不起来的问题坑4运行main.m报错“未定义函数或变量lstmLayer”或Matlab启动时提示由于找不到msvcp140.dll无法继续执行代码。现象代码本身没问题一执行就报函数未定义更早的时候是Matlab一启动就弹dll缺失的窗口。 原因前者是Deep Learning Toolbox没装lstmLayer是工具箱函数不是Matlab内置函数后者是Windows系统缺少VC运行库Matlab的深度学习功能启动时需要加载这些动态链接库。 解决前者在Matlab的“附加功能”里安装Deep Learning Toolbox装完执行which lstmLayer确认路径可用后者下载安装Microsoft Visual C Redistributable 2015-2022 x64版本装完重启Matlab。这两个环境问题解决后基本不会再出现。坑5readmatrix读取01127000.txt后列数对不上数据错位。现象data维度不是预期的N×1而是1×N或者某一列全是0和NaN。 原因txt里有表头、单位说明或者制表符与逗号混用readmatrix有时会把第一行当成数据有时会把多列读成一行。 解决先打开文件看前10行确认结构有表头就加NumHeaderLines多列就显式取需要的列。还有一个笨但有效的方法用readtable(01127000.txt)读成表格再用table2array取数值列表格能保留更多文件结构信息排查起来更直观。环境问题解决完再谈调参顺序不要反。最后补一个环境核对清单按这个查一遍能省出至少半小时检查项确认内容常见问题Matlab版本R2019a及以上老版本没有readmatrixDeep Learning Toolbox已安装lstmLayer未定义VC运行库2015-2022 x64msvcp140.dll缺失当前目录包含四个文件路径不对读不到txt6. 进阶验证用NSE和RMSE判断模型是真会还是假会6.1 先小数据快速跑通再上全量LSTM训练一次少则几十秒、多则几分钟参数试错成本很高。我的习惯是先截取前2000个样本把全流程跑通确认代码没有低级错误再放开全量数据训练。% 调试模式只用前2000个点 debugLen 2000; q_debug q(1:min(debugLen, length(q))); % 后续归一化、切分、滑窗全部基于q_debug逻辑说明压缩迭代周期把“代码报错”和“模型效果差”两类问题分开处理。参数说明debugLen取2000按80/20切分后有1600个训练点足够验证滑窗和trainNetwork是否正常跑一轮只要几十秒。6.2 NSE和RMSE的计算与判读水文预报最常用的两个指标是NSE和RMSE。NSE越接近1越好大于0.5算可用大于0.65算良好小于0说明模型比直接用均值预测还差。RMSE是带单位的绝对误差方便直观感受误差量级。% 计算RMSE和NSEYPredReal和YTestReal需长度一致且已反归一化 residual YPredReal - YTestReal; RMSE sqrt(mean(residual.^2)); NSE 1 - sum(residual.^2) / sum((YTestReal - mean(YTestReal)).^2); fprintf(RMSE: %.3f m3/s, NSE: %.3f\n, RMSE, NSE);逻辑说明RMSE是预测误差的均方根单位是流量单位直观NSE把模型误差和“用均值预测”的误差对比是无量纲相对指标。参数说明分母用的是实测序列的方差所以NSE会惩罚对洪峰的低估洪峰差一点NSE掉得很快。从复现这份资源的角度建议下载后在Matlab里依次运行Normalization.m再跑main.m然后把滞后步长和隐藏单元数都改一遍分别算NSE对比你会发现这个“调参—验证”循环比单纯跑通一次学到的东西多得多。从那以后我每次复现水文LSTM代码都强制走一遍先小数据验证、再上全量的流程模型输出先画图看峰谷对没对上再谈指标数值。判断“会了”的标准是曲线形状和NSE同时过关而不是训练误差为零。希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑