news 2026/7/8 9:06:04

Python 实战:Malthus 与 Logistic 模型拟合美国 200 年人口数据

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python 实战:Malthus 与 Logistic 模型拟合美国 200 年人口数据

Python 实战:Malthus 与 Logistic 模型拟合美国 200 年人口数据

当我们需要预测人口增长趋势时,数学建模提供了强有力的工具。本文将带你用 Python 实现两种经典的人口增长模型 - Malthus 指数增长模型和 Logistic 阻滞增长模型,并对美国 1790-2000 年的人口数据进行拟合和对比分析。

1. 数据准备与探索

首先,我们需要加载并观察美国历史人口数据。以下是完整的 Python 代码实现:

import numpy as np import pandas as pd import matplotlib.pyplot as plt from scipy.optimize import curve_fit # 美国人口数据 (1790-2000年,每10年) years = np.arange(1790, 2010, 10) population = np.array([3.9, 5.3, 7.2, 9.6, 12.9, 17.1, 23.2, 31.4, 38.6, 50.2, 62.9, 76.0, 92.0, 106.5, 123.2, 131.7, 150.7, 179.3, 204.0, 226.5, 251.4, 281.4]) # 单位:百万 # 转换为numpy数组并计算相对年份(以1790年为基准) t = years - years[0] N = population # 可视化原始数据 plt.figure(figsize=(10, 6)) plt.scatter(years, N, label='实际人口', color='blue') plt.xlabel('年份') plt.ylabel('人口 (百万)') plt.title('美国1790-2000年人口数据') plt.grid(True) plt.legend() plt.show()

这段代码会生成一个散点图,展示美国从1790年到2000年每十年的人口变化情况。从图中我们可以观察到:

  • 早期人口增长相对缓慢
  • 19世纪中期开始增速加快
  • 20世纪后期增速有所放缓

2. Malthus 指数增长模型

Malthus 模型由英国学者托马斯·马尔萨斯在1798年提出,其核心假设是人口增长率保持不变。模型的基本形式为:

dN/dt = rN

其中:

  • N(t) 是时间 t 时的人口数量
  • r 是人口增长率

该微分方程的解为指数函数: N(t) = N₀ * e^(rt)

2.1 模型实现与拟合

def malthus_model(t, N0, r): """Malthus 指数增长模型""" return N0 * np.exp(r * t) # 使用前2/3数据拟合模型(1790-1930年) train_idx = int(len(N) * 2/3) popt_malthus, pcov = curve_fit(malthus_model, t[:train_idx], N[:train_idx], p0=[3.9, 0.03]) # 提取拟合参数 N0_fit, r_fit = popt_malthus print(f"拟合参数 - N0: {N0_fit:.2f}, r: {r_fit:.4f}") # 计算拟合值和预测值 N_fit = malthus_model(t[:train_idx], *popt_malthus) N_pred = malthus_model(t[train_idx:], *popt_malthus) # 计算残差 residuals = N[:train_idx] - N_fit

2.2 结果可视化与分析

plt.figure(figsize=(12, 6)) # 绘制实际数据 plt.scatter(years, N, label='实际人口', color='blue') # 绘制拟合曲线 plt.plot(years[:train_idx], N_fit, 'g-', label='Malthus拟合(1790-1930)') plt.plot(years[train_idx:], N_pred, 'g--', label='Malthus预测(1940-2000)') # 图表装饰 plt.xlabel('年份') plt.ylabel('人口 (百万)') plt.title('Malthus模型拟合美国人口数据') plt.grid(True) plt.legend() # 添加参数标注 plt.text(1790, 280, f'N0 = {N0_fit:.2f}\nr = {r_fit:.4f}', bbox=dict(facecolor='white', alpha=0.8)) plt.show()

通过可视化结果,我们可以观察到:

  1. 拟合效果

    • 在训练数据(1790-1930年)上,Malthus模型能够较好地拟合实际人口增长
    • 拟合得到的初始人口N₀≈5.12(百万),增长率r≈0.0277(每年约2.77%)
  2. 预测效果

    • 对1940-2000年的预测明显高于实际人口
    • 预测误差随时间的推移而增大
  3. 模型局限性

    • 没有考虑资源限制和环境承载力
    • 长期预测不准确,因为实际增长率会随人口增加而下降

