def excprob(X, X_thr, ignore_nan=False):
    """
    For a given forecast ensemble field, compute exceedance probabilities
    for the given intensity thresholds.

    Parameters
    ----------
    X: array_like
        Array of shape (k, m, n, ...) containing an k-member ensemble of
        forecasts with shape (m, n, ...).
    X_thr: float or a sequence of floats
        Intensity threshold(s) for which the exceedance probabilities are
        computed.
    ignore_nan: bool
        If True, ignore nan values.

    Returns
    -------
    out: ndarray
        Array of shape (len(X_thr), m, n) containing the exceedance
        probabilities for the given intensity thresholds.
        If len(X_thr)=1, the first dimension is dropped.
    """
    #  Checks
    X = np.asanyarray(X)
    X_ndim = X.ndim

    if X_ndim < 3:
        raise Exception(
            f"Number of dimensions of X should be 3 or more. It was: {X_ndim}"
        )

    P = []

    if np.isscalar(X_thr):
        X_thr = [X_thr]
        scalar_thr = True
    else:
        scalar_thr = False

    for x in X_thr:
        X_ = np.zeros(X.shape)

        X_[X >= x] = 1.0
        X_[~np.isfinite(X)] = np.nan

        if ignore_nan:
            P.append(np.nanmean(X_, axis=0))
        else:
            P.append(np.mean(X_, axis=0))

    if not scalar_thr:
        return np.stack(P)
    else:
        return P[0]
For a given forecast ensemble field, compute exceedance probabilities
for the given intensity thresholds.

Parameters
----------
X: array_like
Array of shape (k, m, n, ...) containing an k-member ensemble of
forecasts with shape (m, n, ...).
X_thr: float or a sequence of floats
Intensity threshold(s) for which the exceedance probabilities are
computed.
ignore_nan: bool
If True, ignore nan values.

Returns
-------
out: ndarray
Array of shape (len(X_thr), m, n) containing the exceedance
probabilities for the given intensity thresholds.
If len(X_thr)=1, the first dimension is dropped.
pysteps/postprocessing/ensemblestats.py