首页 / 资讯中心 / 文章详情

Leslie人口增长模型MATLAB实现:从年龄结构到长期预测

Leslie人口增长模型MATLAB实现:从年龄结构到长期预测 ★ FEATURED ARTICLE
简介这份资源围绕中国人口增长预测展开面向数学建模学习者、参赛选手及人口研究入门者重点解决如何用Logistic阻滞增长模型与Leslie年龄结构模型进行中短期和长期人口趋势预测的问题。压缩包内共1个doc文档约988KB完整收录了模型建立、参数估计、残差分析与优缺点评价等核心内容并借助MATLAB完成数据处理与预测计算。文档中详细对比了1954年、1963年、1980年至2005年三组数据建模的效果指出以1980—2005年数据拟合的可决系数达0.9987并给出2010年、2020年、2033年总人口预测值Leslie模型部分则预测了2002—2050年总人口、劳动年龄人口与老年人口分析了老龄化加速、人口抚养比上升及育龄妇女人数变化等指标。目前已有5152人学习下载适合需要参考完整建模思路、指标预测方法与MATLAB实现细节的读者。1. Leslie人口增长模型从年龄结构到长期预测的那条主线人口预测这件事很多人第一反应是拿历史总人口拟合一条曲线外推。做过几年数据的人都知道这种玩法在短期还行一旦拉到二三十年尺度就会翻车——因为它把人口最核心的东西丢掉了年龄结构。同样是一亿人一半是儿童和一半是劳动年龄人口未来二十年的走向完全相反。Leslie人口增长模型解决的正是这个问题它把人口按年龄分组用生育率和存活率构造一个矩阵逐年迭代就能推出年龄结构和总量的演化。它属于离散时间的矩阵人口学模型和Logistic那种只盯总量、靠环境容量约束的连续模型是两条路子。这篇面向的是想用MATLAB把Leslie模型真正跑起来的人需要什么数据、矩阵怎么填、参数从哪来、结果怎么读、哪里最容易出错。新手能照着复现熟手能对着参数和边界挑刺。2. Leslie矩阵的构造逻辑与数据准备2.1 为什么是矩阵而不是一条拟合曲线Leslie模型的核心假设很朴素把人口按等长的年龄区间切成若干组比如每5岁一组0-4、5-9、……、直到最高年龄组。每个年龄组的女性人数构成一个列向量记为 $n_t$。下一时刻的向量 $n_{t1}$ 由当前向量左乘一个矩阵 $L$ 得到$$n_{t1} L \cdot n_t$$这个 $L$ 就是Leslie矩阵它的结构分两部分。主对角线下方的那条次对角线放的是各年龄组的存活率 $s_i$含义是第 $i$ 组的女性活到第 $i1$ 组的比例第一行放的是各年龄组的生育率 $f_i$含义是第 $i$ 组女性在单位时间内生育并存活到第0组的女儿数。矩阵长这样以 $k$ 个年龄组为例L [ f_0 f_1 f_2 ... f_{k-1} ] [ s_0 0 0 ... 0 ] [ 0 s_1 0 ... 0 ] [ 0 0 s_2 ... 0 ] [ ... ... ... ... ... ] [ 0 0 0 ... 0 ]为什么用女性而不是总人口因为生育行为由育龄女性决定用女性单性别建模能把生育率定义得干净避免两性数据口径打架。这是人口学里的通行做法不是偷懒。选它而不是Logistic的理由也很直接Logistic给不出年龄结构做不了学龄人口、劳动力、老龄化的分年龄预测而这些恰恰是政策场景真正关心的。2.2 数据从哪来怎么对齐年龄组跑Leslie模型最少需要三类数据分年龄组的女性人口、分年龄组的女性存活率、分年龄组的女性生育率。常见来源是人口普查或统计年鉴的分年龄表通常按5岁分组。这里第一个坑就是年龄组的对齐——普查数据的分组边界、你建模用的分组边界、生育率数据的分组边界三者必须完全一致否则矩阵填进去就是错的。我一般会先把原始数据整理成三张表用MATLAB的table读进来再做一次显式的对齐检查。下面是一个最小可跑的数据准备脚本假设你已经有分年龄女性人口pop_f、存活率surv、生育率fert三个列向量长度都是k% 年龄组参数每5岁一组从0岁到100共21组 k 21; age_edges 0:5:105; % 分组边界长度 k1 % 假设从外部读入这里用占位数据演示结构 pop_f rand(k,1) * 1e5; % 各年龄组女性人口 surv 0.98 * ones(k,1); % 各年龄组存活率最后一组通常置0 fert zeros(k,1); % 各年龄组女性生育率 fert(4:8) [0.02 0.08 0.10 0.07 0.03]; % 15-19到35-39岁育龄段示例 % 对齐检查三个向量长度必须一致 assert(numel(pop_f)k numel(surv)k numel(fert)k, ... 年龄组数不一致检查分组边界); % 存活率最后一组无法存活到下一组强制置0 surv(end) 0;这段代码的关键不在计算而在那个assert。血泪经验是数据来源一多长度对不上是最高频的低级错误早检查早省事。age_edges的长度必须是k1因为它是边界不是组数很多人在这里差一位。生育率只填育龄段其余为0这是模型定义决定的不是可选项。2.3 生育率与存活率的换算口径原始数据里的生育率往往是总和生育率或分年龄生育率单位是「每个女性一生生育的孩子数」或「千分比」而Leslie矩阵第一行要的是「每个女性单位时间生育的女儿数」。换算要过两道一是除以2假设性别比接近1只取女儿二是按时间步长缩放。如果时间步是5年而生育率是年度的就要乘以5。存活率同理。普查给的通常是某年龄组的存活比例如果时间步是5年直接用即可如果时间步是1年就要把5年存活率开5次方近似成年存活率。这个换算不做迭代几轮后总量会明显偏离而且偏离方向还不直观属于典型的玄学偏差。提示性别比明显偏离1的地区女儿比例不要简单除以2用出生性别比单独算否则长期预测会系统性偏高或偏低。3. 用MATLAB把Leslie模型跑起来3.1 构造矩阵与逐年迭代的最小实现数据齐了构造矩阵就是填两个位置。下面这段是完整的迭代核心输入是初始女性人口向量和三个参数向量输出是每年每步的总人口和年龄结构function [N_total, N_hist] leslie_run(pop_f, surv, fert, steps) % pop_f : k×1 初始各年龄组女性人口 % surv : k×1 各年龄组存活率 % fert : k×1 各年龄组生育率 % steps : 迭代步数 k numel(pop_f); L zeros(k, k); L(1, :) fert(:); % 第一行生育率 for i 1:k-1 L(i1, i) surv(i); % 次对角线存活率 end N_hist zeros(k, steps1); N_hist(:,1) pop_f(:); for t 1:steps N_hist(:, t1) L * N_hist(:, t); end N_total sum(N_hist, 1); % 每步女性总人口 end逻辑说明L(1,:)一次性把生育率铺到第一行for循环把存活率放到次对角线这是Leslie矩阵的标准形态。迭代部分就是反复左乘没有别的花样。N_hist存的是每一步的完整年龄结构不只是总量——这一点很重要因为Leslie模型的价值恰恰在结构只存总量等于白跑。参数说明steps是迭代步数如果时间步是5年steps10就是预测50年。surv的最后一组在上一节已经置0所以矩阵最后一行全0意味着最高年龄组的人下一步全部退出这是合理的封闭人口假设。3.2 主特征值与长期趋势的读法Leslie矩阵有个漂亮的性质当迭代步数足够多人口结构会收敛到一个稳定的年龄分布总量按矩阵的主特征值 $\lambda_1$ 等比增长。$\lambda_1 1$ 长期增长$1$ 长期衰减$1$ 稳定。这个特征值就是长期增长率对应的特征向量就是稳定年龄结构。[V, D] eig(L); lambda diag(D); [lambda_max, idx] max(real(lambda)); stable_struct real(V(:, idx)); stable_struct stable_struct / sum(stable_struct); % 归一化为比例 fprintf(主特征值 lambda1 %.4f\n, lambda_max); fprintf(长期年增长率约 %.2f%%\n, (lambda_max^(1/5)-1)*100); % 步长5年换算这里有个容易忽略的点eig返回的特征值可能是复数取实部再找最大是常规操作因为Leslie矩阵是非负矩阵由Perron-Frobenius定理主特征值一定是正实数。换算年增长率时如果步长是5年要开5次方再减1直接拿 $\lambda_1-1$ 当年度增长率是错的会高估好几倍。3.3 结果可视化与结构演化光看总量曲线不够Leslie模型最该看的是年龄结构怎么随时间变形。我一般画两张图一张总量随时间的曲线一张用热力图或堆叠面积图展示各年龄组占比的演化。figure; subplot(1,2,1); plot(0:steps, N_total, LineWidth, 1.5); xlabel(时间步每步5年); ylabel(女性总人口); title(总量演化); grid on; subplot(1,2,2); prop N_hist ./ sum(N_hist, 1); % 各年龄组占比 imagesc(prop); colorbar; xlabel(时间步); ylabel(年龄组); title(年龄结构演化);prop那一步是逐列归一化得到每个时间点上各年龄组的占比。热力图能一眼看出老龄化是不是在加剧、育龄段占比是不是在萎缩。这比单看总量有信息量得多也是Leslie相对Logistic的核心优势所在。4. 参数敏感性、情景对比与常见误用4.1 生育率假设怎么设才不拍脑袋Leslie模型最容易被质疑的就是生育率假设——它直接决定长期结果而未来生育率谁也说不准。稳妥做法是不设单一情景而是设高、中、低三档跑出包络区间。中档可以取当前水平或略降高档假设政策激励见效回升低档假设继续下滑。三档跑完结论表述成「在低方案下2050年总量为X高方案为Y」而不是给一个点估计。fert_low fert * 0.7; fert_mid fert; fert_high fert * 1.3; [~, ~, N_low] deal(0); % 占位实际调用 leslie_run [Nt_low, ~] leslie_run(pop_f, surv, fert_low, steps); [Nt_mid, ~] leslie_run(pop_f, surv, fert_mid, steps); [Nt_high, ~] leslie_run(pop_f, surv, fert_high, steps); plot(0:steps, Nt_low, --, 0:steps, Nt_mid, -, 0:steps, Nt_high, --); legend(低方案,中方案,高方案);三档的倍数不是随便定的要结合历史波动幅度。如果过去二十年生育率波动在正负30%以内那用0.7和1.3就是合理的包络如果波动更大包络要相应放宽。这一步的严谨程度直接决定结论可信度。4.2 存活率随时间的改进要不要建模很多入门实现把存活率当成常数跑几十年不变。这在短期可以长期会低估寿命改善带来的老年人口累积。常见做法是给存活率加一个随时间缓慢上升的改进因子比如每年提升0.1%到0.3%或者直接引用权威机构的分年龄死亡率预测。加改进因子后矩阵每步都要重建不能再用一个固定 $L$ 迭代到底。surv_t surv; for t 1:steps surv_t min(surv_t * 1.002, 0.999); % 每年存活率改进0.2% L build_leslie(fert, surv_t); % 每步重建矩阵 N_hist(:, t1) L * N_hist(:, t); endmin(..., 0.999)是防止存活率被改进到超过1这种物理上不可能的值。这个细节不注意跑几十步后会出现存活率大于1的荒谬结果然后总量爆炸排查起来很费时间。4.3 和Logistic混用的边界在哪有人会想能不能把Leslie和Logistic结合用Logistic的环境容量去约束Leslie的总量可以但要清楚代价。Leslie本身是线性模型不含密度制约长期要么指数增长要么指数衰减。加容量约束相当于在每步迭代后按Logistic方式压缩总量这会破坏年龄结构的自洽性——压缩是均匀施加还是按年龄加权结果差别很大而且没有公认标准。我的建议是如果研究期在二三十年以内纯Leslie够用如果非要引入容量明确写出压缩规则并做敏感性分析别默认它无害。5. 避坑与排查Leslie模型跑出来不对劲时先看这几条5.1 总量第一步就跳变现象初始向量代进去第一步总量就和初始值差很多。原因生育率或存活率的单位口径和步长不匹配比如年度生育率没乘步长或者存活率用了千分比没除以1000。解决把L打印出来逐行核对第一行的量级和次对角线的取值范围存活率必须在0到1之间生育率量级要和人口数匹配。5.2 迭代若干步后出现负数或NaN现象跑着跑着人口出现负值或NaN。原因存活率被改进因子推过1或者生育率里混入了负值或者初始向量里有NaN没清理。解决迭代前加assert(all(surv0 surv1))和assert(all(fert0))把非法值挡在门外比事后排查省事得多。5.3 主特征值和总量曲线对不上现象算出来的 $\lambda_1$ 大于1但总量曲线却在下降。原因多半是迭代步数太少还没进入主特征值主导的稳定段前期的结构瞬态还在起作用。解决把步数拉长到50步以上再看趋势或者直接看最后若干步的比值是否收敛到 $\lambda_1$。5.4 年龄结构占比之和不为1现象归一化后的年龄结构加起来不是1。原因N_hist某列全为0导致除零或者归一化时用了错误的维度。解决归一化前检查sum(N_hist,1)是否全为正用prop N_hist ./ sum(N_hist,1)而不是手动循环维度对不上会直接报错而不是静默出错。5.5 预测结果对初始年龄结构过度敏感现象只微调初始年龄结构长期总量就明显变化。原因如果初始结构和稳定结构差得远前期会有较大的瞬态振荡这是模型本身的特性不是bug。解决报告结果时区分短期受初始结构影响大和长期受生育率存活率主导别把短期波动当成长期趋势。6. 把Leslie模型做成可复用的预测工具跑通一次不难难的是让它变成一个换数据就能用、换情景就能比的小工具。我自己的习惯是把整个流程拆成三个函数prepare_data负责读数据和对齐年龄组build_leslie负责构造矩阵leslie_run负责迭代和输出。主脚本只做参数设定和调用不掺计算逻辑。这样换一个地区的数据只改prepare_data里的读取路径和分组边界其余不动。再进一步把情景对比也封装起来。下面这个函数接收一组生育率情景返回每个情景的总量矩阵方便直接画包络图function Nt_all leslie_scenarios(pop_f, surv, fert_base, steps, factors) % factors: 情景倍数向量如 [0.7 1.0 1.3] n_scen numel(factors); Nt_all zeros(steps1, n_scen); for j 1:n_scen [Nt, ~] leslie_run(pop_f, surv, fert_base*factors(j), steps); Nt_all(:, j) Nt(:); end end验证方法上我一般做两件事。一是拿历史数据回测用十年前的初始结构和当时的生育率存活率跑十年和实际人口对比看偏差在不在可接受范围。二是做守恒检查在没有生育、存活率全为1的极端设定下总量应该保持不变如果变了说明矩阵构造有错。这两个检查花不了多少时间但能挡掉大部分低级错误。一个具体技巧是给结果加时间戳和参数快照。每次跑完把fert、surv、steps和结果一起存成.mat文件文件名带上日期。过几个月回头看某个结论能立刻知道当时用的什么参数不用靠记忆。这个习惯救过我很多次尤其是当同一批数据被不同人改过之后。说到底Leslie模型的价值不在矩阵本身——它简单到几行代码就能实现——而在于它逼你把年龄结构、生育率、存活率这些真正决定人口走向的量摆到台面上而不是用一条拟合曲线糊弄过去。参数怎么设、情景怎么分、结果怎么读这些判断才是功夫所在。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站