LSTM城市人口预测MATLAB实战:数据处理、训练与调参避坑
发布时间:2026/10/10 23:45:04 锦皓数字建站

简介面向城市人口预测与时间序列建模需求这份基于MATLAB长短期神经网络LSTM的完整代码包适合本科及以上阶段的研究者、竞赛选手及工程应用人员。资源内含人口数据Excel表格、四个MATLAB脚本及三十余张运行截图脚本覆盖数据读取、LSTM网络构建、训练预测与误差评估的完整流程并计算MSE、RMSE、MBE、MAE与R²等指标截图直观展示模型收敛、拟合及预测效果便于对照调试。人口数据Excel中收录了多年城市人口历史记录可直接用于训练与验证所有脚本附有清晰注释方便根据实际数据调整输入维度与网络参数。压缩包共38个文件整体仅553KB轻量易用。目前已有525人浏览学习验证了其参考价值。通过这份资料读者可掌握基于LSTM的时间序列预测方法、MATLAB实现细节与参数调优思路并迁移应用到GDP、客流量等同类预测问题。1. 用 LSTM 做城市人口预测这份 MATLAB 代码包到底怎么用才不翻车城市人口预测这类时间序列问题拿传统回归硬套往往效果很差因为人口增长受政策、经济、迁移等多因素影响数据本身带有明显的非线性和时序依赖。长短期神经网络LSTM恰好擅长捕捉这种长期依赖所以基于 LSTM 的城市人口预测这几年在课程设计、本科毕设里出现频率非常高。这份代码包基于 MATLAB 编写包含完整的人口数据 Excel、两个主程序 main1.m 和 main2.m、R² 与 MSE_RMSE_MBE_MAE 评价脚本以及大量训练过程图表适合需要快速复现 LSTM 预测流程、又不想从零搭网络的新手也适合想在此基础上改网络结构做创新的高年级学生。但资源下载下来只是第一步怎么把数据喂进去、参数怎么调、结果图怎么读才是真正决定你能不能交差的关键。2. 为什么选 LSTM 而不是 ARIMA 或 BP先搞懂人口数据属于哪类问题2.1 人口序列的三个特征决定了网络选型城市人口数据本质上是一个单变量时间序列年份在前、人口数在后每年一个观测点。这类数据和股票、气温、客流一样存在三个显著特征趋势性、周期性和随机波动。趋势性指城市人口长期向上或向下走比如过去二十年绝大多数城市都在增长周期性可能来自五年规划、普查周期带来的统计口径变化随机波动则来自突发政策或统计误差。传统 ARIMA 模型对平稳性要求很高拿到非平稳人口序列得先做差分、定阶还要反复做 ADF 检验操作繁琐且对非线性捕捉能力弱。BP 神经网络虽然能拟合非线性函数但它把每个时刻的输入当作独立样本处理不保留时间维度的记忆序列前后关系被丢掉了。LSTM 通过门控结构输入门、遗忘门、输出门维持一条贯穿时间步的记忆线在人口这类存在长期趋势的数据上能自动学到“几年前的人口基数如何影响当前值”这层关系。这也是代码包作者选择 LSTM 的核心理由——不是因为它新而是因为它和人口预测问题的匹配度高。2.2 数据文件长什么样Excel 是起点不要动格式压缩包里的人口数据.xlsx 是唯一的数据来源。我解压后用 MATLAB 的 readtable 读了一下典型结构是两列第一列年份第二列人口数。年份通常从 2000 年左右开始逐年排到近年样本量大概在 20 到 30 条之间。这不是大数据量但对 LSTM 来说已经能跑出可用结果关键是数据量少的时候更考验划分和归一化策略。我这里强烈建议拿到 Excel 先备份原始文件所有清洗、转置、归一化操作在脚本里完成不要直接在 Excel 里改数。原因很简单main1.m 读取数据时往往用固定的列索引你在 Excel 里多删一行、多插一列脚本直接报错或读出错位数据而且这种错误很难肉眼发现。我见过一个学弟把年份列删了结果 LSTM 把索引号当输入预测曲线竟然也是一条平滑上升线乍看没问题细看全是错的。2.3 单步滚动预测LSTM 在这里不是一次性输出所有年份代码包里的主程序走的是单步滚动预测思路。什么意思就是用前 N 年的数据预测第 N1 年然后把第 N1 年的真实值加入输入窗口继续预测第 N2 年。训练时输入是滑动窗口切出来的子序列输出是窗口后一年的值。比如样本总量 25 条窗口长度 3那么能构造出 22 条训练样本第 1 到 3 年预测第 4 年第 2 到 4 年预测第 5 年依此类推。% 从 Excel 读取人口数据 data readmatrix(人口数据.xlsx); % 第一列为年份第二列为人口数 pop data(:, 2); % 提取人口数列注意保持原始顺序 % 数据归一化LSTM 对输入尺度敏感必须压缩到 [0,1] 区间 pop_norm (pop - min(pop)) / (max(pop) - min(pop)); % 构造训练样本窗口滑动切分 windowSize 3; % 用过去 3 年预测第 4 年 XTrain []; YTrain []; for i 1 : length(pop_norm) - windowSize XTrain [XTrain; pop_norm(i : i windowSize - 1)]; YTrain [YTrain; pop_norm(i windowSize)]; end这段代码的逻辑是用 for 循环构造输入输出对每一行的 XTrain 是连续三年的归一化人口值对应的 YTrain 是第四年的值。windowSize 是最关键的参数设小了模型学不到长期趋势设大了训练样本数量急剧减少。对 20 多条数据来说窗口取 3 到 5 比较稳妥我一般先跑 3 起步逐步加到 5 看效果变化。注意这里用的是向量拼接方式构造样本虽然直观但样本之间存在大量重叠训练时相当于把同一条信息反复学习容易过拟合后面可以改用分块训练来缓解。3. 把 main1.m 跑起来完整训练流程与参数调整实操3.1 网络搭建隐藏层、Dropout 和全连接层的取舍main1.m 的核心是 MATLAB Deep Learning Toolbox 的 lstmLayer。代码里通常会先定义网络层结构典型写法是 sequenceInputLayer 接 lstmLayer再接 dropoutLayer 和 fullyConnectedLayer最后是 regressionLayer 回归输出。这里的 lstmLayer 第一个参数是隐藏单元数也是整个网络容量最直接的调节旋钮。% 定义 LSTM 网络结构 layers [ sequenceInputLayer(1) % 输入维度为 1即单变量人口值 lstmLayer(64, OutputMode, sequence) % 64 个隐藏单元输出完整序列 dropoutLayer(0.2) % 随机丢 20% 神经元防过拟合 fullyConnectedLayer(1) % 全连接层输出 1 个值 regressionLayer]; % 回归损失适配人口数值预测 % 训练选项 options trainingOptions(adam, ... MaxEpochs, 500, ... % 迭代轮数人口数据量小500 轮够用 InitialLearnRate, 0.005, ... % 初始学习率过大震荡过小收敛慢 MiniBatchSize, 16, ... % 每批 16 条样本 GradientThreshold, 1, ... % 梯度裁剪防止梯度爆炸 Plots, training-progress, ... % 实时画训练误差曲线 Verbose, 0); % 不打印每轮日志减少控制台刷屏这里 attentionMATLAB 的 lstmLayer 在较老版本里不支持 OutputMode 参数设为 sequence 时接 fullyConnectedLayer 的某些组合如果报维度错误把 OutputMode 改成 last只输出最后一个时间步的结果。因为我们要预测的是未来一年的人口值不是逐时间步输出last 模式在逻辑上反而更贴合但部分代码包会用 sequence 配合 flatten 层两种都能跑通区别在于训练速度和最终精度差异不大看报错情况决定去留。3.2 训练集和测试集划分别把最后几年混进训练时间序列预测最常见的翻车就是把未来数据混进训练集。人口预测的场景里我们通常拿前 80% 的数据训练后 20% 做验证。比如 25 年数据前 20 年训练后 5 年用来对比预测效果。划分的边界必须在构造滑动窗口之前完成不然窗口切片会让训练集包含未来信息测试失去意义。% 按时间顺序划分训练集和测试集严禁随机打乱 trainRatio 0.8; trainLen floor(length(pop_norm) * trainRatio); % 在归一化后的序列上直接切分 trainData pop_norm(1 : trainLen); testData pop_norm(trainLen 1 : end); % 训练部分构造窗口样本 XTrain []; YTrain []; for i 1 : trainLen - windowSize XTrain [XTrain; trainData(i : i windowSize - 1)]; YTrain [YTrain; trainData(i windowSize)]; end % 测试部分同样构造但只用于评估不参与训练 XTest []; YTest []; for i 1 : length(testData) - windowSize XTest [XTest; testData(i : i windowSize - 1)]; YTest [YTest; testData(i windowSize)]; end需要注意trainData 和 testData 共用同一个归一化参数min(pop) 和 max(pop)也就是用全体数据的最大最小值做归一化这一点很多新手搞错——有人只对训练集计算 min 和 max测试集用另一套归一化参数导致数据分布不一致预测结果直接变形。正确的做法是归一化参数来自全部数据这样测试集的归一化值才和训练集处在同一尺度上。3.3 训练后的滚动预测预测值要反归一化才能看懂训练完成后用 predict 函数对测试集做滚动预测。每预测一步把得到的预测值作为下一轮输入的一部分模拟真实的逐年外推场景。这里有个关键细节滚动预测是拿预测值当输入继续跑而不是拿真实值。如果在测试阶段用真实值喂给模型那评估出来的误差是“一步预测误差”不是“多步预测误差”真实使用场景下未来值根本不存在所以必须滚动。% 滚动预测测试集后续年份 net trainNetwork(XTrain, YTrain, layers, options); predNorm zeros(length(YTest), 1); inputWindow trainData(end - windowSize 1 : end); % 用训练集末尾窗口启动 for i 1 : length(YTest) % 当前窗口作为输入预测下一个值 p predict(net, inputWindow); predNorm(i) p; % 将预测值加入窗口末尾并丢到窗口最前面的值 inputWindow [inputWindow(2 : end); p]; end % 反归一化恢复人口真实量级 predPop predNorm * (max(pop) - min(pop)) min(pop); realPop YTest * (max(pop) - min(pop)) min(pop);这段代码中 inputWindow 是长度为 windowSize 的列向量每次 predict 输入需要转置成行向量MATLAB 的 sequenceInputLayer 默认接受 1×windowSize 的格式预测出的标量 p 是归一化的预测值。把它拼到窗口末尾同时去掉最旧的年份窗口向后滑动一步循环往复。这里最容易翻车的是 predict 函数输入格式如果直接传列向量MATLAB 会报 Input data must be a single datastore, a single cell array, or a single matrix 之类的错误这时候加上转置符即可。反归一化公式就是归一化的逆运算乘标准差加最小值代码里写成乘 (max-pop) 加 min和前面的归一化一一对应。4. 看懂评价指标与配套脚本R²、MSE 这些数字到底意味着什么4.1 R_2.m 和 MSE_RMSE_MBE_MAE.m 的功能定位包里的 R_2.m 和 MSE_RMSE_MBE_MAE.m 是独立的评价函数跑完预测后调用它们可以一次性算出决定系数 R²、均方误差 MSE、均方根误差 RMSE、平均偏差 MBE 和平均绝对误差 MAE 这五个指标。R² 衡量模型解释了多少方差越接近 1 越好MSE 和 RMSE 衡量预测偏差的大小越小越好MBE 反映系统性的偏高或偏低正值说明整体预测偏大MAE 是绝对误差的平均比 MSE 更抗异常值干扰。% 调用评价脚本传入真实值和预测值 R2 R_2(realPop, predPop); [MSE, RMSE, MBE, MAE] MSE_RMSE_MBE_MAE(realPop, predPop); fprintf(R² %.4f\nMSE %.2f\nRMSE %.2f\nMBE %.2f\nMAE %.2f\n, ... R2, MSE, RMSE, MBE, MAE);这些脚本内部就是套公式R² 等于 1 减去残差平方和除以总平方和RMSE 是 MSE 开根号。但注意评价指标算的是反归一化之后的值还是归一化之后的值会直接影响数字大小。MSE 如果基于归一化数据计算数值在 0 到 1 之间反归一化后变成真实人口数量级的平方差可能动辄上万。代码包里默认状态我没法逐一确认但稳妥做法是在反归一化后的真实量级上计算指标这样写论文时可以直接引用不用再换算。4.2 训练图 a1 到 b16 怎么看曲线形态比数字更重要压缩包里那一堆 a1.jpg、b1.jpg、b3.jpg 之类图片是代码运行过程中自动保存的训练过程图和预测对比图。a 系列通常是训练集的效果展示b 系列是测试集或全序列的预测对比。看这些图有一个实用技巧先看预测曲线和真实曲线的重合度在哪个时间段变差。如果前期重合很好、后期分叉说明模型学到了历史规律但外推能力弱这通常是数据量不足或窗口太短导致的如果整体趋势对但每年峰值差一截可能是归一化没有保留周期性如果训练误差曲线剧烈震荡不下降先怀疑学习率太大。MAE 等指标描述的是平均表现但一张图能告诉你误差集中在哪些年份。城市人口数据里通常最近几年的值受政策影响波动大测试集恰好落在最近年份时预测误差天然偏大这不代表模型失败而是数据本身的不可预测性。写报告时我会把训练集和测试集分开展示再单独列最近三年的预测误差这样老师能看出你不是用一个模型糊弄所有年份。4.3 main2.m 是变体还是升级版先跑 main1再对照改代码包里同时存在 main1.m 和 main2.m很可能是同一套流程的两种变体。常见的区别是main1 用单步滚动预测并输出测试集指标main2 可能改成多步直接预测或者改变了窗口长度、隐藏单元数、训练轮数中的一个参数来对比效果。这类设计的目的是方便你做参数对比实验。我的建议是先把 main1 完整跑通记录指标再用 main2 跑一遍对比两者差异。如果 main2 只是改了窗口长度你可以在 main1 基础上手动改 windowSize 复现不需要同时维护两个脚本。5. 避坑指南城市人口预测最容易翻车的四个地方5.1 预测结果是一条几乎水平的直线现象训练误差正常下降但预测曲线最后变成一条平线基本不随年份变化。原因序列归一化后数值接近 0 或 1 的边界LSTM 的输出经过 tanh 激活函数会趋向饱和梯度极小模型输出近似常量。另一个常见原因是窗口内所有输入值几乎相等模型学到的是“输出约等于输入”相当于一个平滑器。解决检查归一化后的最小值是否接近 0加入一个很小的偏移量如 0.01 再归一化同时把 lstmLayer 的隐藏单元数降下来从 64 减到 32 或 16降低模型容量减少“死神经元”现象。如果还是平线把 InitialLearnRate 调大到 0.01 重训一次看训练损失曲线是否重新开始下降。5.2 测试集误差远大于训练集误差现象训练集 R² 超过 0.99但测试集 R² 只有 0.7 甚至更差。原因样本量太少加上窗口滑动构造样本导致信息重叠训练时模型“背”下了训练序列相当于记忆样本而不是学习规律。解决在 lstmLayer 后面加大 dropoutLayer 的比例到 0.3 或 0.4同时把 MaxEpochs 从 500 降到 200减少迭代次数相当于提前停止可以显著压制过拟合。另外可以尝试把窗口滑动构造改成分段不重叠构造虽然样本数变少但每一条样本的独立性更强测试集表现往往更好。5.3 读入 Excel 时报错或数据错位现象readmatrix 或 xlsread 读进来的人口数远大于或远小于预期或者年份列读出来是 NaN。原因人口数据 Excel 里可能包含表头、多列说明文字或合并单元格MATLAB 默认从 A1 开始读取表头文本被当作数据列后数值转换失败。解决读入时指定范围或用 detectImportOptions 跳过表头例如readmatrix(人口数据.xlsx, Range, A2:B26)。如果文件里有多余的 sheet用sheetname参数指定到底读哪一张表。批处理前先disp(data)打印前五列肉眼确认读进来的矩阵形状这一步能挡掉 90% 的后续错误。5.4 把 R_2.m 当主程序直接运行现象双击 R_2.m 点击运行MATLAB 报错说找不到变量 realPop 或 predPop。原因R_2.m 是函数文件文件开头是 function 声明它只定义输入输出的计算逻辑不会主动加载数据必须由 main1.m 在预测完成后调用。解决先运行 main1.m确保工作区里生成了 realPop 和 predPop 两个变量再在命令行手动输入R2 R_2(realPop, predPop)。这一点对 MATLAB 新手特别容易卡住因为脚本和函数文件的运行逻辑完全不同函数文件没有输入参数时直接运行必然报错。6. 把结果做进论文和报告三个自查技巧与曲线优化习惯确定预测步数时我一般遵循一个原则测试集样本数至少留 4 到 6 个点太少评估没统计意义。人口数据总量 25 条、测试集留 5 条时窗口最大只能取 3因为窗口占掉 3 个历史值剩下的 17 条训练样本构造窗口样本后非常少。如果觉得效果不好可以用交叉验证思路多次随机选择不同的切分点跑多个模型看指标波动范围而不是只依赖一次切分的结果。这个习惯在写论文时特别有用评审问一句“你的结果稳定吗”你能直接给出多次运行的误差棒图说服力完全不一样。核验预测性能的快速手段是对比评价指标的量级。城市人口如果是几百万量级RMSE 在几万到几十万之间是正常的如果 RMSE 只有几百大概率是归一化区间搞错了或者测试集样本数太少恰好没踩中大偏差点。我会把真实值和预测值并排打印出来逐年做差观察误差是否集中在某一年。如果某一年误差特别大先查那一年人口是不是有异常突变——比如行政区划调整导致人口跳增这样的点模型学不到不能怪网络结构。为论文准备对比实验时可以在 main1 的基础上复制出 main1_arima.m 和 main1_bp.m用同一份数据文件跑 ARIMA 和 BP 模型把三个模型的 RMSE、MAE、R² 列成表。LSTM 在这个场景下通常 RMSE 比 ARIMA 低 20% 到 40%比 BP 低 10% 到 20%这是非常好看的对比结论。做表时注意统一评价指标的计算区间三个模型都用测试集的同一年份段不然公平性站不住脚。关于 LSTM 隐藏单元数的确定我习惯做一组小规模参数扫描固定其他参数不变隐藏单元分别取 16、32、64、128记录每个配置下测试集 RMSE选最小的一项。人口数据量小跑一轮最多几分钟参数扫描成本完全可以接受。扫描结果用柱状图画出来放进报告附录能体现工作量。从那以后我每次做时序预测都会强制走一遍“数据肉眼检查 → 归一化参数全序列统一 → 测试集滚动预测 → 多配置参数对比”这套流程少走很多弯路希望帮到你。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。