Repository: scipy/scipy
File: scipy/stats/_stats_py.py (Python)

Code before:
        raise ValueError(message)
    standardize = bool(standardize)

    sample = xp.moveaxis(sample, axis, -1)
    sample = xp.sort(sample, axis=-1) if not sorted else sample

    return sample, order, axis, sorted, standardize


def _br(x, *, r=0, xp):
    n = x.shape[-1]
    x = xp.expand_dims(x, axis=-2)
    x = xp.broadcast_to(x, x.shape[:-2] + (r.shape[0], n))
    x = xp.triu(x)
    j = xp.arange(n, dtype=x.dtype)
    n = xp.asarray(n, dtype=x.dtype)[()]
    binom_j_r = xpx.lazy_apply(special.binom, j, r[:, xp.newaxis])
    binom_nm1_r = xpx.lazy_apply(special.binom, n-1, r)
    return xp.vecdot(binom_j_r, x, axis=-1) / binom_nm1_r / n


def _prk(r, k):
    # Writen to match [1] Equation 27 closely to facilitate review.
    # This does not protect against overflow, so improvements to
    # robustness would be a welcome follow-up.
    binom_r_k = xpx.lazy_apply(special.binom, r, k, as_numpy=True)
    binom_rpk_k = xpx.lazy_apply(special.binom, r+k, k, as_numpy=True)
    return (-1)**(r-k)*binom_r_k*binom_rpk_k


@xp_capabilities(skip_backends=[('dask.array', "too many issues")],
                 cpu_only=True,  # torch doesn't have `binom`
                 exceptions=('cupy', 'jax.numpy'),
                 extra_note="Lazy backends do not support `order` greater than 4.")
@_axis_nan_policy_factory(  # noqa: E302
    _moment_result_object, n_samples=1, result_to_tuple=_moment_tuple,
    n_outputs=lambda kwds: _moment_outputs(kwds, [1, 2, 3, 4])
)
def lmoment(sample, order=None, *, axis=0, sorted=False, standardize=True):
    r"""Compute L-moments of a sample from a continuous distribution.

    The L-moments of a probability distribution are summary statistics with
    uses similar to those of conventional moments, but they are defined in
    terms of the expected values of order statistics.
    Sample L-moments are defined analogously to population L-moments, and
    they can serve as estimators of population L-moments. They tend to be less
    sensitive to extreme observations than conventional moments.

    Parameters
    ----------
    sample : array_like

Review comment (suggestion):
```suggestion
    binom_r_k = xpx.lazy_apply(special.binom, r, k)
```

Code after:
        raise ValueError(message)
    standardize = bool(standardize)

    sample = xp.moveaxis(sample, axis, -1)
    sample = xp.sort(sample, axis=-1) if not sorted else sample

    return sample, order, axis, sorted, standardize


def _br(x, *, r=0, xp):
    n = x.shape[-1]
    x = xp.expand_dims(x, axis=-2)
    x = xp.broadcast_to(x, x.shape[:-2] + (r.shape[0], n))
    x = xp.triu(x)
    j = xp.arange(n, dtype=x.dtype)
    n = xp.asarray(n, dtype=x.dtype)[()]
    binom_j_r = xpx.lazy_apply(special.binom, j, r[:, xp.newaxis])
    binom_nm1_r = xpx.lazy_apply(special.binom, n-1, r)
    return xp.vecdot(binom_j_r, x, axis=-1) / binom_nm1_r / n


def _prk(r, k):
    # Writen to match [1] Equation 27 closely to facilitate review.
    # This does not protect against overflow, so improvements to
    # robustness would be a welcome follow-up.
    binom_r_k = xpx.lazy_apply(special.binom, r, k)
    binom_rpk_k = xpx.lazy_apply(special.binom, r+k, k)
    return (-1)**(r-k)*binom_r_k*binom_rpk_k


@xp_capabilities(skip_backends=[('dask.array', "too many issues")],
                 cpu_only=True,  # torch doesn't have `binom`
                 exceptions=('cupy', 'jax.numpy'),
                 extra_note="Lazy backends do not support `order` greater than 4.")
@_axis_nan_policy_factory(  # noqa: E302
    _moment_result_object, n_samples=1, result_to_tuple=_moment_tuple,
    n_outputs=lambda kwds: _moment_outputs(kwds, [1, 2, 3, 4])
)
def lmoment(sample, order=None, *, axis=0, sorted=False, standardize=True):
    r"""Compute L-moments of a sample from a continuous distribution.

    The L-moments of a probability distribution are summary statistics with
    uses similar to those of conventional moments, but they are defined in
    terms of the expected values of order statistics.
    Sample L-moments are defined analogously to population L-moments, and
    they can serve as estimators of population L-moments. They tend to be less
    sensitive to extreme observations than conventional moments.

    Parameters
    ----------
    sample : array_like