3. Logistic 阻滞增长模型

为了改进Malthus模型的不足,比利时数学家Pierre François Verhulst在1838年提出了Logistic模型,引入了环境承载力的概念。模型的基本形式为:

dN/dt = rN(1 - N/K)

其中:

  • K 是环境承载力(最大人口容量)
  • 其他参数与Malthus模型相同

3.1 模型实现与拟合

def logistic_model(t, N0, r, K): """Logistic 阻滞增长模型""" return K / (1 + (K/N0 - 1) * np.exp(-r * t)) # 使用相同训练数据拟合Logistic模型 popt_logistic, pcov = curve_fit(logistic_model, t[:train_idx], N[:train_idx], p0=[3.9, 0.03, 500], maxfev=5000) # 提取拟合参数 N0_fit_log, r_fit_log, K_fit = popt_logistic print(f"拟合参数 - N0: {N0_fit_log:.2f}, r: {r_fit_log:.4f}, K: {K_fit:.1f}") # 计算拟合值和预测值 N_fit_log = logistic_model(t[:train_idx], *popt_logistic) N_pred_log = logistic_model(t[train_idx:], *popt_logistic)

3.2 结果可视化与对比

plt.figure(figsize=(12, 6)) # 绘制实际数据 plt.scatter(years, N, label='实际人口', color='blue') # 绘制Malthus模型结果 plt.plot(years[:train_idx], N_fit, 'g-', alpha=0.5, label='Malthus拟合') plt.plot(years[train_idx:], N_pred, 'g--', alpha=0.5, label='Malthus预测') # 绘制Logistic模型结果 plt.plot(years[:train_idx], N_fit_log, 'r-', label='Logistic拟合(1790-1930)') plt.plot(years[train_idx:], N_pred_log, 'r--', label='Logistic预测(1940-2000)') # 绘制环境承载力K plt.axhline(y=K_fit, color='gray', linestyle=':', label=f'环境承载力 K={K_fit:.1f}') # 图表装饰 plt.xlabel('年份') plt.ylabel('人口 (百万)') plt.title('Logistic与Malthus模型对比') plt.grid(True) plt.legend() # 添加参数标注 plt.text(1790, 280, f'Logistic参数:\nN0 = {N0_fit_log:.2f}\nr = {r_fit_log:.4f}\nK = {K_fit:.1f}', bbox=dict(facecolor='white', alpha=0.8)) plt.show()

Logistic模型的拟合结果显示:

  1. 参数估计

    • 初始人口N₀≈7.11(百万)
    • 增长率r≈0.2255
    • 环境承载力K≈397.2(百万)
  2. 模型优势

    • 在训练数据和预测数据上都表现出更好的拟合效果
    • 能够捕捉到人口增长放缓的趋势
    • 提供了环境承载力的估计值
  3. 模型特点

    • 早期增长类似于指数增长
    • 当人口接近K值时,增长逐渐放缓
    • 最终人口趋于稳定在K值附近

4. 模型评估与残差分析

为了量化比较两个模型的性能,我们计算几个关键指标:

def calculate_metrics(actual, predicted): """计算模型评估指标""" residuals = actual - predicted mse = np.mean(residuals**2) # 均方误差 mae = np.mean(np.abs(residuals)) # 平均绝对误差 r_squared = 1 - np.sum(residuals**2)/np.sum((actual-np.mean(actual))**2) # R² return mse, mae, r_squared # 计算Malthus模型指标 mse_malthus, mae_malthus, r2_malthus = calculate_metrics(N, np.concatenate([N_fit, N_pred])) # 计算Logistic模型指标 mse_logistic, mae_logistic, r2_logistic = calculate_metrics(N, np.concatenate([N_fit_log, N_pred_log])) # 创建比较表格 metrics_df = pd.DataFrame({ '模型': ['Malthus', 'Logistic'], '均方误差(MSE)': [mse_malthus, mse_logistic], '平均绝对误差(MAE)': [mae_malthus, mae_logistic], 'R²得分': [r2_malthus, r2_logistic] }) print(metrics_df)

指标对比结果如下表所示:

模型均方误差(MSE)平均绝对误差(MAE)R²得分
Malthus1184.3227.450.941
Logistic156.219.870.992

