读者答疑 | 两种SPI标准降水指数的计算方法

文摘   2024-07-01 10:00   四川  



前言



近日有读者留言询问Python如何计算SPI

在应对气候变化和极端天气事件日益频繁的当下,准确评估降水变化对于水资源管理、农业规划、灾害预警等领域至关重要。
SPI(Standard Precipitation Index,标准降水指数)作为一种国际公认的衡量降水异常程度的指标,被广泛应用于气候领域。

SPI计算原理是将某时间尺度(如1、3、6、12个月等)降水量的连续时间序列(最好是长期记录,一般最少30年)看作服从某种概率密度函数分布(如gamma分布),然后推导出相应的累积概率函数,再通过累积概率函数转换为标准正态分布。转换之后,某时间尺度样本的SPI为:该样本降水量的累积概率所对应的标准正态分布的x轴的值。
https://www.cnblogs.com/misakayier/articles/16035429.html

本文旨在探讨并比较两种计算SPI的主流方法,即利用standard_precip库和gma库进行实现。这两种方法各有特色,不仅能够满足不同用户的技术需求,也体现了开源软件在气象数据分析领域的广泛应用与价值。







standard_precip



In [4]:
import pandas as pdfrom standard_precip import spi

读取降水月数据

In [5]:
df_rainfall = pd.read_csv('/home/mw/project/wichita_rain.csv')df_rainfall.head()
Out[5]:

使用 Gamma 分布和 L 矩计算每月 SPI(1 个月)
In [6]:
spi_rain = spi.SPI()spi_monthly = spi_rain.calculate(df_rainfall, 'date', 'precip', freq="M", scale=1, 
fit_type="lmom", dist_type="gam")spi_monthly.head()
Out[6]:

使用 Gamma 分布和 MLE 计算每月 SPI(3 个月)

In [7]:
spi_3monthly = spi_rain.calculate(df_rainfall, 'date', 'precip', freq="M", scale=3, 
fit_type="mle", dist_type="gam")
spi_3monthly.head()

Out






绘图



In [8]:
import matplotlib.pyplot as pltfig = plt.figure(figsize = (10,8))# 绘图
# 获取日期的索引并选取特定间隔的日期作为标签date_indices = spi_3monthly.index[::120] # freq 是你的频率,例如每隔7天选取一个日期selected_dates = spi_3monthly.loc[date_indices, 'date']
plt.plot(spi_3monthly.date, # x轴数据 spi_3monthly.precip_scale_3_calculated_index, # y轴数据 linestyle = '-', # 折线类型 linewidth = 2, # 折线宽度 color = 'steelblue', # 折线颜色 marker = 'o', # 点的形状 markersize = 6, # 点的大小 markeredgecolor='black', # 点的边框色 markerfacecolor='brown') # 点的填充色
# 添加标题和坐标轴标签plt.title('SPI3')plt.xlabel('日期')plt.ylabel('SPI')# 剔除图框上边界和右边界的刻度plt.tick_params(top = 'off', right = 'off')
# 显示图形plt.show()






gma




读取月数据

In [9]:
from gma import climet
Data = pd.read_csv('/home/mw/project/wichita_rain.csv')
PRE = Data['precip'].values
# 分别计算1个月、3个月、6个月、12个月、24个月、60个月尺度的 SPI 指数SPI1 = climet.Index.SPI(PRE)SPI3 = climet.Index.SPI(PRE, Scale = 3)SPI6 = climet.Index.SPI(PRE, Scale = 6)SPI12 = climet.Index.SPI(PRE, Scale = 12)SPI24 = climet.Index.SPI(PRE, Scale = 24)SPI60 = climet.Index.SPI(PRE, Scale = 60)
In [10]:
data = {    'date': Data['date'],    'SPI1': SPI1,    'SPI3': SPI3,    'SPI6': SPI6,    'SPI12': SPI12,    'SPI24': SPI24,    'SPI60': SPI60,}
# 将数据转换为DataFramedf = pd.DataFrame(data)df






绘图



In [11]:
fig = plt.figure(figsize = (12,8))# 绘图
# 获取日期的索引并选取特定间隔的日期作为标签date_indices = df.index[::120] # freq 是你的频率,例如每隔7天选取一个日期selected_dates = df.loc[date_indices, 'date']
plt.plot(df.date, # x轴数据 df.SPI3, # y轴数据 linestyle = '-', # 折线类型 linewidth = 2, # 折线宽度 color = 'steelblue', # 折线颜色 marker = 'o', # 点的形状 markersize = 6, # 点的大小 markeredgecolor='black', # 点的边框色 markerfacecolor='brown') # 点的填充色
# 添加标题和坐标轴标签plt.title('SPI3')plt.xlabel('日期')plt.ylabel('SPI')plt.xticks(date_indices, selected_dates, rotation=45)# 剔除图框上边界和右边界的刻度plt.tick_params(top = 'off', right = 'off')
# 显示图形plt.show()





小结



结果上看两者是比较接近的,指数大部分在[-2,2]区间内

standard_precip在06年左右有一较为突出的点,gma计算结果没有,可能内部做了平滑

代码无疑是gma库更加简洁





第八星系人造大气理论爱好者
记录与交流python、matlab等科研工具。记录与交流大气科学的学科知识
 最新文章