Skip to main content

Standard Precipitation (Evapotranspiration) Index

CI PyPI GitHub license

Overview

This is a Python implementation for calculating the Standardized Precipitation Index (SPI) and the Standardized Precipitation Evapotranspiration Index (SPEI) — key indices for identifying droughts. See NCAR's Climate Data Guide for a useful discussion of the relative merits of SPI vs SPEI.

These functions are loosely based on the SPEI package in R by Santiago Beguería and Sergio M. Vicente-Serrano. The paper that most clearly describes the algorithm is:

Lloyd-Hughes, Benjamin, and Mark A. Saunders. "A drought climatology for Europe." International Journal of Climatology 22.13 (2002): 1571-1592.

This paper is included in the docs folder.

Distributions can be fit with either L-moments or Maximum Likelihood Estimation (MLE). L-moments is the recommended method — it is what NCAR's SPI calculators and R's SPI/SPEI packages use, and MLE can be unstable for some distributions and datasets. Indices can be calculated on daily, weekly, monthly, annual or any custom time grouping, at any scale (e.g. 3-month, 6-month), and optionally against a fixed baseline (reference) period.

Requires Python 3.10+.

Installation

pip install standard-precip

or with uv:

uv add standard-precip

Available distributions

Distribution L-moments MLE
Gamma :heavy_check_mark: :heavy_check_mark:
Exponential :heavy_check_mark: :heavy_check_mark:
Generalized Extreme Value :heavy_check_mark: :heavy_check_mark:
Generalized Pareto :heavy_check_mark: :heavy_check_mark:
Gumbel :heavy_check_mark: :heavy_check_mark:
Normal :heavy_check_mark: :heavy_check_mark:
Pearson III :heavy_check_mark: :heavy_check_mark:
Weibull :heavy_check_mark: :heavy_check_mark:
Generalized Logistic :heavy_check_mark: :heavy_check_mark:
Generalized Normal :heavy_check_mark: :heavy_check_mark:
Kappa :heavy_check_mark:¹ :heavy_check_mark:
Wakeby :heavy_check_mark: -

¹ Kappa L-moment ratios have no solution for some samples; affected groups yield NaN with a warning.

Note: for the Generalized Logistic, Generalized Normal and Kappa distributions, the L-moments fits use Hosking's distributions (via lmoments3) while the MLE fits use scipy's genlogistic, gennorm and kappa4. These are different parameterizations — parameters from one fit type are not interchangeable with the other.

Basic usage

For a more detailed walkthrough see the example notebook.

import pandas as pd
from standard_precip import SPI
from standard_precip.utils import plot_index

rainfall_data = pd.read_csv("data/monthly_data.csv")

spi = SPI()
df_spi = spi.calculate(
    rainfall_data, "date", "TotalPrecipitation", freq="M", scale=1, fit_type="lmom", dist_type="gam"
)

For a 3-month SPI, set scale=3 (the precipitation is summed over a 3-month rolling window and the result appears in a ..._scale_3_calculated_index column). precip_cols may also be a list of column names to process several series at once.

Plotting:

fig = plot_index(df_spi, "date", "TotalPrecipitation_calculated_index")

Baseline (reference) period

For climate-projection work you typically fit the distributions on a historical baseline and apply them to the full record:

df_spi = spi.calculate(
    rainfall_data,
    "date",
    "TotalPrecipitation",
    baseline_start=1961,
    baseline_end=1990,  # ints = years; dates work too
)

Fitted parameters

return_params=True additionally returns a dataframe of the fitted distribution parameters, one row per (column, frequency group), including the probability of zero precipitation:

df_spi, df_params = spi.calculate(rainfall_data, "date", "TotalPrecipitation", return_params=True)

Annual and custom frequencies

The freq parameter controls the seasonal grouping used for fitting: each day of year (freq="D"), week of year ("W") or month of year ("M") forms its own fitting population. For annual totals there is no seasonal cycle to condition on — use freq=None so that a single distribution is fit to the whole series:

df_annual = df.resample("YE", on="date").sum().reset_index()
df_spi = spi.calculate(df_annual, "date", "TotalPrecipitation", freq=None)

(Do not create a per-year grouping column for annual data: each year would end up alone in its own fitting group.)

For any other custom grouping, add an integer column that assigns each row to a fitting group and pass its name as freq_col.

SPEI

SPEI is calculated exactly like SPI but on the climatic water balance D = P − PET. This package does not compute potential evapotranspiration; supply the water-balance column yourself. Because D takes negative values, use a distribution defined on the whole real line — Vicente-Serrano et al. (2010) recommend the generalized logistic distribution:

from standard_precip import SPEI

df["wb"] = df["precip"] - df["pet"]
df_spei = SPEI().calculate(df, "date", "wb", dist_type="glo", fit_type="lmom")

Notes

  1. Although the user is allowed to select the distribution they wish to fit, one should be aware of the support of each distribution. Precipitation data can have zero values (handled for Gamma and Pearson III via the mixed CDF of Thom, 1966) and P − PET can take on negative values. This should be considered when selecting a distribution.
  2. For gamma MLE fits, the location parameter is fixed at 0 unless you pass floc/loc explicitly; unconstrained-loc gamma MLE is ill-posed on precipitation data and produced extreme index values.
  3. L-moment fitting is provided by the lmoments3 package, which is licensed under GPL-3. This package's own code remains Apache-2.0; lmoments3 is an external dependency installed alongside it.

Development

uv sync --group dev
uv run pytest
uv run ruff check .

Contacts

Author - Eric Nussbaumer (ebaumer@gmail.com)

License

Apache License, Version 2.0

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Release files for standard-precip 2.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for standard-precip 2.0.0
File Size Uploaded
standard_precip-2.0.0.tar.gz 356.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for standard-precip 2.0.0
File Interpreter ABI Platform
standard_precip-2.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 376.1 kB

Release files / standard_precip-2.0.0.tar.gz

Download URL standard_precip-2.0.0.tar.gz
Size 356.3 kB
Tags Source
SHA-256 checksum
How to use checksums
6a1f65c093568248a093d9ef14e76d62dade6dee6064a381b9f044980f0ce323
BLAKE2b-256 checksum
How to use checksums
c63568bd5ee3a766e2b0b9a26157ce4b99ae17ecfd332bafbe3e12b55883faf6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / standard_precip-2.0.0-py3-none-any.whl

Download URL standard_precip-2.0.0-py3-none-any.whl
Size 19.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
150c4e7e5166fe44e63e01b73ae32df8a630e69d3862373e62215d9fdb8dce19
BLAKE2b-256 checksum
How to use checksums
5119f170af8c7ab99ac6aa016cf76d98ae9c1997867c16da06a8328260369650
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.9 {"installer":{"name":"uv","version":"0.12.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

2.0.0 This release

2 release files

1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page