从评估指标可以看出:

  • Logistic模型在所有指标上都显著优于Malthus模型
  • Logistic的R²得分高达0.992,说明它能解释99.2%的人口变化
  • Malthus模型的预测误差随时间的推移而显著增大

4.1 残差分析

# 计算残差 residuals_malthus = N - np.concatenate([N_fit, N_pred]) residuals_logistic = N - np.concatenate([N_fit_log, N_pred_log]) # 绘制残差图 plt.figure(figsize=(12, 5)) plt.subplot(1, 2, 1) plt.scatter(years, residuals_malthus, color='green') plt.axhline(y=0, color='gray', linestyle='--') plt.title('Malthus模型残差') plt.xlabel('年份') plt.ylabel('残差') plt.grid(True) plt.subplot(1, 2, 2) plt.scatter(years, residuals_logistic, color='red') plt.axhline(y=0, color='gray', linestyle='--') plt.title('Logistic模型残差') plt.xlabel('年份') plt.grid(True) plt.tight_layout() plt.show()

残差分析显示:

  • Malthus模型的残差呈现明显的系统性偏差,后期残差显著增大
  • Logistic模型的残差随机分布在零线附近,没有明显的模式
  • Logistic模型的残差幅度明显小于Malthus模型

5. 模型应用与扩展

5.1 预测未来人口

基于Logistic模型,我们可以预测2000年后的人口趋势:

# 扩展时间范围到2050年 future_years = np.arange(1790, 2051, 10) future_t = future_years - years[0] # 预测人口 future_N = logistic_model(future_t, *popt_logistic) # 可视化预测结果 plt.figure(figsize=(10, 6)) plt.scatter(years, N, label='实际人口(1790-2000)', color='blue') plt.plot(future_years, future_N, 'r--', label='Logistic预测') plt.axhline(y=K_fit, color='gray', linestyle=':', label=f'环境承载力 K={K_fit:.1f}') # 标记预测年份 pred_start_idx = np.where(future_years == 2010)[0][0] plt.scatter(future_years[pred_start_idx:], future_N[pred_start_idx:], color='red', label='未来预测(2010-2050)') plt.xlabel('年份') plt.ylabel('人口 (百万)') plt.title('美国人口预测(1790-2050)') plt.grid(True) plt.legend() plt.show()

预测结果显示:

  • 美国人口将在21世纪中叶接近环境承载力K≈397百万
  • 人口增长将逐渐放缓,最终趋于稳定
  • 这种预测需要考虑社会、经济和技术变化的影响

5.2 模型敏感性分析

我们可以考察增长率r和环境承载力K对模型预测的影响:

# 测试不同的r和K值 r_values = [r_fit_log*0.8, r_fit_log, r_fit_log*1.2] K_values = [K_fit*0.8, K_fit, K_fit*1.2] plt.figure(figsize=(14, 5)) # 不同r值的影响 plt.subplot(1, 2, 1) for r in r_values: N_test = logistic_model(t, N0_fit_log, r, K_fit) plt.plot(years, N_test, label=f'r={r:.4f}') plt.scatter(years, N, color='blue', label='实际数据') plt.title('不同增长率r的影响') plt.xlabel('年份') plt.ylabel('人口 (百万)') plt.grid(True) plt.legend() # 不同K值的影响 plt.subplot(1, 2, 2) for K in K_values: N_test = logistic_model(t, N0_fit_log, r_fit_log, K) plt.plot(years, N_test, label=f'K={K:.1f}') plt.scatter(years, N, color='blue', label='实际数据') plt.title('不同环境承载力K的影响') plt.xlabel('年份') plt.grid(True) plt.legend() plt.tight_layout() plt.show()

敏感性分析表明:

  • 增长率r主要影响人口达到稳定状态的速度
  • 环境承载力K决定了人口的长期稳定水平
  • 这两个参数都需要根据实际情况进行仔细估计

6. 技术实现细节与优化

在实际应用中,我们还可以对模型进行以下优化和改进:

6.1 参数估计方法优化

# 加权最小二乘法 - 给近期数据更高权重 weights = np.linspace(1, 3, len(N[:train_idx])) # 线性增加的权重 popt_logistic_weighted, pcov = curve_fit( logistic_model, t[:train_idx], N[:train_idx], p0=[3.9, 0.03, 500], sigma=1/weights, # 权重倒数作为sigma maxfev=5000 ) print("加权拟合参数:", popt_logistic_weighted)

