{
    "nbformat": 4,
    "nbformat_minor": 5,
    "metadata": {
        "kernelspec": {
            "display_name": "Python",
            "language": "python",
            "name": "python"
        },
        "language_info": {
            "name": "python"
        }
    },
    "cells": [
        {
            "id": "b2803d92",
            "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": "e72c7ba0",
            "cell_type": "markdown",
            "source": "Suppose we wish to test the null hypothesis that the median of a population\nis equal to 0.5. We choose a confidence level of 99%; that is, we will\nreject the null hypothesis in favor of the alternative if the p-value is\nless than 0.01.\n\nWhen testing random variates from the standard uniform distribution, which\nhas a median of 0.5, we expect the data to be consistent with the null\nhypothesis most of the time.\n",
            "metadata": {}
        },
        {
            "id": "aef0cf85",
            "cell_type": "code",
            "metadata": {},
            "execution_count": null,
            "source": "import numpy as np\nfrom scipy import stats\nrng = np.random.default_rng()\nrvs = stats.uniform.rvs(size=100, random_state=rng)\nstats.quantile_test(rvs, q=0.5, p=0.5)",
            "outputs": [
                {
                    "output_type": "execute_result",
                    "metadata": {},
                    "data": {
                        "text/plain": "QuantileTestResult(statistic=45, statistic_type=1, pvalue=0.36820161732669576)"
                    },
                    "execution_count": null
                }
            ]
        },
        {
            "id": "e341848b",
            "cell_type": "markdown",
            "source": "As expected, the p-value is not below our threshold of 0.01, so\nwe cannot reject the null hypothesis.\n\nWhen testing data from the standard *normal* distribution, which has a\nmedian of 0, we would expect the null hypothesis to be rejected.\n",
            "metadata": {}
        },
        {
            "id": "a229f587",
            "cell_type": "code",
            "metadata": {},
            "execution_count": null,
            "source": "rvs = stats.norm.rvs(size=100, random_state=rng)\nstats.quantile_test(rvs, q=0.5, p=0.5)",
            "outputs": [
                {
                    "output_type": "execute_result",
                    "metadata": {},
                    "data": {
                        "text/plain": "QuantileTestResult(statistic=67, statistic_type=2, pvalue=0.0008737198369123724)"
                    },
                    "execution_count": null
                }
            ]
        },
        {
            "id": "cd81dfb4",
            "cell_type": "markdown",
            "source": "Indeed, the p-value is lower than our threshold of 0.01, so we reject the\nnull hypothesis in favor of the default \"two-sided\" alternative: the median\nof the population is *not* equal to 0.5.\n\nHowever, suppose we were to test the null hypothesis against the\none-sided alternative that the median of the population is *greater* than\n0.5. Since the median of the standard normal is less than 0.5, we would not\nexpect the null hypothesis to be rejected.\n",
            "metadata": {}
        },
        {
            "id": "7b8e4760",
            "cell_type": "code",
            "metadata": {},
            "execution_count": null,
            "source": "stats.quantile_test(rvs, q=0.5, p=0.5, alternative='greater')",
            "outputs": [
                {
                    "output_type": "execute_result",
                    "metadata": {},
                    "data": {
                        "text/plain": "QuantileTestResult(statistic=67, statistic_type=1, pvalue=0.9997956114162866)"
                    },
                    "execution_count": null
                }
            ]
        },
        {
            "id": "46107ab9",
            "cell_type": "markdown",
            "source": "Unsurprisingly, with a p-value greater than our threshold, we would not\nreject the null hypothesis in favor of the chosen alternative.\n\nThe quantile test can be used for any quantile, not only the median. For\nexample, we can test whether the third quartile of the distribution\nunderlying the sample is greater than 0.6.\n",
            "metadata": {}
        },
        {
            "id": "89504838",
            "cell_type": "code",
            "metadata": {},
            "execution_count": null,
            "source": "rvs = stats.uniform.rvs(size=100, random_state=rng)\nstats.quantile_test(rvs, q=0.6, p=0.75, alternative='greater')",
            "outputs": [
                {
                    "output_type": "execute_result",
                    "metadata": {},
                    "data": {
                        "text/plain": "QuantileTestResult(statistic=64, statistic_type=1, pvalue=0.00940696592998271)"
                    },
                    "execution_count": null
                }
            ]
        },
        {
            "id": "c8418ab5",
            "cell_type": "markdown",
            "source": "The p-value is lower than the threshold. We reject the null hypothesis in\nfavor of the alternative: the third quartile of the distribution underlying\nour sample is greater than 0.6.\n\n`quantile_test` can also compute confidence intervals for any quantile.\n",
            "metadata": {}
        },
        {
            "id": "01f48a39",
            "cell_type": "code",
            "metadata": {},
            "execution_count": null,
            "source": "rvs = stats.norm.rvs(size=100, random_state=rng)\nres = stats.quantile_test(rvs, q=0.6, p=0.75)\nci = res.confidence_interval(confidence_level=0.95)\nci",
            "outputs": [
                {
                    "output_type": "execute_result",
                    "metadata": {},
                    "data": {
                        "text/plain": "ConfidenceInterval(low=0.284491604437432, high=0.8912531024914844)"
                    },
                    "execution_count": null
                }
            ]
        },
        {
            "id": "64861cc8",
            "cell_type": "markdown",
            "source": "When testing a one-sided alternative, the confidence interval contains\nall observations such that if passed as `q`, the p-value of the\ntest would be greater than 0.05, and therefore the null hypothesis\nwould not be rejected. For example:\n",
            "metadata": {}
        },
        {
            "id": "7ebd73cc",
            "cell_type": "code",
            "metadata": {},
            "execution_count": null,
            "source": "rvs.sort()\nq, p, alpha = 0.6, 0.75, 0.95\nres = stats.quantile_test(rvs, q=q, p=p, alternative='less')\nci = res.confidence_interval(confidence_level=alpha)\nfor x in rvs[rvs <= ci.high]:\n    res = stats.quantile_test(rvs, q=x, p=p, alternative='less')\n    assert res.pvalue > 1-alpha\nfor x in rvs[rvs > ci.high]:\n    res = stats.quantile_test(rvs, q=x, p=p, alternative='less')\n    assert res.pvalue < 1-alpha",
            "outputs": []
        },
        {
            "id": "f481d5a4",
            "cell_type": "markdown",
            "source": "Also, if a 95% confidence interval is repeatedly generated for random\nsamples, the confidence interval will contain the true quantile value in\napproximately 95% of replications.\n",
            "metadata": {}
        },
        {
            "id": "8d8bd7b3",
            "cell_type": "code",
            "metadata": {},
            "execution_count": null,
            "source": "dist = stats.rayleigh() # our \"unknown\" distribution\np = 0.2\ntrue_stat = dist.ppf(p) # the true value of the statistic\nn_trials = 1000\nquantile_ci_contains_true_stat = 0\nfor i in range(n_trials):\n    data = dist.rvs(size=100, random_state=rng)\n    res = stats.quantile_test(data, p=p)\n    ci = res.confidence_interval(0.95)\n    if ci[0] < true_stat < ci[1]:\n        quantile_ci_contains_true_stat += 1\nquantile_ci_contains_true_stat >= 950",
            "outputs": [
                {
                    "output_type": "execute_result",
                    "metadata": {},
                    "data": {
                        "text/plain": "True"
                    },
                    "execution_count": null
                }
            ]
        },
        {
            "id": "b0793770",
            "cell_type": "markdown",
            "source": "This works with any distribution and any quantile, as long as the samples\nare i.i.d.",
            "metadata": {}
        }
    ]
}