{
    "nbformat": 4,
    "nbformat_minor": 5,
    "metadata": {
        "kernelspec": {
            "display_name": "Python",
            "language": "python",
            "name": "python"
        },
        "language_info": {
            "name": "python"
        }
    },
    "cells": [
        {
            "id": "45d39e97",
            "cell_type": "markdown",
            "source": "<div class='alert alert-warning'>\n\nSciPy's interactive examples with Jupyterlite are experimental and may not always work as expected. Execution of cells containing imports may result in large downloads (up to 60MB of content for the first import from SciPy). Load times when importing from SciPy may take roughly 10-20 seconds. If you notice any problems, feel free to open an [issue](https://github.com/scipy/scipy/issues/new/choose).\n\n</div>",
            "metadata": {}
        },
        {
            "id": "582fa1b2",
            "cell_type": "markdown",
            "source": "Suppose we have 100 observations of a dependent variable for each of four\nseasons:\n",
            "metadata": {}
        },
        {
            "id": "14d38cfb",
            "cell_type": "code",
            "metadata": {},
            "execution_count": null,
            "source": "import numpy as np\nrng = np.random.default_rng()\nx = rng.random(size=(100, 4))",
            "outputs": []
        },
        {
            "id": "75081f37",
            "cell_type": "markdown",
            "source": "We compute the seasonal slopes as:\n",
            "metadata": {}
        },
        {
            "id": "ad6af06e",
            "cell_type": "code",
            "metadata": {},
            "execution_count": null,
            "source": "from scipy import stats\nintra_slope, inter_slope = stats.mstats.sen_seasonal_slopes(x)",
            "outputs": []
        },
        {
            "id": "85150378",
            "cell_type": "markdown",
            "source": "If we define a function to compute all slopes between observations within\na season:\n",
            "metadata": {}
        },
        {
            "id": "cce6a0d6",
            "cell_type": "code",
            "metadata": {},
            "execution_count": null,
            "source": "def dijk(yi):\n    n = len(yi)\n    x = np.arange(n)\n    dy = yi - yi[:, np.newaxis]\n    dx = x - x[:, np.newaxis]\n    # we only want unique pairs of distinct indices\n    mask = np.triu(np.ones((n, n), dtype=bool), k=1)\n    return dy[mask]/dx[mask]",
            "outputs": []
        },
        {
            "id": "114d99a5",
            "cell_type": "markdown",
            "source": "then element ``i`` of ``intra_slope`` is the median of ``dijk[x[:, i]]``:\n",
            "metadata": {}
        },
        {
            "id": "3997b522",
            "cell_type": "code",
            "metadata": {},
            "execution_count": null,
            "source": "i = 2\nnp.allclose(np.median(dijk(x[:, i])), intra_slope[i])",
            "outputs": [
                {
                    "output_type": "execute_result",
                    "metadata": {},
                    "data": {
                        "text/plain": "True"
                    },
                    "execution_count": null
                }
            ]
        },
        {
            "id": "241a7957",
            "cell_type": "markdown",
            "source": "and ``inter_slope`` is the median of the values returned by ``dijk`` for\nall seasons:\n",
            "metadata": {}
        },
        {
            "id": "37f57845",
            "cell_type": "code",
            "metadata": {},
            "execution_count": null,
            "source": "all_slopes = np.concatenate([dijk(x[:, i]) for i in range(x.shape[1])])\nnp.allclose(np.median(all_slopes), inter_slope)",
            "outputs": [
                {
                    "output_type": "execute_result",
                    "metadata": {},
                    "data": {
                        "text/plain": "True"
                    },
                    "execution_count": null
                }
            ]
        },
        {
            "id": "33e22d90",
            "cell_type": "markdown",
            "source": "Because the data are randomly generated, we would expect the median slopes\nto be nearly zero both within and across all seasons, and indeed they are:\n",
            "metadata": {}
        },
        {
            "id": "8d76b6b0",
            "cell_type": "code",
            "metadata": {},
            "execution_count": null,
            "source": "intra_slope.data",
            "outputs": [
                {
                    "output_type": "execute_result",
                    "metadata": {},
                    "data": {
                        "text/plain": "array([ 0.00124504, -0.00277761, -0.00221245, -0.00036338])"
                    },
                    "execution_count": null
                }
            ]
        },
        {
            "id": "ff652f24",
            "cell_type": "code",
            "metadata": {},
            "execution_count": null,
            "source": "inter_slope",
            "outputs": [
                {
                    "output_type": "execute_result",
                    "metadata": {},
                    "data": {
                        "text/plain": "-0.0010511779872922058"
                    },
                    "execution_count": null
                }
            ]
        }
    ]
}