SPEI

The Standardized Precipitation Evapotranspiration Index (SPI) method fits a loglogistic distribution to the difference between precipitation and potential evapotranspiration values (P-PET), and maps the result to a normal distribution (z values), which correspond to the SPEI values. P-PET is usually resampled to one ore more months.

\(spei \geq 2.0\)

extremely wet

\(1.5 \leq spei < 2.0\)

very wet

\(1.0 \leq spei < 1.5\)

moderately wet

\(-1.0 \leq spei < 1.0\)

near normal

\(-1.5 \leq spei < -1.0\)

moderately dry

\(-2.0 \leq spei < -1.5\)

severely dry

\(spei \leq -2.0\)

extremely dry

Tutorial

P-PET refers to a time series of differences between precipitation and evapotranspiration of any frequency not higher than monthly (minutely, hourly, daily, weekly, or monthly).

spei()

Input is a list or numpy.array of P-PET values. The output is an array of same size with calculated SPEI values. Gaps in the input data (numpy.nan) are ignored and result a numpy.nan at the same position in the output array.

>>> import numpy as np
>>> import pandas as pd
>>> from caeli.drought_indices import spei, spei_monthly
>>> b = [236.78906908, 264.81174819, 206.07614488, 329.1471248, 229.76300328, 88.48107583,
...      222.12576411, 203.1740944, 194.24915861, 233.04840882, 203.03193236, 181.99807424,
...      228.55427209, 239.45338575, 316.16425044, 192.11761111, 173.18384051, 285.25591321,
...      275.19281235, 310.7161464, 348.84101779, 330.42774158, 163.55803563, 177.16544205,
...      359.67310805, 282.82742497, 191.03543726, 333.89194558, 163.25115185, 322.16858475]
>>> spei(b)
array([-0.05447834,  0.39161421, -0.55496029,  1.28044935, -0.16899123,
       -2.21208646, -0.29378891, -0.60177122, -0.74448836, -0.11538335,
       -0.60405976, -0.93656914, -0.18873257, -0.01121518,  1.11915418,
       -0.7782526 , -1.07149926,  0.69786961,  0.54963214,  1.04873009,
        1.50833784,  1.29587081, -1.21539086, -1.01091053,  1.62564314,
        0.66256868, -0.79534214,  1.33715757, -1.21991663,  1.19488129])
>>> b = [np.nan, 264.81174819, 206.07614488, 329.1471248, 229.76300328, 88.48107583,
...      222.12576411, 203.1740944, 194.24915861, 233.04840882, 203.03193236, 181.99807424,
...      228.55427209, 239.45338575, 316.16425044, 192.11761111, 173.18384051, 285.25591321,
...      275.19281235, 310.7161464, 348.84101779, 330.42774158, 163.55803563, 177.16544205,
...      359.67310805, 282.82742497, 191.03543726, 333.89194558, np.nan, 322.16858475]
>>> spei(b).round(1)
array([  nan,  0.32, -0.61,  1.24, -0.23, -2.18, -0.36, -0.65, -0.79,
       -0.18, -0.66, -0.98, -0.25, -0.08,  1.07, -0.82, -1.1 ,  0.64,
        0.48,  1.  ,  1.47,  1.25, -1.24, -1.05,  1.6 ,  0.6 , -0.84,
        1.3 ,   nan,  1.15])

spei_monthly()

Generating a pandas.DataFrame with random daily P-PET values:

>>> np.random.seed(1)
>>> index = pd.date_range('1990-01-01', '2019-12-31', freq='1d')
>>> values = np.random.normal(100, 70, len(index))
>>> values[values < 0] = 0.0
>>> df = pd.DataFrame({'P-PET': values}, index=index)

Given daily data, calculate monthly SPEI:

>>> df_spei = spei_monthly(df).round(1)
>>> with pd.option_context('display.max_rows', 4, 'display.max_columns', 8):
...     print(df_spei)
...
       P01   P02   P03   P04  ...  SPEI09  SPEI10  SPEI11  SPEI12
year                          ...
1990  30.3  29.5  35.5  29.4  ...     0.4    -0.3     1.2    -1.4
1991  32.1  28.7  39.4  29.7  ...    -0.4    -0.3     0.0    -0.6
...    ...   ...   ...   ...  ...     ...     ...     ...     ...
2018  32.1  25.5  33.2  33.9  ...     1.8     0.9    -1.0    -0.8
2019  23.9  28.7  30.8  37.6  ...     0.8    -0.7     0.7     1.3

[30 rows x 24 columns]

Given daily data, calculate monthly SPEI for accumulated three months:

>>> df_spei = spei_monthly(df, aggregation=3).round(1)
>>> with pd.option_context('display.max_rows', 4, 'display.max_columns', 8):
...     print(df_spei)
...
      P01-03  P02-04  P03-05  P04-06  ...  SPEI09-11  SPEI10-12  SPEI11-01  SPEI12-02
year                                  ...
1990    95.3    94.3   100.1    97.4  ...        0.7       -0.6       -0.2       -0.8
1991   100.2    97.8    98.5    91.5  ...       -0.4       -0.6       -0.4       -0.7
...      ...     ...     ...     ...  ...        ...        ...        ...        ...
2018    90.9    92.6    97.0    96.7  ...        1.2       -0.6       -2.0       -1.8
2019    83.3    97.0    99.2    97.4  ...        0.5        0.8        NaN        NaN

[30 rows x 24 columns]

Given daily data and list of months, calculate monthly SPI aggregating three months:

>>> df_spei = spei_monthly(df, aggregation=3, months=[1, 4, 7, 10]).round(1)
>>> with pd.option_context('display.max_rows', 4, 'display.max_columns', 8):
...     print(df_spei)
...
      P01-03  P04-06  P07-09  P10-12  SPEI01-03  SPEI04-06  SPEI07-09  SPEI10-12
year
1990    95.3    97.4   101.1    91.9        0.6        0.8        0.8       -0.6
1991   100.2    91.5   100.0    92.0        1.4       -0.3        0.6       -0.6
...      ...     ...     ...     ...        ...        ...        ...        ...
2018    90.9    96.7   100.8    91.7       -0.3        0.6        0.7       -0.6
2019    83.3    97.4    90.8    99.2       -1.8        0.7       -0.8        0.8

[30 rows x 8 columns]