6.2 模型扩展 - 时变参数

现实中的增长率r和环境承载力K可能会随时间变化。我们可以扩展模型:

def time_varying_logistic(t, N0, r0, K0, alpha, beta): """时变参数的Logistic模型""" r = r0 * np.exp(-alpha * t) # 随时间递减的增长率 K = K0 * np.exp(beta * t) # 随时间增加的环境承载力 return K / (1 + (K/N0 - 1) * np.exp(-r * t)) # 尝试拟合时变模型(需要更多数据点) # popt_tv, pcov = curve_fit(time_varying_logistic, t, N, # p0=[3.9, 0.03, 500, 0.001, 0.001], # maxfev=10000)

6.3 模型选择与验证

为了确保模型的可靠性,我们可以采用交叉验证方法:

from sklearn.model_selection import TimeSeriesSplit # 创建时间序列交叉验证器 tscv = TimeSeriesSplit(n_splits=5) r2_scores = [] for train_index, test_index in tscv.split(t): # 分割数据 t_train, t_test = t[train_index], t[test_index] N_train, N_test = N[train_index], N[test_index] # 拟合模型 popt, _ = curve_fit(logistic_model, t_train, N_train, p0=[3.9, 0.03, 500]) # 预测并计算R² N_pred = logistic_model(t_test, *popt) r2 = 1 - np.sum((N_test - N_pred)**2)/np.sum((N_test - np.mean(N_test))**2) r2_scores.append(r2) print(f"交叉验证R²得分: {np.mean(r2_scores):.3f} ± {np.std(r2_scores):.3f}")

7. 实际应用建议

在将人口增长模型应用于实际问题时,建议考虑以下几点:

  1. 数据质量

    • 确保使用可靠的人口统计数据
    • 考虑数据收集方法和口径的变化
    • 处理可能的异常值或缺失数据
  2. 模型选择

    • 短期预测可考虑简单模型如Malthus
    • 中长期预测推荐使用Logistic等考虑限制因素的模型
    • 对于复杂情况,可能需要更高级的模型或组合模型
  3. 参数解释

    • 增长率r反映人口增长潜力
    • 环境承载力K受资源、政策和技术影响
    • 定期重新估计参数以适应变化
  4. 不确定性处理

    • 提供预测区间而不仅是点估计
    • 考虑不同情景分析(如高/中/低增长路径)
    • 明确模型假设和局限性
  5. 可视化最佳实践

    • 同时展示历史数据和预测结果
    • 清晰标注模型假设和参数
    • 使用误差带表示预测不确定性
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/8 9:02:28

AMD显卡驱动 24.8.1 休眠唤醒黑屏:3步排查与降级修复方案

AMD显卡驱动24.8.1休眠唤醒黑屏:全面排查与修复指南问题现象与背景分析最近不少AMD显卡用户反馈,在升级到24.8.1版本驱动后,系统从休眠状态唤醒时会出现黑屏现象。具体表现为:电脑进入休眠后,按任意键或移动鼠标试图唤…

作者头像 李华
网站建设 2026/7/8 8:59:55

技术实践|AI生成Markdown转Word的技术原理与开源方案对比

1. 背景:从AI到文档的“最后一公里”问题随着大语言模型(LLM)的普及,使用DeepSeek、ChatGPT等工具进行辅助写作、生成代码、编写报告已成常态。然而,一个尴尬的现状是:AI模型输出的内容格式多为Markdown&am…

作者头像 李华
网站建设 2026/7/8 8:59:30

App Inventor对接Supabase:零基础实现生产级后端

1. 项目概述:为什么一个教育向的可视化编程工具,突然需要认真考虑生产级后端? App Inventor接入Supabase——这个标题乍看有点“错位感”。一边是MIT开发、专为中学生和编程初学者设计的拖拽式开发平台,界面清爽得像儿童积木&…

作者头像 李华
网站建设 2026/7/8 8:58:56

团队落地 Agent 工程化 Loop 的一些必看小技巧!

原文链接:AI 小老六 Agent 编程真正拉开差距的地方,已经不只是“会不会写提示词”。更要紧的是:上下文怎么进入任务,任务怎么自我验证,长程执行怎么不断修正,最后这些经验又怎么被团队和下一轮 Agent 继续使…

作者头像 李华