基于长时间序列的模拟数据集(1990-2022年)利用 Python实现长时序逐月标准化降水指数 SPI(SPI-1)计算与绘图

目录

一、依赖库与环境配置

(一)导入依赖库

(二)中文字体配置

[二、SPI 计算核心函数解析](#二、SPI 计算核心函数解析)

(一)函数定义与逻辑框架

(二)关键算法说明

[三、数据生成与 SPI 计算流程](#三、数据生成与 SPI 计算流程)

(一)生成时间序列与模拟降水数据

[(二)计算 SPI-1 并组织数据](#(二)计算 SPI-1 并组织数据)

四、可视化模块详细解析

(一)绘图基础设置

[(二)干旱 / 湿润等级阈值线绘制](#(二)干旱 / 湿润等级阈值线绘制)

(三)坐标轴与图表样式优化

(四)图例与布局调整

五、高清晰度图片保存功能

(一)目录创建与路径处理

(二)图片保存参数详解

六、总结

七、运行结果


若觉得代码对您的研究 / 项目有帮助,欢迎点击打赏支持!需要完整代码的朋友,打赏后可在后台私信(复制文章标题发给我),我会尽快发您完整可运行代码,感谢支持!

本代码基于 Python 数据科学生态库(NumPy、Pandas、Matplotlib、SciPy),实现三大核心功能:

  • 生成 1990-2022 年逐月模拟降水数据(服从 Gamma 分布);
  • 计算标准化降水指数(SPI-1,即 1 个月尺度 SPI);
  • 可视化 SPI-1 时间序列,标注不同干旱 / 湿润等级阈值,并保存高清晰度图片。

SPI(Standardized Precipitation Index)是衡量干旱程度的常用指标,通过将降水数据标准化为正态分布(均值 0、标准差 1),使不同地区、不同时段的降水异常程度具有可比性。

一、依赖库与环境配置

(一)导入依赖库

python 复制代码
import numpy as np  # 数值计算(数组操作、随机数生成)
import pandas as pd  # 数据处理(时间序列、DataFrame管理)
import matplotlib.pyplot as plt  # 绘图可视化
import scipy.stats as stats  # 统计分析(分布拟合、分位数计算)
import os  # 文件路径与目录管理

各库核心作用:

  • **NumPy:**处理降水数据数组、替换无效值;
  • **Pandas:**生成时间序列、组织 SPI 结果为表格格式;
  • **Matplotlib:**绘制 SPI 趋势图、阈值线、图例等;
  • **SciPy.stats:**拟合 Gamma 分布、计算累积概率(CDF)、转换正态分布分位数;
  • **os:**创建保存目录、处理文件路径。

(二)中文字体配置

python 复制代码
plt.rcParams['font.sans-serif'] = ['SimHei']  # 解决中文显示乱码(Windows系统)
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示异常

注: 不同系统需适配字体(如 macOS 用'Arial Unicode MS',Linux 用'WenQuanYi Zen Hei')。

二、SPI 计算核心函数解析

(一)函数定义与逻辑框架

python 复制代码
def calculate_spi(data):
    """
    简易SPI计算逻辑(核心三步):
    1. 处理无效降水数据(0值替换)
    2. 拟合Gamma分布(描述降水数据统计特征)
    3. 转换为标准正态分布Z分数(即SPI值)
    """
    # 步骤1:处理0值(降水为0时无法拟合Gamma分布,替换为极小值)
    data = np.where(data <= 0, 0.01, data)
    
    # 步骤2:拟合Gamma分布参数(shape=形状参数,loc=位置参数,scale=尺度参数)
    shape, loc, scale = stats.gamma.fit(data, floc=0)  # 固定位置参数为0(降水非负)
    
    # 步骤3:计算累积概率(CDF)并转换为SPI
    cdf = stats.gamma.cdf(data, shape, loc, scale)  # 每个数据点的累积概率(0-1)
    spi = stats.norm.ppf(cdf)  # 概率转换为标准正态分布分位数(Z分数)
    return spi

(二)关键算法说明

  • Gamma 分布拟合: 降水数据(非零)通常服从 Gamma 分布,通过stats.gamma.fit估计分布参数,是 SPI 计算的核心前提;
  • **累积概率(CDF):**表示某一降水量小于等于当前值的概率,反映降水在历史序列中的相对位置;
  • 正态转换: 通过stats.norm.ppf(分位数函数)将 [0,1] 区间的概率转换为标准正态分布的 Z 分数,即 SPI 值(SPI=0 为平均水平,正值为湿润,负值为干旱)。

三、数据生成与 SPI 计算流程

(一)生成时间序列与模拟降水数据

python 复制代码
# 生成1990-2022年逐月时间索引(freq='ME'表示月末频率,修复Pandas兼容性警告)
dates = pd.date_range(start='1990-01-01', end='2022-12-31', freq='ME')

# 设置随机种子(保证结果可重复)
np.random.seed(42)

# 模拟月降水量(Gamma分布:shape=2.0,scale=50.0,均值≈shape×scale=100mm)
precip = np.random.gamma(shape=2.0, scale=50.0, size=len(dates))
  • **时间序列:**共 33 年(1990-2022),每月 1 个数据点,总计 396 个数据;
  • **降水模拟:**Gamma 分布的 shape 和 scale 参数决定降水分布特征,此处模拟均值约 100mm 的月降水(符合温带地区平均水平)。

(二)计算 SPI-1 并组织数据

python 复制代码
# 计算1个月尺度SPI(SPI-1)
spi_values = calculate_spi(precip)

# 构建DataFrame(便于后续绘图与数据管理)
df = pd.DataFrame({'Date': dates, 'SPI1': spi_values})

DataFrame 结构: 两列(Date为时间,SPI1为对应月份的 SPI 值),行索引为数据序号。

四、可视化模块详细解析

(一)绘图基础设置

python 复制代码
# 创建画布(figsize=宽×高,单位英寸;dpi=显示分辨率)
plt.figure(figsize=(16, 6), dpi=100)

# 绘制SPI-1时间序列折线
plt.plot(df['Date'], df['SPI1'], color='darkblue', linewidth=1.2, label='SPI-1')
  • **画布尺寸:**16×6 英寸(宽屏适合时间序列展示);
  • **折线样式:**深蓝色、线宽 1.2,标注图例为 "SPI-1"。

(二)干旱 / 湿润等级阈值线绘制

python 复制代码
# 定义阈值参数:(SPI值, 颜色, 线型, 标签)
thresholds = [
    (2.0, 'navy', '--', '极端湿润 (SPI ≥ 2.0)'),
    (1.5, 'royalblue', '--', '严重湿润 (SPI ≥ 1.5)'),
    (1.0, 'lightblue', '--', '中等湿润 (SPI ≥ 1.0)'),
    (-1.0, 'orange', '--', '中等干旱 (SPI ≤ -1.0)'),
    (-1.5, 'red', '--', '严重干旱 (SPI ≤ -1.5)'),
    (-2.0, 'brown', '--', '极端干旱 (SPI ≤ -2.0)'),
]

# 循环绘制各阈值线(水平虚线)
for val, color, style, label in thresholds:
    plt.axhline(y=val, color=color, linestyle=style, linewidth=1, label=label)

# 绘制SPI=0基准线(黑色实线,区分湿润与干旱)
plt.axhline(y=0, color='black', linewidth=0.8)

阈值标准说明(国际通用 SPI 等级):

SPI 范围 等级 颜色
≥2.0 极端湿润 藏青色
1.5-2.0 严重湿润 宝蓝色
1.0-1.5 中等湿润 浅蓝色
-1.0-1.0 正常 -
-1.5--1.0 中等干旱 橙色
-2.0--1.5 严重干旱 红色
≤-2.0 极端干旱 棕色

(三)坐标轴与图表样式优化

python 复制代码
# 设置Y轴范围(聚焦主要异常区间,避免极端值拉伸图表)
plt.ylim(-2.8, 2.8)
# 设置X轴范围(覆盖完整时间序列)
plt.xlim(df['Date'].min(), df['Date'].max())

# 坐标轴标签与标题
plt.ylabel('SPI-1', fontsize=12)
plt.title('1990 - 2022年逐月标准化降水指数(SPI-1)', fontsize=14, pad=20)

# X轴刻度优化(每2年显示一次,旋转45°避免重叠)
xtick_dates = pd.date_range(start='1990-12-31', end='2022-12-31', freq='2YE')
plt.xticks(xtick_dates, [d.strftime('%Y-%m-%d') for d in xtick_dates], rotation=45)

# 网格线(细点线,透明度0.6,不干扰主线)
plt.grid(True, linestyle=':', alpha=0.6)

(四)图例与布局调整

python 复制代码
# 图例设置(顶部居中,4列分布,带阴影边框)
plt.legend(loc='upper center', bbox_to_anchor=(0.5, 1.05),
           ncol=4, frameon=True, shadow=True, fontsize=9)

# 自动调整布局(避免标题、图例被截断)
plt.tight_layout()

**图例优化逻辑:**因阈值线较多(6 条),采用 4 列布局避免纵向占用过多空间,提升图表整洁度。

五、高清晰度图片保存功能

(一)目录创建与路径处理

python 复制代码
# 定义保存目录(统一管理图片文件)
save_dir = 'SPI_figures'
# 若目录不存在则创建(避免保存失败)
if not os.path.exists(save_dir):
    os.makedirs(save_dir)

# 构建保存路径(目录+文件名,支持png/jpg/svg格式)
save_path = os.path.join(save_dir, '1990-2022_SPI-1_600dpi.png')

(二)图片保存参数详解

python 复制代码
plt.savefig(
    save_path,
    dpi=600,        # 核心参数:600DPI(高清晰度,满足论文/报告使用)
    bbox_inches='tight',  # 自动裁剪多余空白,避免图例/标题被截断
    facecolor='white',    # 背景色设为白色(默认透明,适配多数文档场景)
    edgecolor='none'      # 去除图片边框
)

# 打印保存路径(方便用户查找文件)
print(f"图片已保存至:{os.path.abspath(save_path)}")

# 显示图片(保存后再显示,不影响图片质量)
plt.show()
  • **DPI 设置:**600DPI 为学术图表常用分辨率,高于 300DPI 的 "印刷级" 标准;
  • **背景色:**白色背景避免插入文档时出现透明区域与正文冲突;
  • **bbox_inches='tight':**解决 Matplotlib 默认布局下图例 / 标题超出画布的问题。

六、总结

优点:

  • **流程完整:**从数据生成、SPI 计算到可视化、保存一站式实现;
  • 兼容性强: 修复 Pandas 频率字符串警告(M→MEY→YE),适配新版本库;
  • **可视化专业:**阈值线颜色与等级对应清晰,图例、刻度优化提升可读性;
  • **实用性高:**支持高清晰度图片保存,满足学术与业务场景需求。

局限性与改进方向:

  • **数据处理简化:**将 0 降水替换为 0.01 仅为简易处理,实际应分离 "无降水" 与 "有降水" 数据分别计算;
  • **分布拟合:**未进行 Gamma 分布拟合优度检验(如 KS 检验),需验证数据是否符合 Gamma 分布;
  • **实际应用:**模拟数据需替换为真实站点 / 格点降水数据,且需考虑数据缺失值填补。

七、运行结果

1990-2022 年逐月 SPI-1 计算与可视化结果

若觉得代码对您的研究 / 项目有帮助,欢迎点击打赏支持!需要完整代码的朋友,打赏后可在后台私信(复制文章标题发给我),我会尽快发您完整可运行代码,感谢支持!

相关推荐
@HNUSTer8 天前
基于 30 年月尺度长时间序列的降水和气温模拟数据集的 SPI、SPEI 与 PET 实现
长时间序列·降水和气温·模拟数据集·spi(标准化降水指数)·spei(标准化降水蒸散指数)·pet(潜在蒸发散)·pnp(正常降水百分比)
博弈星宇2 年前
Python数据分析-5
python 数据分析
zmjia1112 年前
R语言环境下MaxEnt模型的优化策略与物种分布模拟
开发语言·r语言·气象·植被·多时间尺度·气象干旱·maxent
博弈星宇2 年前
Python数据分析-4
python 数据分析