Repository: optimagic-dev/optimagic (language: python)

Issue:
Add bootstrap functionality to estimagic.
In this pull request, I add bootstrap functionality to estimagic. Both the usual uniform bootstrap as well as the cluster robust bootstrap, where clusters instead of observations are drawn with replacement, are implemented.

The main features are separated code for drawing bootstrap sample seeds, computing bootstrap estimates and computing bootstrap confidence intervals. Various types of confidence intervals are supported. Computation of the estimates as well as some calculations for confidence intervals are parallelized using joblib.

Parts of the code for the bootstrap confidence intervals are an adjusted version from Daniel Saxton's resample library ([https://github.com/dsaxton/resample/tree/master/resample]), which now allows for multiple parameters, additional confidence interval types and a faster computation of jackknife estimates for the bca confidence interval.

The main bootstrap() function takes a dataset and a user-specified function that calculates a vector of statistics of interest on the dataset (and additional refining arguments such as number of bootstrap draws, confidence interval method, etc) and returns a DataFrame containing mean, standard deviation and a confidence interval for each element of the statistic vector. The documentation features a jupyter notebook containing a tutorial on how to use the bootstrap.


Discussion / hints:

Fix patch:
diff --git a/docs/source/explanations/inference/bootstrap_ci.rst b/docs/source/explanations/inference/bootstrap_ci.rst
new file mode 100644
index 000000000..6c56a627f
--- /dev/null
+++ b/docs/source/explanations/inference/bootstrap_ci.rst
@@ -0,0 +1,93 @@
+.. _bootstrap_cis:
+
+Bootstrap Confidence Intervals
+********************************
+We use the notation and formulations provided in chapter 10 of :cite:`Hansen2020`.
+
+Bruce E. Hansen - Econometrics,  (https://www.ssc.wisc.edu/~bhansen/econometrics)
+
+The first supported confidence interval type is the **"percentile"** confidence
+interval, as discussed in section 10.10 of the Hansen textbook.
+Let :math:`\{ \hat{\theta}_1^*, ..., \hat{\theta}_B^*\}` denote the estimates of
+estimator :math:`\hat{\theta}` for the B bootstrap samples. The idea of the percentile
+confidence interval is to simply take the empirical quantiles :math:`q_{p}^*` of
+this distributions, so we have
+
+.. math:: CI^{percentile} = [q_{\alpha/2}^*, q_{1-\alpha/2}^*].
+
+The second supported confidence interval **"normal"** is based on a normal approximation
+and discussed in Hansen's section 10.9.
+Let :math:`s_{boot}` be the sample standard error of the distribution
+of bootstrap estimators, :math:`z_q` the q-quantile of a standard normal
+distribution and :math:`\hat{\theta}` be the full sample estimate of :math:`\theta`.
+Then, the asymptotic normal confidence interval is given by
+
+.. math::
+
+    CI^{normal} = [\hat{\theta} - z_{1- \alpha/2} s_{boot},
+    \hat{\theta} + z_{1- \alpha/2} s_{boot}].
+
+The bias-corrected **"bc"** bootstrap confidence interval addresses the issue of biased
+estimators. This problem is often present when estimating nonlinear models. Econometric
+details are discussed in section 10.17 of Hansen. Let
+
+.. math:: p^* = \frac{1}{B} \sum_{b=1}^B 1(\hat{\theta}_b^* \leq \hat{\theta})
+
+and define :math:`z_0^* = \Phi^{-1} (p^*)`, where :math:`\Phi` is the standard normal
+cdf. The bias correction works via correcting the significance level.
+Define :math:`x(\alpha) = \Phi(z_\alpha + 2 z_0^*)` as the corrected significance level
+for a target significant level of :math:`\alpha`. Then, the bias-corrected confidence
+interval is given by
+
+.. math:: CI^{bc} = [q_{x(\alpha/2)}^*, q_{x(1-\alpha/2)}^*].
+
+
+A further refined version of the bias-corrected confidence interval is the
+bias-corrected and accelerated interval, short **"bca"**, as discussed in section 10.20
+of Hansen. The general idea is to correct for skewness sampling distribution.
+Downsides of this confidence interval are that it takes quite a lot of time to compute,
+since it features calculating leave-one-out estimates of the original sample.
+Formally, again, the significance levels are adjusted. Define
+
+.. math::
+
+    \hat{a}=\frac{\sum_{i=1}^{n}\left(\bar{\theta}-\hat{\theta}_{(-i)}\right)^{3}}
+    {6\left(\sum_{i=1}^{n}\left(\bar{\theta}-\hat{\theta}_{(-i)}\right)^{2}
+    \right)^{3 / 2}},
+
+where :math:`\bar{\theta}=\frac{1}{n} \sum_{i=1}^{n} \widehat{\theta}_{(-i)}`.
+This is an estimator for the skewness of :math:`\hat{\theta}`. Then, the corrected
+significance level is given by
+
+.. math:: x(\alpha)=\Phi(z_{0}+\frac{z_{\alpha}+z_{0}}{1-a(z_{\alpha}+z_{0})})
+
+and the bias-corrected and accelerated confidence interval is given by
+
+.. math:: CI^{bca} = [q_{x(\alpha/2)}^*, q_{x(1-\alpha/2)}^*].
+
+The studentized confidence interval, here called **"t"** type confidence interval first
+studentizes the bootstrap parameter distribution, i.e. applies the transformation
+:math:`\frac{\hat{\theta}_b-\hat{\theta}}{s_{boot}}`, and then builds
+the confidence interval based on the estimated quantile function of the studentized
+data :math:`\hat{G}`:
+
+.. math::
+
+    CI^{t} = \left[\hat{\theta}+\hat{\sigma} \hat{G}^{-1}(\alpha / 2),
+    \hat{\theta}+\hat{\sigma} \hat{G}^{-1}(1-\alpha / 2)\right]
+
+The final supported confidence interval method is the **"basic"** bootstrap confidence
+interval, which is derived in section 3.4 of :cite:`Wassermann2006`, where it is called
+the pivotal confidence interval. It is given by
+
+.. math::
+    CI^{basic} = \left[\hat{\theta}+\left(\hat{\theta}-\hat{\theta}_{u}^{\star}\right),
+    \hat{\theta}+\left(\hat{\theta}-\hat{\theta}_{l}^{\star}\right)\right],
+
+where :math:`\hat{\theta}_{u}^{\star}` denotes the :math:`1-\alpha/2` empirical quantile
+of the bootstrap estimate distribution for parameter :math:`\theta` and
+:math:`\hat{\theta}_{l}^{\star}` denotes the :math:`\alpha/2` quantile.
+
+
+.. bibliography:: ../../refs.bib
+    :filter: docname in docnames
diff --git a/docs/source/explanations/inference/bootstrap_montecarlo_comparison.ipynb b/docs/source/explanations/inference/bootstrap_montecarlo_comparison.ipynb
new file mode 100644
index 000000000..b9bd990ed
--- /dev/null
+++ b/docs/source/explanations/inference/bootstrap_montecarlo_comparison.ipynb
@@ -0,0 +1,336 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import random\n",
+    "\n",
+    "import matplotlib.pyplot as plt\n",
+    "import numpy as np\n",
+    "import pandas as pd\n",
+    "import scipy\n",
+    "import seaborn as sns\n",
+    "import statsmodels.api as sm\n",
+    "from joblib import Parallel\n",
+    "from joblib import delayed\n",
+    "\n",
+    "from estimagic.inference import get_bootstrap_outcomes"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Bootstrap Monte Carlo Comparison"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "In this juypter notebook, I perform a Monte Carlo exercise to illustrate the importance of using the cluster robust variant of the bootstrap when data within clusters is correlated. \n",
+    "\n",
+    "The main idea is to repeatedly draw clustered samples, get both uniform and clustered bootstrap estimates in these samples, and then compare how often the true null hypothesis is rejected."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Data Generating Process"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The true data generating process is given by\n",
+    "\n",
+    "$$ logit(y_{i,g}) = \\beta_0 + \\beta_1 (x_{i,g}) + \\epsilon_{i,g}, $$\n",
+    "\n",
+    "where the independent variable $x_{i,g} = x_i + x_g$ and the noise term $\\epsilon_{i,g} = \\epsilon_i + \\epsilon_g$ each consist of an individual and a cluster term.\n",
+    "\n",
+    "In the simulations I perform below, we have $\\beta_0 = \\beta_1 =0$. $x_i$ and $x_g$ are drawn from a standard normal distribution, and $\\epsilon_i$ and $\\epsilon_g$ are drawn from a normal distribution with $\\mu_0$ and $\\sigma=0.5$. The value of $\\sigma$ is chosen to not blow up rejection rates in the independent case too much."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def create_clustered_data(nclusters, nobs_per_cluster, true_beta=0):\n",
+    "    \"\"\"Create a bivariate clustered dataset with specified number of\n",
+    "    clusters and number of observations per cluster that has a population\n",
+    "    value of true_beta for the logit coefficient on the independent variable.\n",
+    "\n",
+    "    Args:\n",
+    "        nclusters (int): number of clusters.\n",
+    "        nobs_per_cluster (int): number of observations per cluster.\n",
+    "        true_beta (int): true logit coefficient on x.\n",
+    "\n",
+    "    Returns:\n",
+    "        (pd.DataFrame): clustered dataset.\n",
+    "    \"\"\"\n",
+    "\n",
+    "    x_cluster = np.random.normal(size=nclusters)\n",
+    "    x_ind = np.random.normal(size=nobs_per_cluster * nclusters)\n",
+    "    eps_cluster = np.random.normal(size=nclusters, scale=0.5)\n",
+    "    eps_ind = np.random.normal(size=nobs_per_cluster * nclusters, scale=0.5)\n",
+    "\n",
+    "    y = []\n",
+    "    x = []\n",
+    "    cluster = []\n",
+    "\n",
+    "    for g in range(nclusters):\n",
+    "\n",
+    "        for i in range(nobs_per_cluster):\n",
+    "\n",
+    "            key = (i + 1) * (g + 1) - 1\n",
+    "\n",
+    "            arg = (\n",
+    "                true_beta * (x_cluster[g] + x_ind[key]) + eps_ind[key] + eps_cluster[g]\n",
+    "            )\n",
+    "\n",
+    "            y_prob = 1 / (1 + np.exp(-arg))\n",
+    "            y.append(np.random.binomial(n=1, p=y_prob))\n",
+    "            x.append(x_cluster[g] + x_ind[(i + 1) * (g + 1) - 1])\n",
+    "            cluster.append(g)\n",
+    "\n",
+    "    y = np.array(y)\n",
+    "    x = np.array(x)\n",
+    "    cluster = np.array(cluster)\n",
+    "\n",
+    "    return pd.DataFrame({\"y\": y, \"x\": x, \"cluster\": cluster})"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Monte Carlo Simulation Code"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The following function computes bootstrap T-values. As suggested my Cameron and Miller (2015), critical values are the 0.975 quantiles from a T distribution with $n_{clusters} -1$ degrees of freedom."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def get_t_values(data, hyp_beta=0, cluster=False):\n",
+    "    \"\"\"Get bootstrap t-values for testing the hypothesis that beta = hyp_beta.\n",
+    "\n",
+    "    Args:\n",
+    "        data (pd.DataFrame): original dataset.\n",
+    "        hyp_beta (float): hypothesised value of beta.\n",
+    "        cluster (bool): whether or not to cluster on the cluster column.\n",
+    "\n",
+    "    Returns:\n",
+    "        (float): T-Value of hypothesis.\n",
+    "\n",
+    "    \"\"\"\n",
+    "\n",
+    "    def logit_wrap(df):\n",
+    "\n",
+    "        y = df[\"y\"]\n",
+    "        x = df[\"x\"]\n",
+    "\n",
+    "        result = sm.Logit(y, sm.add_constant(x)).fit(disp=0).params\n",
+    "\n",
+    "        return pd.Series(result, index=[\"constant\", \"x\"])\n",
+    "\n",
+    "    if cluster is False:\n",
+    "\n",
+    "        estimates = get_bootstrap_outcomes(\n",
+    "            data=data, outcome=logit_wrap, n_draws=200, n_cores=1\n",
+    "        )[\"x\"]\n",
+    "\n",
+    "    else:\n",
+    "\n",
+    "        estimates = get_bootstrap_outcomes(\n",
+    "            data=data, outcome=logit_wrap, n_draws=200, n_cores=1, cluster_by=\"cluster\"\n",
+    "        )[\"x\"]\n",
+    "\n",
+    "    return (estimates.mean() - hyp_beta) / estimates.std()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def monte_carlo(nsim, nclusters, nobs_per_cluster, true_beta=0, n_cores=-1):\n",
+    "    \"\"\"Run a Monte Carlo simulation for rejection rates and a logit data generating process.\n",
+    "    Rejection rates are based on a T distribution with nclusters-1 degrees of freedom.\n",
+    "\n",
+    "    Args:\n",
+    "        nsim (int): number of Monte Carlo draws.\n",
+    "        nclusters (int): number of clusters in each generated dataset.\n",
+    "        nobs_per_cluster (int) number of observations per cluster.\n",
+    "        true_beta (int): population value of logit coefficient on x.\n",
+    "        n_cores (int): number of jobs for Parallelization.\n",
+    "\n",
+    "    Returns:\n",
+    "        result (pd.DataFrame): DataFrame of average rejection rates.\n",
+    "    \"\"\"\n",
+    "\n",
+    "    reject_independent = np.zeros(nsim)\n",
+    "\n",
+    "    reject_cluster = np.zeros(nsim)\n",
+    "\n",
+    "    def loop(i):\n",
+    "\n",
+    "        df = create_clustered_data(nclusters, nobs_per_cluster, true_beta)\n",
+    "\n",
+    "        return [get_t_values(df), get_t_values(df, cluster=True)]\n",
+    "\n",
+    "    t_value_array = np.array(\n",
+    "        Parallel(n_jobs=n_cores)(delayed(loop)(i) for i in range(nsim))\n",
+    "    )\n",
+    "\n",
+    "    crit = scipy.stats.t.ppf(0.975, nclusters - 1)\n",
+    "\n",
+    "    result = pd.DataFrame(np.abs(t_value_array) > crit, columns=[\"uniform\", \"cluster\"])\n",
+    "\n",
+    "    return result"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Results"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Here, I perform Monte Carlo simulations with the above functions. In each simulation, the sample size is 1000, but the number of clusters varies across simulations. Be warned that the code below takes a long time to run."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "np.random.seed(505)\n",
+    "random.seed(505)\n",
+    "\n",
+    "results_list = []\n",
+    "\n",
+    "for g, k in [[20, 50], [50, 20], [100, 10], [200, 5], [500, 2]]:\n",
+    "\n",
+    "    results_list.append(monte_carlo(500, g, k))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "           uniform  cluster\n",
+      "nclusters                  \n",
+      "20           0.172    0.070\n",
+      "50           0.096    0.054\n",
+      "100          0.074    0.052\n",
+      "200          0.074    0.060\n",
+      "500          0.038    0.042\n"
+     ]
+    }
+   ],
+   "source": [
+    "mean_rejection_data = pd.DataFrame([x.mean() for x in results_list])\n",
+    "mean_rejection_data[\"nclusters\"] = [20, 50, 100, 200, 500]\n",
+    "mean_rejection_data.set_index(\"nclusters\", inplace=True)\n",
+    "\n",
+    "print(mean_rejection_data)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "Text(0.5, 0.98, 'Comparison of Rejection Rates')"
+      ]
+     },
+     "execution_count": 7,
+     "metadata": {},
+     "output_type": "execute_result"
+    },
+    {
+     "data": {
+      "image/png": "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OZLCwkJGjhzJ4sWLk5b/73//44UXXuCqq67aNQzvXXfdRf/+/SksLOSss85i0aJF3Hfffdx+++0UFxfz+uuvM2bMGH70ox8xYsQIrrnmGqZOncrRRx/NoEGDOProo5k7d+6uY3P66adz8skn069fP2688cZa/U6SSjYcXkN/pWOI20Rz5oRhIR97LO2bFhGptuoMcVsXY9zeeeedfvnll1c6L36I10ceeaTCMK2jRo3ySZMmeUlJiR9//PG7yteuXevuYWjcadOmubv7tm3b/KijjvIVK1a4u/tTTz3l3/72t3ct9/3vf7/S/T/yyCPeoUMHLyoq8v3228+HDh3qZWVl7u5+2mmn+aOPPuru7g899JCffvrpVZaff/75/swzz+zadpcuXXzLli0V6hw/tG9snVGjRu3a5/r163379u3u7j5hwgQ/44wzdtWzc+fOvmrVql1D3cY+e1U0xG0d6tMHWrZUkp6I1EPZGOO2lnr37s2CBQu45JJLGDVqFCeeeOJuy8ydO5eZM2dywgknALBjxw66dOmya37isLfxzjzzTO6++27cnYsuuohbb72Va6+9lilTpvC3v/0NgPPOO4+rr74aIGl5osLCQkaPHs1Xv/pVvvrVrybd/ze/+U3y8vKAMPDN+eefz8cff4yZsX379l3LnXDCCbRv3x4IQwK/8cYbDB5caa+3NaZm/Gpo2lTd5opIA1UHY9wOGDCA6dOn73G5pk2bsnPnzl3TsaFc27Vrx3vvvcfw4cO55557uOCCC3Zb190ZMGAAM2bMYMaMGXzwwQf85z//2TU/cdjbypgZX/7yl3nttdeSzq9O+YsvvshFF13E9OnTOeyww5Lek4+v209/+lNGjBjBzJkz+cc//lFhONvE/aRjSNtECvbVVFioK3sRqYfuuCOMVZvs1bNn5evFxrit7LWHq/rjjjuOrVu38mBcy8C0adN49dVXKyxXUFDAjBkz2LlzJ0uWLGHq1KkArFq1ip07d/L1r3+dX/7yl7zzzjsA7LXXXruGh+3Xrx8rV65kypQpAGzfvp1Zs2aldkzivPHGG7tG4zv66KN56qmnABg/fvyuIWSTlcfXJ/YZRowYwS233MK6devYuHFjhWUqs379erp16waE+/TxJkyYwJo1a9i8eTPPP/88xxxzTLU/355kLNib2clmNtfM5pnZtZXMP8jMppjZVjO7MmHePmb2rJl9aGZzzOyoTNU7UWEhrFgBtUw2FRHJrHHjwpi28Wo5xq2Z8dxzzzFhwgQOOOAABgwYwA033EDXrl0rLHfMMcfQq1cvBg4cyJVXXsmhhx4KwKeffsrw4cMpLi5mzJgx3HTTTQCMGTOGCy+8kOLiYnbs2MGzzz7LNddcQ1FREcXFxSk/4vb0009TXFxMYWEh7777Lj/96U8BuOuuu3jkkUcoLCzk8ccf35Xcl6z8rLPO4tZbb2XQoEF8/PHHnHvuuQwcOJBBgwbxwx/+kH322Ycvf/nLPPfcc7sS9BJdffXVXHfddRxzzDHs2LGjwryhQ4dy3nnnUVxczNe//vW0N+FDhoa4NbM84CPgBKAUmAac7e6z45bZD+gJfBVY6+63xc17DHjd3f9oZs2BfHdfV9U+0znEbbzJk2HECHj5Zajk9pKISMZUd4hbjXFb/zz66KOUlJRw9913V2u96g5xm6kr+yHAPHdf4O7bgKeA0+MXcPcV7j4N2B5fbmZtgWOBh6Lltu0p0NcldZsrIg3W6NGwaBHs3Bl+KtA3GpkK9t2AJXHTpVFZKnoDK4FHzOxdM/ujmVWakWFmY82sxMxKVq5cWbsaJ9G+PXTrpmAvIiK1N2bMmGpf1ddEpoJ9ZamFqd4/aAocCvzB3QcBXwC73fMHcPcH3H2wuw/u2LFjzWqagqIiZeSLiEjDkalgXwrsHzfdHUi1L8RSoNTd346mnyUE/6wpLIQ5c2DbtmzWQkQkPJomjUtNfueZCvbTgAPNrFeUYHcW8EIqK7r7MmCJmfWLikYCVXdSXMcKC2H7doh6OxQRyYqWLVuyevVqBfxGxN1ZvXo1LVu2rNZ6GelBz93LzOxi4GUgD3jY3WeZ2YXR/PvMrDNQArQFdprZ5UB/d98AXAKMj04UFgDfzkS9kykqCj/fe688YU9EJNO6d+9OaWkpdZWjJPVTy5Yt6d69e7XWyVh3ue7+EvBSQtl9ce+XEZr3K1t3BpD+Bw9rqG9faN5cSXoikl3NmjWjV69e2a6GNADqQa8GmjaFAQMU7EVEpGFQsK8hZeSLiEhDoWBfQ4WFsGxZ6DpXRESkPlOwr6HCwvDzgw+yWw8REZE9UbCvoViwV1O+iIjUdwr2NdSxI3TpoiQ9ERGp/xTsa0Fj24uISEOgYF8LRUUwa1boTU9ERKS+UrCvhcLC0D/+Rx9luyYiIiLJKdjXQixJT035IiJSnynY18JBB0GzZsrIFxGR+k3BvhaaNYP+/XVlLyIi9ZuCfS0pI19EROo7BftaKiqCTz+F1auzXRMREZHKKdjXkpL0RESkvlOwryUFexERqe8U7GupU6fwUka+iIjUVwr2aaAkPRERqc8U7NOgsDB0m1tWlu2aiIiI7E7BPg2KimDLFvj442zXREREZHcK9mmgJD0REanPFOzT4KCDoGlTBXsREamfFOzToEULOPhgZeSLiEj9pGCfJsrIFxGR+krBPk0KC2HJEli7Nts1ERERqUjBPk2KisJPXd2LiEh9o2CfJsrIFxGR+krBPk06d4YOHRTsRUSk/slYsDezk81srpnNM7NrK5l/kJlNMbOtZnZlJfPzzOxdM/tnZmpcPWahKV8Z+SIiUt9kJNibWR5wD3AK0B8428z6Jyy2BrgUuC3JZi4D5tRZJdOgsBBmzoQdO7JdExERkXKZurIfAsxz9wXuvg14Cjg9fgF3X+Hu04DtiSubWXdgFPDHTFS2pgoLYfNmmD8/2zUREREpl6lg3w1YEjddGpWl6g7gamBnVQuZ2VgzKzGzkpUrV1a7krUVy8hXU76IiNQnmQr2VkmZp7Si2WnACnefvqdl3f0Bdx/s7oM7duxY3TrW2sEHQ16ekvRERKR+yVSwLwX2j5vuDixNcd1jgK+Y2SJC8/9xZvZEequXHi1bQr9+CvYiIlK/ZCrYTwMONLNeZtYcOAt4IZUV3f06d+/u7gXReq+4+7l1V9XaUUa+iIjUNxkJ9u5eBlwMvEzIqP+Lu88yswvN7EIAM+tsZqXAj4CfmFmpmbXNRP3SqbAQPvkE1q/Pdk1ERESCppnakbu/BLyUUHZf3PtlhOb9qrYxGZhcB9VLm1hPeh98AEOHZrcuIiIioB700k4Z+SIiUt8o2KdZ166w775K0hMRkfpDwT7NzDS2vYiI1C8K9nWgqCjcs99ZZRdAIiIimaFgXwcKC+GLL2DBgmzXRERERMG+TmhsexERqU8U7OvAgAHQpIky8kVEpH5QsK8DrVpB3766shcRkfpBwb6OKCNfRETqCwX7OlJUFBL0NmzIdk1ERKSxU7CvI7EkvZkzs1sPERERBfs6Egv2StITEZFsU7CvI/vvD/vso/v2IiKSfQr2dUTd5oqISH2hYF+HYsFe3eaKiEg2KdjXoaIi2LgRFi3Kdk1ERKQxU7CvQ+o2V0RE6gMF+zo0YEC4d6+MfBERyaZqBXsz29/MjqyryuSa1q3hwAN1ZS8iItmVUrA3sx5m9ibwIfDfqOwbZvbHuqxcLlBGvoiIZFuqV/b3Ay8CewHbo7IJwAl1UalcUlgI8+eHRD0REZFsSDXYDwF+4+47AQdw9/XA3nVVsVxRVATu6jZXRESyJ9VgvxzoE19gZv2BxWmvUY5RRr6IiGRbqsH+NuCfZvZtoKmZnQ08DdxcZzXLET17Qtu2ysgXEZHsaZrKQu7+sJmtAcYCS4BvAT919+frsG45Qd3miohItqUU7M3siCiwP59QPsTdp9ZBvXJKYSE88US4d2+W7dqIiEhjk2oz/oQk5f9OV0VyWWEhbNgAn3yS7ZqIiEhjVGWwN7MmZpYX3ppF07HXgUBZqjsys5PNbK6ZzTOzayuZf5CZTTGzrWZ2ZVz5/mY2yczmmNksM7usOh+wPlCSnoiIZNOeruzLgG1AfvR+e9xrNnBvKjuJThjuAU4B+gNnR9n88dYAlxKSARPrcIW7HwwcCVxUybr12sCB4aeCvYiIZMOe7tn3Agx4FTg2rtyBle6+OcX9DAHmufsCADN7CjidcMIQNui+AlhhZqPiV3T3z4DPovefm9kcoFv8uvVdmzZwwAHKyBcRkeyoMti7e+wuc89a7qcbIYs/phQ4orobMbMCYBDwdi3rk3HKyBcRkWxJKRsfwMy+AgwDOhCu9gFw92+lsnolZZ7qvqP9twH+Clzu7huSLDOW8HggPXr0qM7m61xRETz/PGzaBPn52a6NiIg0JqkOhPNzQv/4TYBvAquBk4B1Ke6nFNg/bro7sDTVSppZM0KgH+/uf0u2nLs/4O6D3X1wx44dU918RhQWqttcERHJjlQfvfsOcIK7/xDYFv38MlCQ4vrTgAPNrJeZNQfOAl5IZUUzM+AhYI67/y7F/dU7ysgXEZFsSbUZfx93j12TbjOzZu4+1cyGpbKyu5eZ2cXAy0Ae8LC7zzKzC6P595lZZ6AEaAvsNLPLCZn7hcB5wAdmNiPa5PXu/lKKda8XevUKiXoK9iIikmmpBvv5ZjbA3WcBM4Hvm9laYG2qO4qC80sJZffFvV9GaN5P9AaV3/NvUJo0CY/gKSNfREQyLdVg/xOgffT+WuBJoA3wg7qoVK4qLISnn1a3uSIikll7vGdvZk2ALcBbAO4+1d37uHvnqpLlZHdFRbBuHZSWZrsmIiLSmOwx2Lv7TuDv7r4tA/XJabEkPTXli4hIJqWajf+amR1ZpzVpBNRtroiIZEOq9+w/Af5lZn8n9IS3q0Mcd/9ZXVQsF7VtG7LyFexFRCSTUg32rSgfyz4+Y75aveBJaMpXM76IiGRSSsHe3b9d1xVpLAoL4R//gM2boVWrbNdGREQag1Tv2UuaFBXBzp0wu8GM2SciIg2dgn2GKSNfREQyTcE+w3r3DqPeKUlPREQyRcE+w/LywiN4CvYiIpIp1RnPvh9QROgmdxd3fzjdlcp1hYXw17+q21wREcmMlIK9mV0P/Ax4D9gUN8sBBftqKiyEBx+EpUuhW7ds10ZERHJdqlf2lwND3F2Nz2lQVBR+vv++gr2IiNS9VO/ZbwY+rMuKNCaxbnOVkS8iIpmQarD/KfB7M+tiZk3iX3VZuVy1zz7Qo4eS9EREJDNSbcZ/NPp5QVyZEe7Z56WzQo1FUZGCvYiIZEaqwb5XndaiESoshJdegi1boGXLbNdGRERyWap9438CEDXbdwKWR+PcSw0VFsKOHTBnDgwalO3aiIhILkvpnruZtTWzPwFbgE+BzWb2mJntXae1y2HxGfkiIiJ1KdUEu7uA1sAhhOFuBwL5UbnUQJ8+ofleGfkiIlLXUr1nfzLQ291jHep8ZGbfBubXTbVyX14eHHKIruxFRKTupXplvwXomFDWAdia3uo0LkVF4crePds1ERGRXJZqsP8jMMHMLjSzU8zsQuBl4IG6q1ruKyyEVatg2bJs10RERHJZqs3444ClwDlA1+j9Lahf/FqJjW3//vvQpUt26yIiIrkr1UfvYgPeKLinUXywP+mk7NZFRERyV9Jgb2bnufvj0fvvJFtOQ9zW3L77QvfuysgXEZG6VdWV/dnA49H785IsoyFua6mwUBn5IiJSt5Im6Ln7qXHvRyR5HZfqjszsZDOba2bzzOzaSuYfZGZTzGyrmV1ZnXUbsqKi0Ivetm3ZromIiOSqVHvQezdJeUmK6+cB9wCnAP2Bs82sf8Jia4BLgdtqsG6DVVgIZWUh4IuIiNSFVB+965NYYGYG9E5x/SHAPHdf4O7bgKeA0+MXcPcV7j4N2F7ddRuy+CQ9ERGRulBlNn7UHz5A87j3MQXArBT30w1YEjddChyRgXXrvb59oUWLkKR3XrLMCBERkVrY06N385O8d+BN4JkU92OVlKXab1zK65rZWGAsQI8ePVLcfHY1bQoDBujKXkRE6k6Vwd7dbwQws7fc/eVa7KcU2D9uujuhY560ruvuDxD16jd48OAG0wltYSH861/ZroWIiOSqVO/ZDzKzw+MLzGyImV2d4vrTgAPNrJeZNQfOAl7IwLoNQlERLF8eXiIiIumWarC/DJidUDYbuDyVld29DLiY0J/+HOAv7j4r6mv/QgAz62xmpcCPgJ+YWamZtU22bor1bhCUpCciInUp1b7xm7N7lvw2oGWqO3L3l4CXEsrui3u/jNBEn9K6ueSjj8LPE0+Enj1h3DgYPTq7dRIRkdyR6pX9dOAHCWUXAu+ktzqNz/jxcMUV5dOffAJjx4ZyERGRdDBPYTB1MxsATAA+I2Tl9wE6ASe4e2Lzfr0wePBgLylJqc+frCooCAE+Uc+esGhRpmsjIiINlZlNd/fBlc1LddS7WWbWFziNkBn/N+Cf7r4xfdVsnBYvrl65iIhIdaV6zx5332hmbwLd3P2tOqxTo9KjR+VX9g2kmwAREWkAUu0bv0cU6D8E/huVfcPM/liXlWsMxo2D/Pzdy4cPz3hVREQkR6WaoHc/8CKwF+VZ+ROAE+qiUo3J6NHwwAPhHr0Z7L8/DBoEjz0Gv/1ttmsnIiK5INVm/CHAKHffaWYO4O7rzWzvuqta4zF6dMVH7bZvD9NXXgmbNsFPfhJOBERERGoi1WC/nJCB/1GsIBpmVmlkdaBZM3jySWjVCn72M/jiC7jpJgV8ERGpmVSD/W3AP83sJqCpmZ0NXA/8ps5q1sg1bQqPPBLu5998c7jCv+MOaJLqjRcREZFIqo/ePWxmawgjyi0Bzgd+6u7P12HdGr0mTeDee8MV/u23w+bNcN99kJeX7ZqJiEhDUp1H754Hnq+zmkilzEKiXuvW8KtfhSv8xx4LV/4iIiKpSBoyzOw8d388ev+dKraxDVjo7m+mu3ISmMEvfxma9K+/HrZsgT//GZo3z3bNRESkIajq+vBs4PHo/XlVLNcE6G1mk9z9W2mrmezmuutCwL/8cvja1+DZZ0MTv4iISFWSBnt3PzXu/YiqNmJm+YR+86WOXXZZCPAXXginnQZ//zu0aZPtWomISH2Wcm63mbU3s/PM7KpouquZdQdw902ER/MkA8aOhT/9CSZPhpNOgvXrs10jERGpz1LtLncYMBcYDfwsKj4Q+ENsGXdfmfbaSVLnngtPPw1Tp8LIkbB6dbZrJCIi9VWqV/Z3AGe6+8lAWVT2NqFnPcmSb3wDnn8eZs6EESNg+fJs10hEROqjVIN9gbtPjN579HMb1Xh0T+rGqFHw4oswfz4MGwalpdmukYiI1DepBvvZZnZSQtnxwAdpro/UwMiR8PLLsHQpHHssLFyY7RqJiEh9kmqwvwIYb2aPAa3M7H7gUeCquqqYVM/QoTBxIqxbFwL+Rx/tcRUREWkkUgr27v4WUATMAh4GFgJD3H1aHdZNqunww0OG/tatIeDPnJntGomISH2Q8qN37v6pu9/i7he5+2+Afc3smTqsm9RAYSG89lroP3/4cHjnnWzXSEREsq3KYG9m+Wb2SzP7h5n9zszamllvM3sO+B+wIjPVlOo46KAQ8Nu0geOOgylTsl0jERHJpj1d2d8DfBmYTUjI+yvwKqE5v8DdL6rb6klNHXBACPgdO8IJJ8CkSdmukYiIZMuegv1JwInufg1wKjASOMfdf+Luq+q8dlIrPXqEgN+zJ5x6Kvz739mukYiIZMOegn0bd18B4O6lwEZ3f73uqyXp0qULvPpqaNr/yldCJzwiItK47KlTnKZmNgKwWEHitLu/Ukd1kzTp0AFeeQVOOSX0uvf443D22dmulYiIZMqegv0KwqN2MasTph3one5KSfq1awcTJsCXvwyjR8PmzfCd72S7ViIikglVNuO7e4G796rilXKgN7OTzWyumc0zs2srmW9mdlc0/30zOzRu3g/NbJaZzTSzP5tZy+p9TAHYay946aWQsPfd78I992S7RiIikgkpP2dfG2aWR8jsPwXoD5xtZv0TFjuFMJLegcBYohH1zKwbcCkw2N0PAfKAszJR71yUnw8vvACnnw4XXwy33prtGomISF3LSLAnjI43z90XuPs24Cng9IRlTgf+5MFbwD5m1iWa15TQTW9TIB9YmqF656QWLeCZZ+DMM+Hqq+HGG8F9z+uJiEjDlKlR67oBS+KmS4EjUlimm7uXmNltwGJgM/Afd/9PXVa2MWjWDMaPh1at4IYb4Isv4OabwWyPq4qISAOTqSv7ykJI4rVkpcuYWTvCVX8voCvQ2szOrXQnZmPNrMTMSlauXFmrCjcGeXnw0EPwgx+E5vxLLoGdO7NdKxERSbdMXdmXAvvHTXdn96b4ZMscDyx095UAZvY34GjgicSduPsDwAMAgwcPVsN0Cpo0gbvvDlf4v/1tyNJ/4IFwIiAiIrkhU8F+GnCgmfUCPiUk2J2TsMwLwMVm9hShiX+9u39mZouBI80sn9CMPxIoyVC9GwWzcGXfujX84hch4D/2WGjqFxGRhi8jwd7dy8zsYuBlQjb9w+4+y8wujObfB7xE6JJ3HrAJ+HY0720zexZ4BygD3iW6epf0MQuJevn5cO21IeA/9VRI5hMRkYbNPEfTsAcPHuwlJWoAqInf/x4uvRROPhn+9rfQxC8iIvWbmU1398GVzctUgp40IJdcAg8+CC+/DKNGwcaN2a6RiIjUhoK9VOqCC0If+q+9BieeCOvWZbtGIiJSUwr2ktTo0fCXv0BJCYwcCas0qLGISIOkYC9VOuOMMCzurFkwYgTcey8UFIRH9goKQsc8UnPjx+t4ikjdU4KepGTixDBEbllZxa518/PDc/mjR2evbg3V+PEwdixs2lRepuMpIjVVVYKegr2krHNnWL589/JWrcJ9fame//wnPOKYqGdPWLQo49URkQauqmCfqU51JAesWFF5+ebNCk41UVmgB/jkE7jiipAnceyx0KZNZuslIrlHV/aSsoKCEIgS6Uq0ZpIdz1hHRlu3QtOmcMQRIfCPHAlHHgnNm2e0miLSQOg5e0mLcePCPeV4+fmhXKov2fF86CFYuxYmTIArr4Rt2+BXv4Jhw6Bdu9DZ0a23wjvvaOAiEUmNruylWsaPhx//GBYvhh49QsBSMlnNpXo8162DyZNDouTEiTBnTijfd9/wlETsyv/AAzVMsUhjpQS92lB0k3po6VJ45ZXy4L9kSSjv3r088I8cCV27ZreeIpI5CvY1pWejpAFwh3nzygP/pEmwenWYd9BB5YF/+PBwG0BEcpOCfU0pI00aoJ074b33yoP/a6+F89UmTeDQQ8uD/zHH7J4zICINl4J9TTVpUrEHmRgzZUZJg7FtG7z9dnnwf+ut0DlS8+Zw9NHlwf/ww0P2v4g0TAr2NaUre8lBGzfC66+XB/8ZM0L5XnuFjP9Y8D/kECX7iTQk6lSnpsaN2/2efV6enjWTBq1Nm9D18SmnhOlVq8J9/ljw/+c/Q/l++8Fxx5UH/169sldnEakdBfuqxJLwYtn4bdvC+vWwcGF26yWSRh06wDe/GV4QvuqxwD9xIjz1VCjv1as88B93XDgZEJGGQc341eEO558fBnofPx7OOSe92xepZ9zDM/2xwD95cjjfBRg4sDz4H3tsOBcWkezRPft02roVTjoJpkwJ//2GDk3/PkTqqbKy0HNfLPi/+SZs2RLubg0ZUh78jzqqvNtfEckMBft0W7Mm/DdbvToE/QMPrJv9iNRzW7bA//5XHvynTQsPqrRqFc6DY8F/0KBwQiAidUfBvi7Mnx9GJWnXLgT89u3rbl8iDcT69fDqq+XBf9asUN6uXejUJxb8+/VTpr9IuinY15U33wz/uYYMCaOWqN1SpIJlyyp26xt7krVr14rd+nbvnt16iuQCBfu69NRTcPbZIXP/8cd1uSKShDssWFAe+F95JTz2B9C3b3ngHzEiDPAjItWj5+zr0llnhf9gP/4x9OkDN9yQ7RqJ1EtmcMAB4TV2bLi3/8EH5cH/8cfhD38Iyw0aVB78hw6F1q2zXXuRhk1X9ungDt/9LjzyCDz2GHzrW5nZr0gO2b4dpk4tD/5TpoSyZs1CPmws+A8ZEspEpCI142fCtm2hS7LXXw/374cNy9y+RXLQF1/AG2+UB/933w3n1W3ahOf6Y8F/4MAwjIVIY6dgnynr1oWRRZYtC5cl/fpldv8iOWzNmord+n70USjv0KFit769eyt1RhonBftMWrgwPJLXpk0YXqxjx8zXQaQRKC2t2K3v0qWhvGfPit36du6c3XqKZEq9CPZmdjJwJ5AH/NHdf5Mw36L5pwKbgDHu/k40bx/gj8AhgAPfcfcpVe0va8Eewniiw4eHwcMnToSWLbNTD5FGwh3mzi0P/JMmhYY2gAEDyoP/sGGw995ZrapInakq2GfkTpeZ5QH3AKcA/YGzzax/wmKnAAdGr7HAH+Lm3Qn8290PAoqAOXVe6do44gh44onQtdiYMSHtWKQy48eHoZSbNAk/x4/Pdo0aJDM46CC46CL429/CI33TpsFvfhOe6X/wQTj99ND31ZFHhodnXnkl9AAo0hhk5MrezI4CbnD3k6Lp6wDc/aa4Ze4HJrv7n6PpucBw4AvgPaC3V6OyWb2yj7n1Vrj6arj+eg2LK7sbP373IZTz8+GBB8pHXJS02Lq1fDiLiRND1v+OHaHR7Zhjyq/8DztM3fpKw1UfnrPvBiyJmy4FjkhhmW5AGbASeMTMioDpwGXu/kXdVTdNrrwS5s2DX/86PFz8ne9ku0aSbe6wfDnMnAmXXFIx0EOYvuSSMIRc797hal8Pmddaixbhztrw4fDLX8KGDfDaa+XB//rrw3J7712xW9+DD1ayn+SGTAX7yv5cEq/Sky3TFDgUuMTd3zazO4FrgZ/uthOzsYRbAPTo0aNWFU4LM7j7bli0CL73vfLMIWkcPv88dA7/wQfhNXNm+BnrNi6ZtWvhK18pn+7UKQwm37v37j+7d9elaA20bQunnRZeACtWVOzW9+9/D+VdulTM9K8P/1ZEaqIhNOM78Ja7F0TlXwKudfdRVe2zXjTjx6xfH7oBW7Ik3Mfvn5iuIA3atm3hObDEoL5oUfkyrVvDIYeEh8IHDgzvzz8/pJQn6t4dnnkmPNmxYEHFn4sXV8wBado0nEQmOxnYd19dmtbAwoUVu/VdsSKU9+lTsVvfDh2yW0+ReFnPxjezpsBHwEjgU2AacI67z4pbZhRwMSEb/wjgLncfEs17HbjA3eea2Q1Aa3e/qqp91qtgD+Gf9BFHhJuEb70VrtakYdm5M/weE4P63LmhqzcIwbdfv/KAHgvuPXvu3vNLTe7Zb98eThpjwT/xhCCx1WCvvSo/CejVK9wiaNUqbYcnV7mHX3Us+L/6ami0ASguLg/+X/pSeOJWJFuyHuyjSpwK3EF49O5hdx9nZhcCuPt90aN3dwMnEx69+7a7l0TrFhMevWsOLIjmra1qf/Uu2AOUlISuvwYODM8G5ednu0aSzKpVuwf1mTNh48byZXr23D2o9+sHzZunvp/x40Nq+OLFoY143LjaJed9/nnlJwGxn4np5126JD8Z6NpVtwgqUVYWMv1jwf9//wuNO02bhkz/WPA/4ojqfRVEaqteBPtMq5fBHuD55+GMM8LrL39RP5/Z9sUXMHt2xaD+wQchiS6mffuKze8DB4aHt9u2zV69ayKWHBgf/OPfl5aGZWKaNw8nNMlOBtq1y95nqUc2bQqjXceC//Tp4TC2bh2u9mPBv6hIf+5StxTs65vbb4cf/Sg8lnfzzdmuTeNQVgYff7x7UF+woDzAtWoVgnji1XqnTo3jvve2bWHA+WQtA2vWVFx+n32S5wr07BlS4BuhtWth8uTy4P/hh6G8fftwnz8W/Pv0aRxfK8kcBfv6xj08XnXPPXD//eG+raSHe7hCTQzqc+aEYAbh8qpv34oBfeDAEKjUbJ3c+vXJbw8sWhQeZo8xg27dkp8MdO7caC5zP/20YqZ/LCdz//3LA//IkeGOikhtKNjXR2VloUuvl1+Gl16CE0/Mdo0anrVrdw/qM2eGoBTTvfvuV+oHHaQujNNt50747LPkJwOfflpx+RYtQuBPdjLQ0G6RpMg9NDDFd+sbazA5+ODywD98eGg4EakOBfv66vPPw029Dz8Mj0gtW5aeJK1cs3lzuDJPDOrxAWSffXYP6gMG6L5yfbFlS/ktgspOBuJP0CD8PSTLFejRI2cy33buhBkzyoP/66+HHIAmTUJvfrHgf8wxenBC9kzBvj77/e/hsssqJkY11i5Td+yA+fN3D+off1z+bHmLFqGfgsRn1rt10w3Qhmzt2spPAhYuDLcIYo82QoiE3bsnPxlowDkW27aFJ3Njwf/tt0MjYIsWYfTsWPAfPDhk/4vEU7CvzwoKwhVPorZt4YYbwj+u/fYLr06dQpZPQ/8rdw9NvolBffbscBUP4Z91nz67B/U+fRr+55fq2bEjjF+b7GTgs88qLp+fH/6ukp0MNKCH4T//PFztx4L/e++F8rZtwwh+seA/YECDPb+RNFKwr8+aNKl4Vb8nZiHgJ54EJHuf7X7V16+vvMvY+MzuLl12D+r9+6sfAknN5s3h6r+yk4EFCyr2jQDQsWPyXIH996/XJ5MrV4b7/LHgP39+KO/UqWK3vgUFWa2mZImCfX2W7Mq+R49wM2/FivBavnz39/Flifc8Y/Lz93xCEHvfvv2es9GTdQKzdWvoSS4xqC9eXL7uXnvtHtQPOUR9jkrdcYfVq5PnCixeHNrJY/Lywvc62clAhw716hL6k0/KA//EieXdQ/TuXR74jzsunN9I7lOwr8/SNczpli3htD/ZiUHi+x07dt9Gkybhn1myE4LZs+Heeyv2wpaXF+avWFH+T7NZs5DxntgRTY8e9eofpQhlZeFZuGQnA7FO8WNat05+e6BXr6y2RrmHP9FY4J88OYzuB1BYWB78jz02nHdL7lGwr+/S3WXqnuzcGRKiUj0xiHUEnkyrVqGToFhQ79s3BHyRhm7jxnCLoLIeBxcu3H2I4k6dkp8MZHiEwrKy0JtfLPi/+WZogGvaFIYMKQ/+Rx7ZaPs/yjkK9lI7mzaFVoNevSrPLzCrOBKbSGPgHk6Gk/U4mDhCYbNm4WQ+2clAHY9QuHlz6Mc/FvxLSkL1WrWq2K1vcbH6lmqoFOwlPZLlF/TsWXE4VxHZfYTCxJ+JIxS2bZs8V6CgIO0dQa1bF0bwiwX/2bNDebt2Fbv17dtXd98aCgV7SY905ReISPkIhclOBhJHKOzaNfnJQNeute5++LPPKnbrG8ut7d69YqZ/t2612o3UIQV7SZ9M5xeINEY7d4a8mWQnA5WNUFhQkPxkoJp977qHx/pigf+VV8JDDRBGcY4F/hEj1EllfaJgLyKSS7ZuDSfcyU4G1q6tuPw++yTPFUhhhMKdO+H998uD/2uvhdGhzeDQQ8uD/9Ch6h4jmxTsRUQak3XrkicOLlxYPgIklI9QmOxkoJIRCrdtg6lTy4P/W2+FFIXmzeGoo8qD/+GH68GcTFKwFxGRIDZCYbJcgcQRClu2rLr74bZt+eKLit36zpgRbgXstVd4rj8W/A85pNGMbJwVCvYiIpKa2AiFybofjvXUE9O+/W4nARva9+LNz3rzz/d7MGFyMz7+OCzasWPFZL/evTP/8XKZgr2IiNSee8gHSJYr8Mknu49QuP/+bOnai8VNe/P+hl5M+qQ376zrxQJ6k99zP0Yeb7u69e3UKXsfLRco2IuISN3bsSPcBkh2MrBsWYXFt+Tls9B7MW9nCP5bOvdi38N7c+AJvTj0671o27XhjFBYHyjYi4hI9m3aVLH74YUL8fkL2Dx7IXmLF9BiW8URCtc07cgX+/Wmeb9etD+8N00PjLtdUM9HKMyGqoK9jpSIiGRGfn4Yvrp//11FBuTDrhEKt85ZwLwJC/n09QVsmr2QvZYuoGDpVNpPegYoH8DL8/KwqrofrmcjFGabruxFRKTe2rAhdOs7aUIZs14uZftHC+jFQvq3WMDhHRfSt+kCOny+kKarE0YobNMm+YlAQUFOdgigZnwREckJy5dX7NY3NixHn84b+cbgRZxwwAIObbeQfdbsYYTCzp0rDk8cf0LQrVuDHA1IwV5ERHLSggUVu/VduTKU9+0b163vcGffshXJEweXLNl9hMKePZN3P9yuXb28RaBgLyIiOW/nTpg5szz4v/oqbNwY4vKgQeXP+H/pS9C6ddyK27dX3f1wbGCAmLZtKwb/+Pc9e+55hMI6GmNEwV5ERBqd7dth2rTy4D9lSujqt1kzOPLI8iv/I47YQ7e+GzZU3f1w4giF3bolbxWYNAm+9706GT1UwV5ERBq9TZvgjTfKg/8774SHAFq3rtitb2FhNbr1jY1QmKz74cQRCpPp2bM8AaGG6kWwN7OTgTuBPOCP7v6bhPkWzT8V2ASMcfd34ubnASXAp+5+2p72p2AvIiJVWbMGJk8uD/5z54byDh3C8L2x4H/AAbW4RR8boTAW/L///cqXM6uYN1ADWQ/2UaD+CDgBKAWmAWe7++y4ZU4FLiEE+yOAO939iLj5PwIGA20V7EVEJN1KSytm+sfGBOrRozzwjxwZEvlrrKAgdCucqI6v7DM1/tAQYJ67L3D3bcBTwOkJy5wO/MmDt4B9zKwLgJl1B0YBf8xQfUVEpJHp3h2+9S147LGQoP/hh3DPPTB4MDz/PJx7LnTpEkbvu+wyeOEFWL++mjsZN273Z/zz80N5HcpUsO8GLImbLo3KUl3mDuBqoHZtHCIiIikwg3794Ac/gL/+NTzSV1ICN98c8u8efBBOPx323Tck+/34x6FVIDFXbzejR4dkvJ49w0569kxLct6eZCrYV3a3I/H+QaXLmNlpwAp3n77HnZiNNbMSMytZGXvYUkREpJby8uCww+Dqq+Hll8Pgf5MnhyCflxdOAkaODI/gH3883HQTTJ0axgZKNJ7RFLCIJuykgEWMp24DPWTunv1RwA3uflI0fR2Au98Ut8z9wGR3/3M0PRcYDlwKnAeUAS2BtsDf3P3cqvape/YiIpIpn38Or71Wfr///fdD+d57w/Dh5ff7330Xxo6tkyfv6kWCXlNCgt5I4FNCgt457j4rbplRwMWUJ+jd5e5DErYzHLhSCXoiIlKfrVgRHqmPBf8FC0J5kyaVJ92nIT8v+6PeuXuZmV0MvEx49O5hd59lZhdG8+8DXiIE+nmER+++nYm6iYiIpNt++8GZZ4YXhEA+cSJccEHlyy9eXLf1Uac6IiIiGVKHT97Vi0fvREREGr0sPXmnYC8iIpIpWXryLjP37EVERCQYPbrug3siXdmLiIjkOAV7ERGRHKdgLyIikuMU7EVERHKcgr2IiEiOU7AXERHJcQr2IiIiOU7BXkREJMflbN/4ZrYSiPVA3AFYlcXq5CId0/TS8Uw/HdP00vFMv3Qf057u3rGyGTkb7OOZWUmywQGkZnRM00vHM/10TNNLxzP9MnlM1YwvIiKS4xTsRUREclxjCfYPZLsCOUjHNL10PNNPxzS9dDzTL2PHtFHcsxcREWnMGsuVvYiISKOV08HezE42s7lmNs/Mrs12fRoKM3vYzFaY2cy4sn3NbIKZfRz9bBc377roGM81s5OyU+v6y8z2N7NJZjbHzGaZ2WVRuY5pDZlZSzObambvRcf0xqhcx7QWzCzPzN41s39G0zqetWBmi8zsAzObYWYlUVlWjmnOBnszywPuAU4B+gNnm1n/7NaqwXgUODmh7FpgorsfCEyMpomO6VnAgGide6NjL+XKgCvc/WDgSOCi6LjpmNbcVuA4dy8CioGTzexIdExr6zJgTty0jmftjXD34rhH7LJyTHM22ANDgHnuvsDdtwFPAadnuU4Ngru/BqxJKD4deCx6/xjw1bjyp9x9q7svBOYRjr1E3P0zd38nev854Z9pN3RMa8yDjdFks+jl6JjWmJl1B0YBf4wr1vFMv6wc01wO9t2AJXHTpVGZ1Ewnd/8MQvAC9ovKdZyrwcwKgEHA2+iY1krU5DwDWAFMcHcd09q5A7ga2BlXpuNZOw78x8ymm9nYqCwrx7RpujZUD1klZXr0IP10nFNkZm2AvwKXu/sGs8oOXVi0kjId0wTuvgMoNrN9gOfM7JAqFtcxrYKZnQascPfpZjY8lVUqKdPx3N0x7r7UzPYDJpjZh1UsW6fHNJev7EuB/eOmuwNLs1SXXLDczLoARD9XROU6zikws2aEQD/e3f8WFeuYpoG7rwMmE+5z6pjWzDHAV8xsEeGW53Fm9gQ6nrXi7kujnyuA5wjN8lk5prkc7KcBB5pZLzNrTkh8eCHLdWrIXgDOj96fD/w9rvwsM2thZr2AA4GpWahfvWXhEv4hYI67/y5ulo5pDZlZx+iKHjNrBRwPfIiOaY24+3Xu3t3dCwj/K19x93PR8awxM2ttZnvF3gMnAjPJ0jHN2WZ8dy8zs4uBl4E84GF3n5XlajUIZvZnYDjQwcxKgZ8DvwH+YmbfBRYD3wRw91lm9hdgNiHr/KKoeVXKHQOcB3wQ3WMGuB4d09roAjwWZSs3Af7i7v80synomKaTvqM114lwewlCrH3S3f9tZtPIwjFVD3oiIiI5Lpeb8UVERAQFexERkZynYC8iIpLjFOxFRERynIK9iIhIjlOwF8lhZvaomf0qS/s2M3vEzNaaWbWeF45GCzu+ruom0tgo2ItkUBTElkedbMTKLjCzyVmsVl0ZCpwAdHf3jA+SYmY3RL3AiTR6CvYimdeUMJRog1KD4TZ7Aovc/Yu6qE9dM7Oc7XRMGh8Fe5HMuxW4MtbdazwzKzAzjw80ZjbZzC6I3o8xszfN7HYzW2dmC8zs6Kh8iZmtMLPzEzbbwcwmmNnnZvaqmfWM2/ZB0bw1ZjbXzP5f3LxHzewPZvaSmX0BjKikvl3N7IVo/Xlm9n9R+XcJQ6UeZWYbzezGyg6Emf2fmc2J6jbbzA6tZJkKtyLMbHjUs2Ns+hoz+zTaxlwzG2lmJxN6KTwz2v970bJ7m9lDZvZZtM6vYicxCcd2DXCDmfWJjtl6M1tlZk9X9jlE6juduYpkXglh4JYrgZ/UYP0jCIG0PXAjYeCSfwB9gGHAX83sr3HjvY8mjFP+NnALMB4YGt1KmAD8DDgFKCQMxzkrrmvpc4BTgdOA5pXU5c/ALKArcBBhZK8F7v6Qme0ALnD3oZV9CDP7JnADYTzvEuAAYHt1DoSZ9QMuBg6PRhcrAPLcfb6Z/RroE/XxHvMYsJxwrFoD/yQMK3p/NP8IwvHcD2gGPAz8h3Ci0xwYXJ36idQXurIXyY6fAZeYWccarLvQ3R+J+s1+mjBS1i/cfau7/wfYRghmMS+6+2vuvhX4MeFqe39CAF8UbavM3d8hjMz3jbh1/+7ub7r7TnffEl+JaBtDgWvcfYu7zyCchJyX4ue4ALjF3ad5MM/dP6nmsdgBtAD6m1kzd1/k7vMrW9DMOhFOai539y+ikchuJwz8ErPU3X8fHY/NhJOPnkDX6DO+Uc36idQLCvYiWeDuMwlXldfWYPXlce83R9tLLGsTN70kbr8bgTWEK/GewBHR7YB1ZraO0ArQubJ1K9EVWOPun8eVfQJ0S/Fz7A9UGphT5e7zgMsJLQQrzOwpM+uaZPGehKv1z+I+7/2Eq/iYxM97NWGc8almNsvMvlOb+opki4K9SPb8HPg/KgbHWDJbflxZfPCtiV1jZJtZG2BfwjjZS4BX3X2fuFcbd/9+3LpVjZS1FNjXomE8Iz2AT1Os1xJC0/2efEEVx8Pdn4xuFfQk1Pfm2KxK9rcV6BD3edu6+4D4zSVse5m7/5+7dwW+B9xrZvGtJiINgoK9SJZEV6VPA5fGla0kBMtzzSwvupJMJSBW5VQzG2pmzYFfAm+7+xJCy0JfMzvPzJpFr8PN7OAU678E+B9wk5m1NLNC4LuEnIBU/JGQqHhY9Ex+n/jkwTgzos+wr5l1JlzJA+GevZkdZ2YtgC2EVo3YsKDLgQIzaxLV9zPC/fffmllbM2tiZgeY2bBkFTSzb5pZ92hyLeFkQEO5SoOjYC+SXb8gJIrF+z/gKmA1MIAQUGvjSUIrwhrgMEJTPVHz+4mEe9ZLgWWEq+IW1dj22UBBtP5zwM/dfUIqK7r7M8C4qH6fA88TWh0SPQ68BywiBOv4jPgWhDHXV0X134+QhQ/wTPRztZm9E73/FiHRbjYheD8LdKmimocDb5vZRuAF4DJ3X5jK5xOpTzSevYiISI7Tlb2IiEiOU7AXERHJcQr2IiIiOU7BXkREJMcp2IuIiOQ4BXsREZEcp2AvIiKS4xTsRUREcpyCvYiISI77/zPuN/TuAvI0AAAAAElFTkSuQmCC\n",
+      "text/plain": [
+       "<Figure size 576x360 with 1 Axes>"
+      ]
+     },
+     "metadata": {
+      "needs_background": "light"
+     },
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "y = mean_rejection_data\n",
+    "x = y.index.values\n",
+    "\n",
+    "plt.rcParams[\"figure.figsize\"] = (8, 5)\n",
+    "plt.xlabel(\"Number of clusters\", fontsize=12)\n",
+    "plt.ylabel(\"Rejection rate\", fontsize=12)\n",
+    "plt.plot(x, y[\"uniform\"], label=\"Uniform Bootstrap\", color=\"blue\", marker=\"o\")\n",
+    "plt.plot(x, y[\"cluster\"], label=\"Cluster Bootstrap\", color=\"red\", marker=\"o\")\n",
+    "plt.legend()\n",
+    "plt.suptitle(\"Comparison of Rejection Rates\", fontsize=15)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "We can see that when the number of clusters is low, it is particularly important to use the cluster robust bootstrap, since rejection with the regular bootstrap is excessive. For a large number of clusters, clustering naturally becomes less important. "
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.8.8"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/docs/source/explanations/inference/index.rst b/docs/source/explanations/inference/index.rst
index 936dce43c..c67168ef5 100644
--- a/docs/source/explanations/inference/index.rst
+++ b/docs/source/explanations/inference/index.rst
@@ -6,3 +6,5 @@ Inference
    :maxdepth: 1
 
    background_moments_inference
+   bootstrap_ci
+   bootstrap_montecarlo_comparison.ipynb
diff --git a/docs/source/how_to_guides/inference/how_to_calculate_bootstrap_confidence_intervals.ipynb b/docs/source/how_to_guides/inference/how_to_calculate_bootstrap_confidence_intervals.ipynb
deleted file mode 100644
index 412b81bda..000000000
--- a/docs/source/how_to_guides/inference/how_to_calculate_bootstrap_confidence_intervals.ipynb
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "metadata": {},
-   "source": [
-    "# How to calculate bootstrap confidence intervals"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  },
-  "language_info": {
-   "codemirror_mode": {
-    "name": "ipython",
-    "version": 3
-   },
-   "file_extension": ".py",
-   "mimetype": "text/x-python",
-   "name": "python",
-   "nbconvert_exporter": "python",
-   "pygments_lexer": "ipython3",
-   "version": "3.7.8"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 2
-}
diff --git a/docs/source/how_to_guides/inference/how_to_do_bootstrap_inference.ipynb b/docs/source/how_to_guides/inference/how_to_do_bootstrap_inference.ipynb
new file mode 100644
index 000000000..87f03c3ba
--- /dev/null
+++ b/docs/source/how_to_guides/inference/how_to_do_bootstrap_inference.ipynb
@@ -0,0 +1,534 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import numpy as np\n",
+    "import pandas as pd\n",
+    "import seaborn as sns\n",
+    "import statsmodels.api as sm"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Bootstrap Tutorial\n",
+    "\n",
+    "This notebook contains a tutorial on how to use the bootstrap functionality provided by estimagic. We start with the simplest possible example of calculating standard errors and confidence intervals for an OLS estimator without and clustering. Then we progress to more advanced examples.\n",
+    "\n",
+    "In this example, we will work with the \"exercise\" example dataset taken from the seaborn library.\n",
+    "\n",
+    "The working example will be a linear regression to investigate the effects of exercise time on pulse.\n",
+    "\n",
+    "## Prepare the dataset"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [
+    {
+     "output_type": "execute_result",
+     "data": {
+      "text/plain": [
+       "   id     diet  pulse  time  kind  constant\n",
+       "0   1  low fat     85     1  rest         1\n",
+       "1   1  low fat     85    15  rest         1\n",
+       "2   1  low fat     88    30  rest         1\n",
+       "3   2  low fat     90     1  rest         1\n",
+       "4   2  low fat     92    15  rest         1"
+      ],
+      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>id</th>\n      <th>diet</th>\n      <th>pulse</th>\n      <th>time</th>\n      <th>kind</th>\n      <th>constant</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>1</td>\n      <td>low fat</td>\n      <td>85</td>\n      <td>1</td>\n      <td>rest</td>\n      <td>1</td>\n    </tr>\n    <tr>\n      <th>1</th>\n      <td>1</td>\n      <td>low fat</td>\n      <td>85</td>\n      <td>15</td>\n      <td>rest</td>\n      <td>1</td>\n    </tr>\n    <tr>\n      <th>2</th>\n      <td>1</td>\n      <td>low fat</td>\n      <td>88</td>\n      <td>30</td>\n      <td>rest</td>\n      <td>1</td>\n    </tr>\n    <tr>\n      <th>3</th>\n      <td>2</td>\n      <td>low fat</td>\n      <td>90</td>\n      <td>1</td>\n      <td>rest</td>\n      <td>1</td>\n    </tr>\n    <tr>\n      <th>4</th>\n      <td>2</td>\n      <td>low fat</td>\n      <td>92</td>\n      <td>15</td>\n      <td>rest</td>\n      <td>1</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
+     },
+     "metadata": {},
+     "execution_count": 2
+    }
+   ],
+   "source": [
+    "df = sns.load_dataset(\"exercise\", index_col=0)\n",
+    "replacements = {\"1 min\": 1, \"15 min\": 15, \"30 min\": 30}\n",
+    "df = df.replace({\"time\": replacements})\n",
+    "df[\"constant\"] = 1\n",
+    "\n",
+    "df.head()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Doing a very simple bootstrap"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The first thing we need is a function that calculates the bootstrap outcome, given an empirical or re-sampled dataset. The bootstrap outcome is the quantity for which you want to calculate standard errors and confidence intervals. In most applications those are just parameter estimates.\n",
+    "\n",
+    "In our case, we want to regress \"pulse\" on \"time\" and a constant, and the function looks as follows:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def ols_fit(data):\n",
+    "\n",
+    "    y = data[\"pulse\"]\n",
+    "    x = data[[\"constant\", \"time\"]]\n",
+    "    params = sm.OLS(y, x).fit().params\n",
+    "    return params"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The outcome function must return a pandas Series.\n",
+    "\n",
+    "Now we can calculate confidence intervals and standard errors."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [
+    {
+     "output_type": "execute_result",
+     "data": {
+      "text/plain": [
+       "               mean       std   lower_ci   upper_ci\n",
+       "constant  93.815998  1.566557  90.806508  97.014317\n",
+       "time       0.376655  0.127959   0.147757   0.647338"
+      ],
+      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>mean</th>\n      <th>std</th>\n      <th>lower_ci</th>\n      <th>upper_ci</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>constant</th>\n      <td>93.815998</td>\n      <td>1.566557</td>\n      <td>90.806508</td>\n      <td>97.014317</td>\n    </tr>\n    <tr>\n      <th>time</th>\n      <td>0.376655</td>\n      <td>0.127959</td>\n      <td>0.147757</td>\n      <td>0.647338</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
+     },
+     "metadata": {},
+     "execution_count": 4
+    }
+   ],
+   "source": [
+    "from estimagic.inference import bootstrap\n",
+    "\n",
+    "results_without_cluster = bootstrap(data=df, outcome=ols_fit)\n",
+    "results_without_cluster"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "The above function call represents the minimum that a user has to specify, making full use of the default options, such as drawing a 1000 bootstrap draws, using the \"percentile\" bootstrap confidence interval, not making use of parallelization, etc.\n",
+    "\n",
+    "If we would for example want to make 10000 draws, while parallelizing on two cores and using a \"bca\" type confidence interval, we would simply call the following."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [
+    {
+     "output_type": "execute_result",
+     "data": {
+      "text/plain": [
+       "              mean       std   lower_ci   upper_ci\n",
+       "constant  93.79045  1.557405  91.757155  97.354431\n",
+       "time       0.38619  0.126238   0.120206   0.557303"
+      ],
+      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>mean</th>\n      <th>std</th>\n      <th>lower_ci</th>\n      <th>upper_ci</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>constant</th>\n      <td>93.79045</td>\n      <td>1.557405</td>\n      <td>91.757155</td>\n      <td>97.354431</td>\n    </tr>\n    <tr>\n      <th>time</th>\n      <td>0.38619</td>\n      <td>0.126238</td>\n      <td>0.120206</td>\n      <td>0.557303</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
+     },
+     "metadata": {},
+     "execution_count": 5
+    }
+   ],
+   "source": [
+    "results_without_cluster2 = bootstrap(\n",
+    "    data=df, outcome=ols_fit, n_draws=10_000, ci_method=\"bca\", n_cores=2\n",
+    ")\n",
+    "\n",
+    "results_without_cluster2"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Doing a clustered bootstrap"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "In the cluster robust variant of the bootstrap, the original dataset is divided into clusters according to the values of some user-specified variable, and then clusters are drawn uniformly with replacement in order to create the different bootstrap samples. \n",
+    "\n",
+    "In order to use the cluster robust boostrap, we simply specify which variable to cluster by. In the example we are working with, it seems sensible to cluster on individuals, i.e. on the column \"id\" of our dataset."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {},
+   "outputs": [
+    {
+     "output_type": "execute_result",
+     "data": {
+      "text/plain": [
+       "               mean       std   lower_ci   upper_ci\n",
+       "constant  93.729417  1.188667  91.360832  96.070291\n",
+       "time       0.380310  0.101324   0.194380   0.584603"
+      ],
+      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>mean</th>\n      <th>std</th>\n      <th>lower_ci</th>\n      <th>upper_ci</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>constant</th>\n      <td>93.729417</td>\n      <td>1.188667</td>\n      <td>91.360832</td>\n      <td>96.070291</td>\n    </tr>\n    <tr>\n      <th>time</th>\n      <td>0.380310</td>\n      <td>0.101324</td>\n      <td>0.194380</td>\n      <td>0.584603</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
+     },
+     "metadata": {},
+     "execution_count": 6
+    }
+   ],
+   "source": [
+    "results_with_cluster = bootstrap(data=df, outcome=ols_fit, cluster_by=\"id\")\n",
+    "\n",
+    "results_with_cluster"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "We can see that the estimated standard errors are indeed of a smaller magnitude when we use the cluster robust bootstrap. \n",
+    "\n",
+    "Finally, we can compare the results to full sample regressions using the statsmodels regression function and see that the cluster robust bootstrap gives standard error estimates very close to the cluster robust regression, while the regular bootstrap seems to overestimate the standard errors of both coefficients.\n",
+    "\n",
+    "Note: We would not expect the asymptotic statsmodels standard errors to be exactly the same as the bootstrapped standard errors.\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [
+    {
+     "output_type": "execute_result",
+     "data": {
+      "text/plain": [
+       "<class 'statsmodels.iolib.summary.Summary'>\n",
+       "\"\"\"\n",
+       "                            OLS Regression Results                            \n",
+       "==============================================================================\n",
+       "Dep. Variable:                  pulse   R-squared:                       0.096\n",
+       "Model:                            OLS   Adj. R-squared:                  0.086\n",
+       "Method:                 Least Squares   F-statistic:                     13.75\n",
+       "Date:                Fri, 02 Jul 2021   Prob (F-statistic):           0.000879\n",
+       "Time:                        11:35:16   Log-Likelihood:                -365.51\n",
+       "No. Observations:                  90   AIC:                             735.0\n",
+       "Df Residuals:                      88   BIC:                             740.0\n",
+       "Df Model:                           1                                         \n",
+       "Covariance Type:              cluster                                         \n",
+       "==============================================================================\n",
+       "                 coef    std err          z      P>|z|      [0.025      0.975]\n",
+       "------------------------------------------------------------------------------\n",
+       "constant      93.7611      1.205     77.837      0.000      91.400      96.122\n",
+       "time           0.3873      0.104      3.708      0.000       0.183       0.592\n",
+       "==============================================================================\n",
+       "Omnibus:                       20.828   Durbin-Watson:                   0.827\n",
+       "Prob(Omnibus):                  0.000   Jarque-Bera (JB):               26.313\n",
+       "Skew:                           1.173   Prob(JB):                     1.93e-06\n",
+       "Kurtosis:                       4.231   Cond. No.                         31.7\n",
+       "==============================================================================\n",
+       "\n",
+       "Notes:\n",
+       "[1] Standard Errors are robust to cluster correlation (cluster)\n",
+       "\"\"\""
+      ],
+      "text/html": "<table class=\"simpletable\">\n<caption>OLS Regression Results</caption>\n<tr>\n  <th>Dep. Variable:</th>          <td>pulse</td>      <th>  R-squared:         </th> <td>   0.096</td>\n</tr>\n<tr>\n  <th>Model:</th>                   <td>OLS</td>       <th>  Adj. R-squared:    </th> <td>   0.086</td>\n</tr>\n<tr>\n  <th>Method:</th>             <td>Least Squares</td>  <th>  F-statistic:       </th> <td>   13.75</td>\n</tr>\n<tr>\n  <th>Date:</th>             <td>Fri, 02 Jul 2021</td> <th>  Prob (F-statistic):</th> <td>0.000879</td>\n</tr>\n<tr>\n  <th>Time:</th>                 <td>11:35:16</td>     <th>  Log-Likelihood:    </th> <td> -365.51</td>\n</tr>\n<tr>\n  <th>No. Observations:</th>      <td>    90</td>      <th>  AIC:               </th> <td>   735.0</td>\n</tr>\n<tr>\n  <th>Df Residuals:</th>          <td>    88</td>      <th>  BIC:               </th> <td>   740.0</td>\n</tr>\n<tr>\n  <th>Df Model:</th>              <td>     1</td>      <th>                     </th>     <td> </td>   \n</tr>\n<tr>\n  <th>Covariance Type:</th>       <td>cluster</td>     <th>                     </th>     <td> </td>   \n</tr>\n</table>\n<table class=\"simpletable\">\n<tr>\n      <td></td>        <th>coef</th>     <th>std err</th>      <th>z</th>      <th>P>|z|</th>  <th>[0.025</th>    <th>0.975]</th>  \n</tr>\n<tr>\n  <th>constant</th> <td>   93.7611</td> <td>    1.205</td> <td>   77.837</td> <td> 0.000</td> <td>   91.400</td> <td>   96.122</td>\n</tr>\n<tr>\n  <th>time</th>     <td>    0.3873</td> <td>    0.104</td> <td>    3.708</td> <td> 0.000</td> <td>    0.183</td> <td>    0.592</td>\n</tr>\n</table>\n<table class=\"simpletable\">\n<tr>\n  <th>Omnibus:</th>       <td>20.828</td> <th>  Durbin-Watson:     </th> <td>   0.827</td>\n</tr>\n<tr>\n  <th>Prob(Omnibus):</th> <td> 0.000</td> <th>  Jarque-Bera (JB):  </th> <td>  26.313</td>\n</tr>\n<tr>\n  <th>Skew:</th>          <td> 1.173</td> <th>  Prob(JB):          </th> <td>1.93e-06</td>\n</tr>\n<tr>\n  <th>Kurtosis:</th>      <td> 4.231</td> <th>  Cond. No.          </th> <td>    31.7</td>\n</tr>\n</table><br/><br/>Notes:<br/>[1] Standard Errors are robust to cluster correlation (cluster)"
+     },
+     "metadata": {},
+     "execution_count": 7
+    }
+   ],
+   "source": [
+    "y = df[\"pulse\"]\n",
+    "x = df[[\"constant\", \"time\"]]\n",
+    "\n",
+    "\n",
+    "cluster_robust_ols = sm.OLS(y, x).fit(cov_type=\"cluster\", cov_kwds={\"groups\": df[\"id\"]})\n",
+    "\n",
+    "cluster_robust_ols.summary()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Splitting up the process"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "In many situations the above examples are enough. However, sometimes it is important to split up the bootstrapping process into smaller steps. Examples for such situations are:\n",
+    "\n",
+    "- You want to look at the bootstrap estimates\n",
+    "- You want to do a bootstrap with a low number of draws first and add more draws later without duplicated calculations\n",
+    "- You have more bootstrap outcomes than just the parameters\n",
+    "\n",
+    "### Calculating bootsrap outcomes"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [
+    {
+     "output_type": "execute_result",
+     "data": {
+      "text/plain": [
+       "    constant      time\n",
+       "0  92.377004  0.465963\n",
+       "1  94.549027  0.219700\n",
+       "2  94.171886  0.298749\n",
+       "3  94.087851  0.346593\n",
+       "4  93.624816  0.466219"
+      ],
+      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>constant</th>\n      <th>time</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>92.377004</td>\n      <td>0.465963</td>\n    </tr>\n    <tr>\n      <th>1</th>\n      <td>94.549027</td>\n      <td>0.219700</td>\n    </tr>\n    <tr>\n      <th>2</th>\n      <td>94.171886</td>\n      <td>0.298749</td>\n    </tr>\n    <tr>\n      <th>3</th>\n      <td>94.087851</td>\n      <td>0.346593</td>\n    </tr>\n    <tr>\n      <th>4</th>\n      <td>93.624816</td>\n      <td>0.466219</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
+     },
+     "metadata": {},
+     "execution_count": 8
+    }
+   ],
+   "source": [
+    "from estimagic.inference import get_bootstrap_outcomes\n",
+    "\n",
+    "my_outcomes = get_bootstrap_outcomes(data=df, outcome=ols_fit, seed=1234)\n",
+    "my_outcomes.head()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "To further compare the cluster bootstrap to the uniform bootstrap, let's plot the sampling distribution of the parameters on time. We can again see that the standard error is smaller when we cluster on the subject id. "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [
+    {
+     "output_type": "execute_result",
+     "data": {
+      "text/plain": [
+       "<AxesSubplot:xlabel='time', ylabel='Density'>"
+      ]
+     },
+     "metadata": {},
+     "execution_count": 9
+    },
+    {
+     "output_type": "display_data",
+     "data": {
+      "text/plain": "<Figure size 432x288 with 1 Axes>",
+      "image/svg+xml": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n  \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n<!-- Created with matplotlib (https://matplotlib.org/) -->\n<svg height=\"262.19625pt\" version=\"1.1\" viewBox=\"0 0 385.78125 262.19625\" width=\"385.78125pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n <metadata>\n  <rdf:RDF xmlns:cc=\"http://creativecommons.org/ns#\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n   <cc:Work>\n    <dc:type rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\"/>\n    <dc:date>2021-07-02T11:35:19.830815</dc:date>\n    <dc:format>image/svg+xml</dc:format>\n    <dc:creator>\n     <cc:Agent>\n      <dc:title>Matplotlib v3.3.4, https://matplotlib.org/</dc:title>\n     </cc:Agent>\n    </dc:creator>\n   </cc:Work>\n  </rdf:RDF>\n </metadata>\n <defs>\n  <style type=\"text/css\">*{stroke-linecap:butt;stroke-linejoin:round;}</style>\n </defs>\n <g id=\"figure_1\">\n  <g id=\"patch_1\">\n   <path d=\"M 0 262.19625 \nL 385.78125 262.19625 \nL 385.78125 0 \nL 0 0 \nz\n\" style=\"fill:none;\"/>\n  </g>\n  <g id=\"axes_1\">\n   <g id=\"patch_2\">\n    <path d=\"M 43.78125 224.64 \nL 378.58125 224.64 \nL 378.58125 7.2 \nL 43.78125 7.2 \nz\n\" style=\"fill:#ffffff;\"/>\n   </g>\n   <g id=\"patch_3\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 60.48548 224.64 \nL 71.221197 224.64 \nL 71.221197 222.609748 \nL 60.48548 222.609748 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_4\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 71.221197 224.64 \nL 81.956915 224.64 \nL 81.956915 218.549244 \nL 71.221197 218.549244 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_5\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 81.956915 224.64 \nL 92.692632 224.64 \nL 92.692632 218.549244 \nL 81.956915 218.549244 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_6\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 92.692632 224.64 \nL 103.42835 224.64 \nL 103.42835 214.488739 \nL 92.692632 214.488739 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_7\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 103.42835 224.64 \nL 114.164067 224.64 \nL 114.164067 182.004706 \nL 103.42835 182.004706 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_8\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 114.164067 224.64 \nL 124.899785 224.64 \nL 124.899785 184.034958 \nL 114.164067 184.034958 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_9\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 124.899785 224.64 \nL 135.635502 224.64 \nL 135.635502 153.581176 \nL 124.899785 153.581176 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_10\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 135.635502 224.64 \nL 146.37122 224.64 \nL 146.37122 125.157647 \nL 135.635502 125.157647 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_11\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 146.37122 224.64 \nL 157.106937 224.64 \nL 157.106937 86.582857 \nL 146.37122 86.582857 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_12\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 157.106937 224.64 \nL 167.842655 224.64 \nL 167.842655 39.887059 \nL 157.106937 39.887059 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_13\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 167.842655 224.64 \nL 178.578372 224.64 \nL 178.578372 21.61479 \nL 167.842655 21.61479 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_14\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 178.578372 224.64 \nL 189.31409 224.64 \nL 189.31409 17.554286 \nL 178.578372 17.554286 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_15\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 189.31409 224.64 \nL 200.049807 224.64 \nL 200.049807 27.705546 \nL 189.31409 27.705546 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_16\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 200.049807 224.64 \nL 210.785524 224.64 \nL 210.785524 54.098824 \nL 200.049807 54.098824 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_17\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 210.785524 224.64 \nL 221.521242 224.64 \nL 221.521242 35.826555 \nL 210.785524 35.826555 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_18\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 221.521242 224.64 \nL 232.256959 224.64 \nL 232.256959 72.371092 \nL 221.521242 72.371092 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_19\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 232.256959 224.64 \nL 242.992677 224.64 \nL 242.992677 141.399664 \nL 232.256959 141.399664 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_20\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 242.992677 224.64 \nL 253.728394 224.64 \nL 253.728394 163.732437 \nL 242.992677 163.732437 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_21\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 253.728394 224.64 \nL 264.464112 224.64 \nL 264.464112 151.550924 \nL 253.728394 151.550924 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_22\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 264.464112 224.64 \nL 275.199829 224.64 \nL 275.199829 177.944202 \nL 264.464112 177.944202 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_23\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 275.199829 224.64 \nL 285.935547 224.64 \nL 285.935547 208.397983 \nL 275.199829 208.397983 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_24\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 285.935547 224.64 \nL 296.671264 224.64 \nL 296.671264 214.488739 \nL 285.935547 214.488739 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_25\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 296.671264 224.64 \nL 307.406982 224.64 \nL 307.406982 218.549244 \nL 296.671264 218.549244 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_26\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 307.406982 224.64 \nL 318.142699 224.64 \nL 318.142699 218.549244 \nL 307.406982 218.549244 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_27\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 318.142699 224.64 \nL 328.878417 224.64 \nL 328.878417 218.549244 \nL 318.142699 218.549244 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_28\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 328.878417 224.64 \nL 339.614134 224.64 \nL 339.614134 222.609748 \nL 328.878417 222.609748 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_29\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 58.999432 224.64 \nL 74.217614 224.64 \nL 74.217614 214.614263 \nL 58.999432 214.614263 \nz\n\" style=\"fill:#ffa500;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_30\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 74.217614 224.64 \nL 89.435795 224.64 \nL 89.435795 210.317518 \nL 74.217614 210.317518 \nz\n\" style=\"fill:#ffa500;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_31\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 89.435795 224.64 \nL 104.653977 224.64 \nL 104.653977 193.13054 \nL 89.435795 193.13054 \nz\n\" style=\"fill:#ffa500;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_32\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 104.653977 224.64 \nL 119.872159 224.64 \nL 119.872159 173.079066 \nL 104.653977 173.079066 \nz\n\" style=\"fill:#ffa500;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_33\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 119.872159 224.64 \nL 135.090341 224.64 \nL 135.090341 130.111621 \nL 119.872159 130.111621 \nz\n\" style=\"fill:#ffa500;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_34\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 135.090341 224.64 \nL 150.308523 224.64 \nL 150.308523 125.814877 \nL 135.090341 125.814877 \nz\n\" style=\"fill:#ffa500;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_35\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 150.308523 224.64 \nL 165.526705 224.64 \nL 165.526705 68.52495 \nL 150.308523 68.52495 \nz\n\" style=\"fill:#ffa500;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_36\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 165.526705 224.64 \nL 180.744886 224.64 \nL 180.744886 101.466658 \nL 165.526705 101.466658 \nz\n\" style=\"fill:#ffa500;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_37\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 180.744886 224.64 \nL 195.963068 224.64 \nL 195.963068 72.821695 \nL 180.744886 72.821695 \nz\n\" style=\"fill:#ffa500;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_38\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 195.963068 224.64 \nL 211.18125 224.64 \nL 211.18125 69.957198 \nL 195.963068 69.957198 \nz\n\" style=\"fill:#ffa500;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_39\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 211.18125 224.64 \nL 226.399432 224.64 \nL 226.399432 79.982936 \nL 211.18125 79.982936 \nz\n\" style=\"fill:#ffa500;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_40\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 226.399432 224.64 \nL 241.617614 224.64 \nL 241.617614 124.382629 \nL 226.399432 124.382629 \nz\n\" style=\"fill:#ffa500;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_41\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 241.617614 224.64 \nL 256.835795 224.64 \nL 256.835795 122.95038 \nL 241.617614 122.95038 \nz\n\" style=\"fill:#ffa500;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_42\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 256.835795 224.64 \nL 272.053977 224.64 \nL 272.053977 145.866351 \nL 256.835795 145.866351 \nz\n\" style=\"fill:#ffa500;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_43\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 272.053977 224.64 \nL 287.272159 224.64 \nL 287.272159 170.21457 \nL 272.053977 170.21457 \nz\n\" style=\"fill:#ffa500;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_44\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 287.272159 224.64 \nL 302.490341 224.64 \nL 302.490341 200.291781 \nL 287.272159 200.291781 \nz\n\" style=\"fill:#ffa500;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_45\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 302.490341 224.64 \nL 317.708523 224.64 \nL 317.708523 210.317518 \nL 302.490341 210.317518 \nz\n\" style=\"fill:#ffa500;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_46\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 317.708523 224.64 \nL 332.926705 224.64 \nL 332.926705 211.749767 \nL 317.708523 211.749767 \nz\n\" style=\"fill:#ffa500;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_47\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 332.926705 224.64 \nL 348.144886 224.64 \nL 348.144886 216.046511 \nL 332.926705 216.046511 \nz\n\" style=\"fill:#ffa500;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"patch_48\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 348.144886 224.64 \nL 363.363068 224.64 \nL 363.363068 218.911007 \nL 348.144886 218.911007 \nz\n\" style=\"fill:#ffa500;fill-opacity:0.5;\"/>\n   </g>\n   <g id=\"matplotlib.axis_1\">\n    <g id=\"xtick_1\">\n     <g id=\"line2d_1\">\n      <defs>\n       <path d=\"M 0 0 \nL 0 3.5 \n\" id=\"mb8d63cda8e\" style=\"stroke:#000000;stroke-width:0.8;\"/>\n      </defs>\n      <g>\n       <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"71.710794\" xlink:href=\"#mb8d63cda8e\" y=\"224.64\"/>\n      </g>\n     </g>\n     <g id=\"text_1\">\n      <!-- 0.1 -->\n      <g transform=\"translate(63.759231 239.238437)scale(0.1 -0.1)\">\n       <defs>\n        <path d=\"M 31.78125 66.40625 \nQ 24.171875 66.40625 20.328125 58.90625 \nQ 16.5 51.421875 16.5 36.375 \nQ 16.5 21.390625 20.328125 13.890625 \nQ 24.171875 6.390625 31.78125 6.390625 \nQ 39.453125 6.390625 43.28125 13.890625 \nQ 47.125 21.390625 47.125 36.375 \nQ 47.125 51.421875 43.28125 58.90625 \nQ 39.453125 66.40625 31.78125 66.40625 \nz\nM 31.78125 74.21875 \nQ 44.046875 74.21875 50.515625 64.515625 \nQ 56.984375 54.828125 56.984375 36.375 \nQ 56.984375 17.96875 50.515625 8.265625 \nQ 44.046875 -1.421875 31.78125 -1.421875 \nQ 19.53125 -1.421875 13.0625 8.265625 \nQ 6.59375 17.96875 6.59375 36.375 \nQ 6.59375 54.828125 13.0625 64.515625 \nQ 19.53125 74.21875 31.78125 74.21875 \nz\n\" id=\"DejaVuSans-48\"/>\n        <path d=\"M 10.6875 12.40625 \nL 21 12.40625 \nL 21 0 \nL 10.6875 0 \nz\n\" id=\"DejaVuSans-46\"/>\n        <path d=\"M 12.40625 8.296875 \nL 28.515625 8.296875 \nL 28.515625 63.921875 \nL 10.984375 60.40625 \nL 10.984375 69.390625 \nL 28.421875 72.90625 \nL 38.28125 72.90625 \nL 38.28125 8.296875 \nL 54.390625 8.296875 \nL 54.390625 0 \nL 12.40625 0 \nz\n\" id=\"DejaVuSans-49\"/>\n       </defs>\n       <use xlink:href=\"#DejaVuSans-48\"/>\n       <use x=\"63.623047\" xlink:href=\"#DejaVuSans-46\"/>\n       <use x=\"95.410156\" xlink:href=\"#DejaVuSans-49\"/>\n      </g>\n     </g>\n    </g>\n    <g id=\"xtick_2\">\n     <g id=\"line2d_2\">\n      <g>\n       <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"114.209832\" xlink:href=\"#mb8d63cda8e\" y=\"224.64\"/>\n      </g>\n     </g>\n     <g id=\"text_2\">\n      <!-- 0.2 -->\n      <g transform=\"translate(106.258269 239.238437)scale(0.1 -0.1)\">\n       <defs>\n        <path d=\"M 19.1875 8.296875 \nL 53.609375 8.296875 \nL 53.609375 0 \nL 7.328125 0 \nL 7.328125 8.296875 \nQ 12.9375 14.109375 22.625 23.890625 \nQ 32.328125 33.6875 34.8125 36.53125 \nQ 39.546875 41.84375 41.421875 45.53125 \nQ 43.3125 49.21875 43.3125 52.78125 \nQ 43.3125 58.59375 39.234375 62.25 \nQ 35.15625 65.921875 28.609375 65.921875 \nQ 23.96875 65.921875 18.8125 64.3125 \nQ 13.671875 62.703125 7.8125 59.421875 \nL 7.8125 69.390625 \nQ 13.765625 71.78125 18.9375 73 \nQ 24.125 74.21875 28.421875 74.21875 \nQ 39.75 74.21875 46.484375 68.546875 \nQ 53.21875 62.890625 53.21875 53.421875 \nQ 53.21875 48.921875 51.53125 44.890625 \nQ 49.859375 40.875 45.40625 35.40625 \nQ 44.1875 33.984375 37.640625 27.21875 \nQ 31.109375 20.453125 19.1875 8.296875 \nz\n\" id=\"DejaVuSans-50\"/>\n       </defs>\n       <use xlink:href=\"#DejaVuSans-48\"/>\n       <use x=\"63.623047\" xlink:href=\"#DejaVuSans-46\"/>\n       <use x=\"95.410156\" xlink:href=\"#DejaVuSans-50\"/>\n      </g>\n     </g>\n    </g>\n    <g id=\"xtick_3\">\n     <g id=\"line2d_3\">\n      <g>\n       <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"156.70887\" xlink:href=\"#mb8d63cda8e\" y=\"224.64\"/>\n      </g>\n     </g>\n     <g id=\"text_3\">\n      <!-- 0.3 -->\n      <g transform=\"translate(148.757308 239.238437)scale(0.1 -0.1)\">\n       <defs>\n        <path d=\"M 40.578125 39.3125 \nQ 47.65625 37.796875 51.625 33 \nQ 55.609375 28.21875 55.609375 21.1875 \nQ 55.609375 10.40625 48.1875 4.484375 \nQ 40.765625 -1.421875 27.09375 -1.421875 \nQ 22.515625 -1.421875 17.65625 -0.515625 \nQ 12.796875 0.390625 7.625 2.203125 \nL 7.625 11.71875 \nQ 11.71875 9.328125 16.59375 8.109375 \nQ 21.484375 6.890625 26.8125 6.890625 \nQ 36.078125 6.890625 40.9375 10.546875 \nQ 45.796875 14.203125 45.796875 21.1875 \nQ 45.796875 27.640625 41.28125 31.265625 \nQ 36.765625 34.90625 28.71875 34.90625 \nL 20.21875 34.90625 \nL 20.21875 43.015625 \nL 29.109375 43.015625 \nQ 36.375 43.015625 40.234375 45.921875 \nQ 44.09375 48.828125 44.09375 54.296875 \nQ 44.09375 59.90625 40.109375 62.90625 \nQ 36.140625 65.921875 28.71875 65.921875 \nQ 24.65625 65.921875 20.015625 65.03125 \nQ 15.375 64.15625 9.8125 62.3125 \nL 9.8125 71.09375 \nQ 15.4375 72.65625 20.34375 73.4375 \nQ 25.25 74.21875 29.59375 74.21875 \nQ 40.828125 74.21875 47.359375 69.109375 \nQ 53.90625 64.015625 53.90625 55.328125 \nQ 53.90625 49.265625 50.4375 45.09375 \nQ 46.96875 40.921875 40.578125 39.3125 \nz\n\" id=\"DejaVuSans-51\"/>\n       </defs>\n       <use xlink:href=\"#DejaVuSans-48\"/>\n       <use x=\"63.623047\" xlink:href=\"#DejaVuSans-46\"/>\n       <use x=\"95.410156\" xlink:href=\"#DejaVuSans-51\"/>\n      </g>\n     </g>\n    </g>\n    <g id=\"xtick_4\">\n     <g id=\"line2d_4\">\n      <g>\n       <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"199.207908\" xlink:href=\"#mb8d63cda8e\" y=\"224.64\"/>\n      </g>\n     </g>\n     <g id=\"text_4\">\n      <!-- 0.4 -->\n      <g transform=\"translate(191.256346 239.238437)scale(0.1 -0.1)\">\n       <defs>\n        <path d=\"M 37.796875 64.3125 \nL 12.890625 25.390625 \nL 37.796875 25.390625 \nz\nM 35.203125 72.90625 \nL 47.609375 72.90625 \nL 47.609375 25.390625 \nL 58.015625 25.390625 \nL 58.015625 17.1875 \nL 47.609375 17.1875 \nL 47.609375 0 \nL 37.796875 0 \nL 37.796875 17.1875 \nL 4.890625 17.1875 \nL 4.890625 26.703125 \nz\n\" id=\"DejaVuSans-52\"/>\n       </defs>\n       <use xlink:href=\"#DejaVuSans-48\"/>\n       <use x=\"63.623047\" xlink:href=\"#DejaVuSans-46\"/>\n       <use x=\"95.410156\" xlink:href=\"#DejaVuSans-52\"/>\n      </g>\n     </g>\n    </g>\n    <g id=\"xtick_5\">\n     <g id=\"line2d_5\">\n      <g>\n       <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"241.706947\" xlink:href=\"#mb8d63cda8e\" y=\"224.64\"/>\n      </g>\n     </g>\n     <g id=\"text_5\">\n      <!-- 0.5 -->\n      <g transform=\"translate(233.755384 239.238437)scale(0.1 -0.1)\">\n       <defs>\n        <path d=\"M 10.796875 72.90625 \nL 49.515625 72.90625 \nL 49.515625 64.59375 \nL 19.828125 64.59375 \nL 19.828125 46.734375 \nQ 21.96875 47.46875 24.109375 47.828125 \nQ 26.265625 48.1875 28.421875 48.1875 \nQ 40.625 48.1875 47.75 41.5 \nQ 54.890625 34.8125 54.890625 23.390625 \nQ 54.890625 11.625 47.5625 5.09375 \nQ 40.234375 -1.421875 26.90625 -1.421875 \nQ 22.3125 -1.421875 17.546875 -0.640625 \nQ 12.796875 0.140625 7.71875 1.703125 \nL 7.71875 11.625 \nQ 12.109375 9.234375 16.796875 8.0625 \nQ 21.484375 6.890625 26.703125 6.890625 \nQ 35.15625 6.890625 40.078125 11.328125 \nQ 45.015625 15.765625 45.015625 23.390625 \nQ 45.015625 31 40.078125 35.4375 \nQ 35.15625 39.890625 26.703125 39.890625 \nQ 22.75 39.890625 18.8125 39.015625 \nQ 14.890625 38.140625 10.796875 36.28125 \nz\n\" id=\"DejaVuSans-53\"/>\n       </defs>\n       <use xlink:href=\"#DejaVuSans-48\"/>\n       <use x=\"63.623047\" xlink:href=\"#DejaVuSans-46\"/>\n       <use x=\"95.410156\" xlink:href=\"#DejaVuSans-53\"/>\n      </g>\n     </g>\n    </g>\n    <g id=\"xtick_6\">\n     <g id=\"line2d_6\">\n      <g>\n       <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"284.205985\" xlink:href=\"#mb8d63cda8e\" y=\"224.64\"/>\n      </g>\n     </g>\n     <g id=\"text_6\">\n      <!-- 0.6 -->\n      <g transform=\"translate(276.254422 239.238437)scale(0.1 -0.1)\">\n       <defs>\n        <path d=\"M 33.015625 40.375 \nQ 26.375 40.375 22.484375 35.828125 \nQ 18.609375 31.296875 18.609375 23.390625 \nQ 18.609375 15.53125 22.484375 10.953125 \nQ 26.375 6.390625 33.015625 6.390625 \nQ 39.65625 6.390625 43.53125 10.953125 \nQ 47.40625 15.53125 47.40625 23.390625 \nQ 47.40625 31.296875 43.53125 35.828125 \nQ 39.65625 40.375 33.015625 40.375 \nz\nM 52.59375 71.296875 \nL 52.59375 62.3125 \nQ 48.875 64.0625 45.09375 64.984375 \nQ 41.3125 65.921875 37.59375 65.921875 \nQ 27.828125 65.921875 22.671875 59.328125 \nQ 17.53125 52.734375 16.796875 39.40625 \nQ 19.671875 43.65625 24.015625 45.921875 \nQ 28.375 48.1875 33.59375 48.1875 \nQ 44.578125 48.1875 50.953125 41.515625 \nQ 57.328125 34.859375 57.328125 23.390625 \nQ 57.328125 12.15625 50.6875 5.359375 \nQ 44.046875 -1.421875 33.015625 -1.421875 \nQ 20.359375 -1.421875 13.671875 8.265625 \nQ 6.984375 17.96875 6.984375 36.375 \nQ 6.984375 53.65625 15.1875 63.9375 \nQ 23.390625 74.21875 37.203125 74.21875 \nQ 40.921875 74.21875 44.703125 73.484375 \nQ 48.484375 72.75 52.59375 71.296875 \nz\n\" id=\"DejaVuSans-54\"/>\n       </defs>\n       <use xlink:href=\"#DejaVuSans-48\"/>\n       <use x=\"63.623047\" xlink:href=\"#DejaVuSans-46\"/>\n       <use x=\"95.410156\" xlink:href=\"#DejaVuSans-54\"/>\n      </g>\n     </g>\n    </g>\n    <g id=\"xtick_7\">\n     <g id=\"line2d_7\">\n      <g>\n       <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"326.705023\" xlink:href=\"#mb8d63cda8e\" y=\"224.64\"/>\n      </g>\n     </g>\n     <g id=\"text_7\">\n      <!-- 0.7 -->\n      <g transform=\"translate(318.753461 239.238437)scale(0.1 -0.1)\">\n       <defs>\n        <path d=\"M 8.203125 72.90625 \nL 55.078125 72.90625 \nL 55.078125 68.703125 \nL 28.609375 0 \nL 18.3125 0 \nL 43.21875 64.59375 \nL 8.203125 64.59375 \nz\n\" id=\"DejaVuSans-55\"/>\n       </defs>\n       <use xlink:href=\"#DejaVuSans-48\"/>\n       <use x=\"63.623047\" xlink:href=\"#DejaVuSans-46\"/>\n       <use x=\"95.410156\" xlink:href=\"#DejaVuSans-55\"/>\n      </g>\n     </g>\n    </g>\n    <g id=\"xtick_8\">\n     <g id=\"line2d_8\">\n      <g>\n       <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"369.204061\" xlink:href=\"#mb8d63cda8e\" y=\"224.64\"/>\n      </g>\n     </g>\n     <g id=\"text_8\">\n      <!-- 0.8 -->\n      <g transform=\"translate(361.252499 239.238437)scale(0.1 -0.1)\">\n       <defs>\n        <path d=\"M 31.78125 34.625 \nQ 24.75 34.625 20.71875 30.859375 \nQ 16.703125 27.09375 16.703125 20.515625 \nQ 16.703125 13.921875 20.71875 10.15625 \nQ 24.75 6.390625 31.78125 6.390625 \nQ 38.8125 6.390625 42.859375 10.171875 \nQ 46.921875 13.96875 46.921875 20.515625 \nQ 46.921875 27.09375 42.890625 30.859375 \nQ 38.875 34.625 31.78125 34.625 \nz\nM 21.921875 38.8125 \nQ 15.578125 40.375 12.03125 44.71875 \nQ 8.5 49.078125 8.5 55.328125 \nQ 8.5 64.0625 14.71875 69.140625 \nQ 20.953125 74.21875 31.78125 74.21875 \nQ 42.671875 74.21875 48.875 69.140625 \nQ 55.078125 64.0625 55.078125 55.328125 \nQ 55.078125 49.078125 51.53125 44.71875 \nQ 48 40.375 41.703125 38.8125 \nQ 48.828125 37.15625 52.796875 32.3125 \nQ 56.78125 27.484375 56.78125 20.515625 \nQ 56.78125 9.90625 50.3125 4.234375 \nQ 43.84375 -1.421875 31.78125 -1.421875 \nQ 19.734375 -1.421875 13.25 4.234375 \nQ 6.78125 9.90625 6.78125 20.515625 \nQ 6.78125 27.484375 10.78125 32.3125 \nQ 14.796875 37.15625 21.921875 38.8125 \nz\nM 18.3125 54.390625 \nQ 18.3125 48.734375 21.84375 45.5625 \nQ 25.390625 42.390625 31.78125 42.390625 \nQ 38.140625 42.390625 41.71875 45.5625 \nQ 45.3125 48.734375 45.3125 54.390625 \nQ 45.3125 60.0625 41.71875 63.234375 \nQ 38.140625 66.40625 31.78125 66.40625 \nQ 25.390625 66.40625 21.84375 63.234375 \nQ 18.3125 60.0625 18.3125 54.390625 \nz\n\" id=\"DejaVuSans-56\"/>\n       </defs>\n       <use xlink:href=\"#DejaVuSans-48\"/>\n       <use x=\"63.623047\" xlink:href=\"#DejaVuSans-46\"/>\n       <use x=\"95.410156\" xlink:href=\"#DejaVuSans-56\"/>\n      </g>\n     </g>\n    </g>\n    <g id=\"text_9\">\n     <!-- time -->\n     <g transform=\"translate(199.885156 252.916562)scale(0.1 -0.1)\">\n      <defs>\n       <path d=\"M 18.3125 70.21875 \nL 18.3125 54.6875 \nL 36.8125 54.6875 \nL 36.8125 47.703125 \nL 18.3125 47.703125 \nL 18.3125 18.015625 \nQ 18.3125 11.328125 20.140625 9.421875 \nQ 21.96875 7.515625 27.59375 7.515625 \nL 36.8125 7.515625 \nL 36.8125 0 \nL 27.59375 0 \nQ 17.1875 0 13.234375 3.875 \nQ 9.28125 7.765625 9.28125 18.015625 \nL 9.28125 47.703125 \nL 2.6875 47.703125 \nL 2.6875 54.6875 \nL 9.28125 54.6875 \nL 9.28125 70.21875 \nz\n\" id=\"DejaVuSans-116\"/>\n       <path d=\"M 9.421875 54.6875 \nL 18.40625 54.6875 \nL 18.40625 0 \nL 9.421875 0 \nz\nM 9.421875 75.984375 \nL 18.40625 75.984375 \nL 18.40625 64.59375 \nL 9.421875 64.59375 \nz\n\" id=\"DejaVuSans-105\"/>\n       <path d=\"M 52 44.1875 \nQ 55.375 50.25 60.0625 53.125 \nQ 64.75 56 71.09375 56 \nQ 79.640625 56 84.28125 50.015625 \nQ 88.921875 44.046875 88.921875 33.015625 \nL 88.921875 0 \nL 79.890625 0 \nL 79.890625 32.71875 \nQ 79.890625 40.578125 77.09375 44.375 \nQ 74.3125 48.1875 68.609375 48.1875 \nQ 61.625 48.1875 57.5625 43.546875 \nQ 53.515625 38.921875 53.515625 30.90625 \nL 53.515625 0 \nL 44.484375 0 \nL 44.484375 32.71875 \nQ 44.484375 40.625 41.703125 44.40625 \nQ 38.921875 48.1875 33.109375 48.1875 \nQ 26.21875 48.1875 22.15625 43.53125 \nQ 18.109375 38.875 18.109375 30.90625 \nL 18.109375 0 \nL 9.078125 0 \nL 9.078125 54.6875 \nL 18.109375 54.6875 \nL 18.109375 46.1875 \nQ 21.1875 51.21875 25.484375 53.609375 \nQ 29.78125 56 35.6875 56 \nQ 41.65625 56 45.828125 52.96875 \nQ 50 49.953125 52 44.1875 \nz\n\" id=\"DejaVuSans-109\"/>\n       <path d=\"M 56.203125 29.59375 \nL 56.203125 25.203125 \nL 14.890625 25.203125 \nQ 15.484375 15.921875 20.484375 11.0625 \nQ 25.484375 6.203125 34.421875 6.203125 \nQ 39.59375 6.203125 44.453125 7.46875 \nQ 49.3125 8.734375 54.109375 11.28125 \nL 54.109375 2.78125 \nQ 49.265625 0.734375 44.1875 -0.34375 \nQ 39.109375 -1.421875 33.890625 -1.421875 \nQ 20.796875 -1.421875 13.15625 6.1875 \nQ 5.515625 13.8125 5.515625 26.8125 \nQ 5.515625 40.234375 12.765625 48.109375 \nQ 20.015625 56 32.328125 56 \nQ 43.359375 56 49.78125 48.890625 \nQ 56.203125 41.796875 56.203125 29.59375 \nz\nM 47.21875 32.234375 \nQ 47.125 39.59375 43.09375 43.984375 \nQ 39.0625 48.390625 32.421875 48.390625 \nQ 24.90625 48.390625 20.390625 44.140625 \nQ 15.875 39.890625 15.1875 32.171875 \nz\n\" id=\"DejaVuSans-101\"/>\n      </defs>\n      <use xlink:href=\"#DejaVuSans-116\"/>\n      <use x=\"39.208984\" xlink:href=\"#DejaVuSans-105\"/>\n      <use x=\"66.992188\" xlink:href=\"#DejaVuSans-109\"/>\n      <use x=\"164.404297\" xlink:href=\"#DejaVuSans-101\"/>\n     </g>\n    </g>\n   </g>\n   <g id=\"matplotlib.axis_2\">\n    <g id=\"ytick_1\">\n     <g id=\"line2d_9\">\n      <defs>\n       <path d=\"M 0 0 \nL -3.5 0 \n\" id=\"m3ced35a3ba\" style=\"stroke:#000000;stroke-width:0.8;\"/>\n      </defs>\n      <g>\n       <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"43.78125\" xlink:href=\"#m3ced35a3ba\" y=\"224.64\"/>\n      </g>\n     </g>\n     <g id=\"text_10\">\n      <!-- 0.0 -->\n      <g transform=\"translate(20.878125 228.439219)scale(0.1 -0.1)\">\n       <use xlink:href=\"#DejaVuSans-48\"/>\n       <use x=\"63.623047\" xlink:href=\"#DejaVuSans-46\"/>\n       <use x=\"95.410156\" xlink:href=\"#DejaVuSans-48\"/>\n      </g>\n     </g>\n    </g>\n    <g id=\"ytick_2\">\n     <g id=\"line2d_10\">\n      <g>\n       <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"43.78125\" xlink:href=\"#m3ced35a3ba\" y=\"198.996816\"/>\n      </g>\n     </g>\n     <g id=\"text_11\">\n      <!-- 0.5 -->\n      <g transform=\"translate(20.878125 202.796035)scale(0.1 -0.1)\">\n       <use xlink:href=\"#DejaVuSans-48\"/>\n       <use x=\"63.623047\" xlink:href=\"#DejaVuSans-46\"/>\n       <use x=\"95.410156\" xlink:href=\"#DejaVuSans-53\"/>\n      </g>\n     </g>\n    </g>\n    <g id=\"ytick_3\">\n     <g id=\"line2d_11\">\n      <g>\n       <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"43.78125\" xlink:href=\"#m3ced35a3ba\" y=\"173.353632\"/>\n      </g>\n     </g>\n     <g id=\"text_12\">\n      <!-- 1.0 -->\n      <g transform=\"translate(20.878125 177.152851)scale(0.1 -0.1)\">\n       <use xlink:href=\"#DejaVuSans-49\"/>\n       <use x=\"63.623047\" xlink:href=\"#DejaVuSans-46\"/>\n       <use x=\"95.410156\" xlink:href=\"#DejaVuSans-48\"/>\n      </g>\n     </g>\n    </g>\n    <g id=\"ytick_4\">\n     <g id=\"line2d_12\">\n      <g>\n       <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"43.78125\" xlink:href=\"#m3ced35a3ba\" y=\"147.710449\"/>\n      </g>\n     </g>\n     <g id=\"text_13\">\n      <!-- 1.5 -->\n      <g transform=\"translate(20.878125 151.509667)scale(0.1 -0.1)\">\n       <use xlink:href=\"#DejaVuSans-49\"/>\n       <use x=\"63.623047\" xlink:href=\"#DejaVuSans-46\"/>\n       <use x=\"95.410156\" xlink:href=\"#DejaVuSans-53\"/>\n      </g>\n     </g>\n    </g>\n    <g id=\"ytick_5\">\n     <g id=\"line2d_13\">\n      <g>\n       <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"43.78125\" xlink:href=\"#m3ced35a3ba\" y=\"122.067265\"/>\n      </g>\n     </g>\n     <g id=\"text_14\">\n      <!-- 2.0 -->\n      <g transform=\"translate(20.878125 125.866484)scale(0.1 -0.1)\">\n       <use xlink:href=\"#DejaVuSans-50\"/>\n       <use x=\"63.623047\" xlink:href=\"#DejaVuSans-46\"/>\n       <use x=\"95.410156\" xlink:href=\"#DejaVuSans-48\"/>\n      </g>\n     </g>\n    </g>\n    <g id=\"ytick_6\">\n     <g id=\"line2d_14\">\n      <g>\n       <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"43.78125\" xlink:href=\"#m3ced35a3ba\" y=\"96.424081\"/>\n      </g>\n     </g>\n     <g id=\"text_15\">\n      <!-- 2.5 -->\n      <g transform=\"translate(20.878125 100.2233)scale(0.1 -0.1)\">\n       <use xlink:href=\"#DejaVuSans-50\"/>\n       <use x=\"63.623047\" xlink:href=\"#DejaVuSans-46\"/>\n       <use x=\"95.410156\" xlink:href=\"#DejaVuSans-53\"/>\n      </g>\n     </g>\n    </g>\n    <g id=\"ytick_7\">\n     <g id=\"line2d_15\">\n      <g>\n       <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"43.78125\" xlink:href=\"#m3ced35a3ba\" y=\"70.780897\"/>\n      </g>\n     </g>\n     <g id=\"text_16\">\n      <!-- 3.0 -->\n      <g transform=\"translate(20.878125 74.580116)scale(0.1 -0.1)\">\n       <use xlink:href=\"#DejaVuSans-51\"/>\n       <use x=\"63.623047\" xlink:href=\"#DejaVuSans-46\"/>\n       <use x=\"95.410156\" xlink:href=\"#DejaVuSans-48\"/>\n      </g>\n     </g>\n    </g>\n    <g id=\"ytick_8\">\n     <g id=\"line2d_16\">\n      <g>\n       <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"43.78125\" xlink:href=\"#m3ced35a3ba\" y=\"45.137714\"/>\n      </g>\n     </g>\n     <g id=\"text_17\">\n      <!-- 3.5 -->\n      <g transform=\"translate(20.878125 48.936932)scale(0.1 -0.1)\">\n       <use xlink:href=\"#DejaVuSans-51\"/>\n       <use x=\"63.623047\" xlink:href=\"#DejaVuSans-46\"/>\n       <use x=\"95.410156\" xlink:href=\"#DejaVuSans-53\"/>\n      </g>\n     </g>\n    </g>\n    <g id=\"ytick_9\">\n     <g id=\"line2d_17\">\n      <g>\n       <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"43.78125\" xlink:href=\"#m3ced35a3ba\" y=\"19.49453\"/>\n      </g>\n     </g>\n     <g id=\"text_18\">\n      <!-- 4.0 -->\n      <g transform=\"translate(20.878125 23.293749)scale(0.1 -0.1)\">\n       <use xlink:href=\"#DejaVuSans-52\"/>\n       <use x=\"63.623047\" xlink:href=\"#DejaVuSans-46\"/>\n       <use x=\"95.410156\" xlink:href=\"#DejaVuSans-48\"/>\n      </g>\n     </g>\n    </g>\n    <g id=\"text_19\">\n     <!-- Density -->\n     <g transform=\"translate(14.798438 134.928594)rotate(-90)scale(0.1 -0.1)\">\n      <defs>\n       <path d=\"M 19.671875 64.796875 \nL 19.671875 8.109375 \nL 31.59375 8.109375 \nQ 46.6875 8.109375 53.6875 14.9375 \nQ 60.6875 21.78125 60.6875 36.53125 \nQ 60.6875 51.171875 53.6875 57.984375 \nQ 46.6875 64.796875 31.59375 64.796875 \nz\nM 9.8125 72.90625 \nL 30.078125 72.90625 \nQ 51.265625 72.90625 61.171875 64.09375 \nQ 71.09375 55.28125 71.09375 36.53125 \nQ 71.09375 17.671875 61.125 8.828125 \nQ 51.171875 0 30.078125 0 \nL 9.8125 0 \nz\n\" id=\"DejaVuSans-68\"/>\n       <path d=\"M 54.890625 33.015625 \nL 54.890625 0 \nL 45.90625 0 \nL 45.90625 32.71875 \nQ 45.90625 40.484375 42.875 44.328125 \nQ 39.84375 48.1875 33.796875 48.1875 \nQ 26.515625 48.1875 22.3125 43.546875 \nQ 18.109375 38.921875 18.109375 30.90625 \nL 18.109375 0 \nL 9.078125 0 \nL 9.078125 54.6875 \nL 18.109375 54.6875 \nL 18.109375 46.1875 \nQ 21.34375 51.125 25.703125 53.5625 \nQ 30.078125 56 35.796875 56 \nQ 45.21875 56 50.046875 50.171875 \nQ 54.890625 44.34375 54.890625 33.015625 \nz\n\" id=\"DejaVuSans-110\"/>\n       <path d=\"M 44.28125 53.078125 \nL 44.28125 44.578125 \nQ 40.484375 46.53125 36.375 47.5 \nQ 32.28125 48.484375 27.875 48.484375 \nQ 21.1875 48.484375 17.84375 46.4375 \nQ 14.5 44.390625 14.5 40.28125 \nQ 14.5 37.15625 16.890625 35.375 \nQ 19.28125 33.59375 26.515625 31.984375 \nL 29.59375 31.296875 \nQ 39.15625 29.25 43.1875 25.515625 \nQ 47.21875 21.78125 47.21875 15.09375 \nQ 47.21875 7.46875 41.1875 3.015625 \nQ 35.15625 -1.421875 24.609375 -1.421875 \nQ 20.21875 -1.421875 15.453125 -0.5625 \nQ 10.6875 0.296875 5.421875 2 \nL 5.421875 11.28125 \nQ 10.40625 8.6875 15.234375 7.390625 \nQ 20.0625 6.109375 24.8125 6.109375 \nQ 31.15625 6.109375 34.5625 8.28125 \nQ 37.984375 10.453125 37.984375 14.40625 \nQ 37.984375 18.0625 35.515625 20.015625 \nQ 33.0625 21.96875 24.703125 23.78125 \nL 21.578125 24.515625 \nQ 13.234375 26.265625 9.515625 29.90625 \nQ 5.8125 33.546875 5.8125 39.890625 \nQ 5.8125 47.609375 11.28125 51.796875 \nQ 16.75 56 26.8125 56 \nQ 31.78125 56 36.171875 55.265625 \nQ 40.578125 54.546875 44.28125 53.078125 \nz\n\" id=\"DejaVuSans-115\"/>\n       <path d=\"M 32.171875 -5.078125 \nQ 28.375 -14.84375 24.75 -17.8125 \nQ 21.140625 -20.796875 15.09375 -20.796875 \nL 7.90625 -20.796875 \nL 7.90625 -13.28125 \nL 13.1875 -13.28125 \nQ 16.890625 -13.28125 18.9375 -11.515625 \nQ 21 -9.765625 23.484375 -3.21875 \nL 25.09375 0.875 \nL 2.984375 54.6875 \nL 12.5 54.6875 \nL 29.59375 11.921875 \nL 46.6875 54.6875 \nL 56.203125 54.6875 \nz\n\" id=\"DejaVuSans-121\"/>\n      </defs>\n      <use xlink:href=\"#DejaVuSans-68\"/>\n      <use x=\"77.001953\" xlink:href=\"#DejaVuSans-101\"/>\n      <use x=\"138.525391\" xlink:href=\"#DejaVuSans-110\"/>\n      <use x=\"201.904297\" xlink:href=\"#DejaVuSans-115\"/>\n      <use x=\"254.003906\" xlink:href=\"#DejaVuSans-105\"/>\n      <use x=\"281.787109\" xlink:href=\"#DejaVuSans-116\"/>\n      <use x=\"320.996094\" xlink:href=\"#DejaVuSans-121\"/>\n     </g>\n    </g>\n   </g>\n   <g id=\"line2d_18\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 60.48548 222.933339 \nL 66.096106 222.087012 \nL 71.706732 221.005227 \nL 77.317359 219.673302 \nL 81.525328 218.425144 \nL 84.330641 217.368653 \nL 87.135954 216.023728 \nL 89.941268 214.285133 \nL 92.746581 212.064174 \nL 95.551894 209.3155 \nL 98.357207 206.055341 \nL 101.16252 202.361985 \nL 105.37049 196.271791 \nL 110.981116 187.646845 \nL 115.189085 180.842019 \nL 117.994399 175.99178 \nL 120.799712 170.772888 \nL 123.605025 165.134467 \nL 126.410338 159.092471 \nL 130.618308 149.414008 \nL 134.826277 139.128651 \nL 137.63159 131.865032 \nL 140.436903 124.12401 \nL 143.242217 115.764007 \nL 146.04753 106.721558 \nL 150.255499 92.0935 \nL 155.866126 72.123984 \nL 158.671439 62.773706 \nL 161.476752 54.260586 \nL 164.282065 46.760684 \nL 167.087378 40.345072 \nL 168.490035 37.546771 \nL 169.892691 35.018994 \nL 171.295348 32.759696 \nL 172.698004 30.767739 \nL 174.100661 29.043253 \nL 175.503317 27.587501 \nL 176.905974 26.402319 \nL 178.30863 25.489188 \nL 179.711287 24.848093 \nL 181.113944 24.476305 \nL 182.5166 24.367247 \nL 183.919257 24.509593 \nL 185.321913 24.886704 \nL 186.72457 25.476512 \nL 188.127226 26.251869 \nL 190.932539 28.230665 \nL 195.140509 31.745528 \nL 199.348479 35.203985 \nL 207.764418 41.580027 \nL 209.167075 42.888885 \nL 210.569731 44.389293 \nL 211.972388 46.129186 \nL 213.375044 48.152044 \nL 214.777701 50.494451 \nL 216.180357 53.184107 \nL 217.583014 56.238364 \nL 218.98567 59.663317 \nL 220.388327 63.453403 \nL 223.19364 72.049396 \nL 225.998953 81.762269 \nL 230.206923 97.51639 \nL 234.414893 113.204283 \nL 237.220206 122.846071 \nL 240.025519 131.439776 \nL 242.830832 138.822765 \nL 244.233488 142.055102 \nL 245.636145 144.997902 \nL 248.441458 150.112436 \nL 251.246771 154.418852 \nL 254.052084 158.226101 \nL 259.662711 165.550673 \nL 262.468024 169.518902 \nL 265.273337 173.828713 \nL 269.481306 180.847441 \nL 276.494589 192.875601 \nL 279.299902 197.332688 \nL 282.105215 201.400315 \nL 284.910528 205.012206 \nL 287.715842 208.14223 \nL 290.521155 210.794424 \nL 293.326468 212.99181 \nL 296.131781 214.767546 \nL 298.937094 216.160345 \nL 301.742407 217.214125 \nL 304.54772 217.980015 \nL 307.353033 218.517835 \nL 311.561003 219.044276 \nL 322.782255 220.221519 \nL 329.795538 221.320444 \nL 339.614134 222.864081 \nL 339.614134 222.864081 \n\" style=\"fill:none;stroke:#1f77b4;stroke-linecap:square;stroke-width:1.5;\"/>\n   </g>\n   <g id=\"line2d_19\">\n    <path clip-path=\"url(#p70c194fa22)\" d=\"M 58.999432 219.340887 \nL 63.587828 217.592516 \nL 68.176225 215.594773 \nL 72.764621 213.302111 \nL 75.823552 211.576263 \nL 78.882483 209.666107 \nL 81.941414 207.546496 \nL 85.000345 205.186397 \nL 88.059276 202.544495 \nL 91.118208 199.567013 \nL 94.177139 196.190789 \nL 97.23607 192.353095 \nL 100.295001 188.007084 \nL 103.353932 183.139012 \nL 106.412863 177.781808 \nL 109.471794 172.019773 \nL 115.589656 159.82103 \nL 121.707518 147.724628 \nL 126.295914 139.233852 \nL 130.884311 131.315783 \nL 137.002173 121.372779 \nL 143.120035 111.866632 \nL 146.178966 107.374743 \nL 149.237897 103.220636 \nL 152.296828 99.560024 \nL 153.826293 97.957912 \nL 155.355759 96.52357 \nL 156.885224 95.261806 \nL 158.41469 94.17077 \nL 159.944155 93.241513 \nL 163.003086 91.79788 \nL 166.062017 90.731843 \nL 170.650414 89.269008 \nL 173.709345 88.018484 \nL 176.768276 86.3511 \nL 179.827207 84.23072 \nL 182.886138 81.75145 \nL 189.004 76.608788 \nL 190.533466 75.492893 \nL 192.062931 74.517105 \nL 193.592397 73.712981 \nL 195.121862 73.107451 \nL 196.651328 72.721966 \nL 198.180793 72.571947 \nL 199.710259 72.666563 \nL 201.239724 73.008821 \nL 202.76919 73.595911 \nL 204.298655 74.41978 \nL 205.828121 75.46786 \nL 207.357586 76.723885 \nL 208.887052 78.168734 \nL 211.945983 81.539051 \nL 215.004914 85.398297 \nL 219.59331 91.709964 \nL 227.240638 102.366838 \nL 231.829034 108.332567 \nL 236.417431 113.927724 \nL 247.123689 126.723751 \nL 253.241552 134.543866 \nL 260.888879 144.784133 \nL 273.124603 161.535287 \nL 279.242465 170.207937 \nL 294.53712 192.255044 \nL 297.596051 196.107778 \nL 300.654982 199.525238 \nL 303.713913 202.443906 \nL 306.772844 204.850253 \nL 309.831775 206.780929 \nL 312.890706 208.311829 \nL 315.949637 209.540029 \nL 320.538034 211.027115 \nL 328.185361 213.140924 \nL 341.950551 216.745629 \nL 351.127344 218.888644 \nL 361.833603 221.108931 \nL 363.363068 221.403963 \nL 363.363068 221.403963 \n\" style=\"fill:none;stroke:#ffa500;stroke-linecap:square;stroke-width:1.5;\"/>\n   </g>\n   <g id=\"patch_49\">\n    <path d=\"M 43.78125 224.64 \nL 43.78125 7.2 \n\" style=\"fill:none;stroke:#000000;stroke-linecap:square;stroke-linejoin:miter;stroke-width:0.8;\"/>\n   </g>\n   <g id=\"patch_50\">\n    <path d=\"M 378.58125 224.64 \nL 378.58125 7.2 \n\" style=\"fill:none;stroke:#000000;stroke-linecap:square;stroke-linejoin:miter;stroke-width:0.8;\"/>\n   </g>\n   <g id=\"patch_51\">\n    <path d=\"M 43.78125 224.64 \nL 378.58125 224.64 \n\" style=\"fill:none;stroke:#000000;stroke-linecap:square;stroke-linejoin:miter;stroke-width:0.8;\"/>\n   </g>\n   <g id=\"patch_52\">\n    <path d=\"M 43.78125 7.2 \nL 378.58125 7.2 \n\" style=\"fill:none;stroke:#000000;stroke-linecap:square;stroke-linejoin:miter;stroke-width:0.8;\"/>\n   </g>\n  </g>\n </g>\n <defs>\n  <clipPath id=\"p70c194fa22\">\n   <rect height=\"217.44\" width=\"334.8\" x=\"43.78125\" y=\"7.2\"/>\n  </clipPath>\n </defs>\n</svg>\n",
+      "image/png": "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\n"
+     },
+     "metadata": {
+      "needs_background": "light"
+     }
+    }
+   ],
+   "source": [
+    "my_outcomes_clustered = get_bootstrap_outcomes(\n",
+    "    data=df, outcome=ols_fit, seed=1234, cluster_by=\"id\"\n",
+    ")\n",
+    "\n",
+    "# clustered distribution in blue\n",
+    "sns.histplot(my_outcomes_clustered[\"time\"], kde=True, stat=\"density\", linewidth=0)\n",
+    "\n",
+    "# non-clustered distribution in orange\n",
+    "sns.histplot(my_outcomes[\"time\"], kde=True, stat=\"density\", linewidth=0, color=\"orange\")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "### Calculating standard errors and confidence intervals from existing outcomes"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Once we have the outcomes, we can compute confidence intervals and standard errors from them"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {},
+   "outputs": [
+    {
+     "output_type": "execute_result",
+     "data": {
+      "text/plain": [
+       "               mean       std   lower_ci   upper_ci\n",
+       "constant  93.767044  1.501594  90.756341  96.598375\n",
+       "time       0.391806  0.128111   0.113098   0.617271"
+      ],
+      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>mean</th>\n      <th>std</th>\n      <th>lower_ci</th>\n      <th>upper_ci</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>constant</th>\n      <td>93.767044</td>\n      <td>1.501594</td>\n      <td>90.756341</td>\n      <td>96.598375</td>\n    </tr>\n    <tr>\n      <th>time</th>\n      <td>0.391806</td>\n      <td>0.128111</td>\n      <td>0.113098</td>\n      <td>0.617271</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
+     },
+     "metadata": {},
+     "execution_count": 10
+    }
+   ],
+   "source": [
+    "from estimagic.inference import bootstrap_from_outcomes\n",
+    "\n",
+    "my_results = bootstrap_from_outcomes(\n",
+    "    data=df, outcome=ols_fit, bootstrap_outcomes=my_outcomes, ci_method=\"t\"\n",
+    ")\n",
+    "my_results"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "You can use this to calculate confidence intervals with several methods (e.g. \"bca\" and \"percentile\") without duplicated calculations."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Extending bootstrap results with more draws\n",
+    "\n",
+    "It is often the case that for speed reasons you set the number of bootstrap draws quite low, so you can look at results earlier and later decide that you need more draws. \n",
+    "\n",
+    "In the long run, we will offer a Dashboard integration for this. For now, you can do it manually.\n",
+    "\n",
+    "As an example we will take `my_outcomes` defined above and extend it with another 500 draws. \n",
+    "\n",
+    "Note: It is very important to use a different random seed when you calculate the additional outcomes!!!"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "more_outcomes = get_bootstrap_outcomes(data=df, outcome=ols_fit, seed=5471, n_draws=500)\n",
+    "combined_outcomes = pd.concat([my_outcomes, more_outcomes])\n",
+    "combined_results = bootstrap_from_outcomes(\n",
+    "    data=df,\n",
+    "    outcome=ols_fit,\n",
+    "    bootstrap_outcomes=combined_outcomes,\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## More than one outcome\n",
+    "\n",
+    "to be written"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Accessing the bootstrap samples"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "It is also possible to just access the bootstrap samples. You can use this for example, if you want to calculate your the bootstrap outcomes in parallel in a way that is not yet supported by estimagic (e.g. on a large cluster or supercomputer)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {},
+   "outputs": [
+    {
+     "output_type": "execute_result",
+     "data": {
+      "text/plain": [
+       "    id     diet  pulse  time     kind  constant\n",
+       "47  16   no fat     89    30  walking         1\n",
+       "83  28   no fat    140    30  running         1\n",
+       "38  13  low fat     93    30  walking         1\n",
+       "53  18   no fat    101    30  walking         1\n",
+       "76  26   no fat    126    15  running         1\n",
+       "..  ..      ...    ...   ...      ...       ...\n",
+       "0    1  low fat     85     1     rest         1\n",
+       "33  12  low fat     93     1  walking         1\n",
+       "21   8   no fat     92     1     rest         1\n",
+       "71  24  low fat    120    30  running         1\n",
+       "68  23  low fat     99    30  running         1\n",
+       "\n",
+       "[90 rows x 6 columns]"
+      ],
+      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>id</th>\n      <th>diet</th>\n      <th>pulse</th>\n      <th>time</th>\n      <th>kind</th>\n      <th>constant</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>47</th>\n      <td>16</td>\n      <td>no fat</td>\n      <td>89</td>\n      <td>30</td>\n      <td>walking</td>\n      <td>1</td>\n    </tr>\n    <tr>\n      <th>83</th>\n      <td>28</td>\n      <td>no fat</td>\n      <td>140</td>\n      <td>30</td>\n      <td>running</td>\n      <td>1</td>\n    </tr>\n    <tr>\n      <th>38</th>\n      <td>13</td>\n      <td>low fat</td>\n      <td>93</td>\n      <td>30</td>\n      <td>walking</td>\n      <td>1</td>\n    </tr>\n    <tr>\n      <th>53</th>\n      <td>18</td>\n      <td>no fat</td>\n      <td>101</td>\n      <td>30</td>\n      <td>walking</td>\n      <td>1</td>\n    </tr>\n    <tr>\n      <th>76</th>\n      <td>26</td>\n      <td>no fat</td>\n      <td>126</td>\n      <td>15</td>\n      <td>running</td>\n      <td>1</td>\n    </tr>\n    <tr>\n      <th>...</th>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n      <td>...</td>\n    </tr>\n    <tr>\n      <th>0</th>\n      <td>1</td>\n      <td>low fat</td>\n      <td>85</td>\n      <td>1</td>\n      <td>rest</td>\n      <td>1</td>\n    </tr>\n    <tr>\n      <th>33</th>\n      <td>12</td>\n      <td>low fat</td>\n      <td>93</td>\n      <td>1</td>\n      <td>walking</td>\n      <td>1</td>\n    </tr>\n    <tr>\n      <th>21</th>\n      <td>8</td>\n      <td>no fat</td>\n      <td>92</td>\n      <td>1</td>\n      <td>rest</td>\n      <td>1</td>\n    </tr>\n    <tr>\n      <th>71</th>\n      <td>24</td>\n      <td>low fat</td>\n      <td>120</td>\n      <td>30</td>\n      <td>running</td>\n      <td>1</td>\n    </tr>\n    <tr>\n      <th>68</th>\n      <td>23</td>\n      <td>low fat</td>\n      <td>99</td>\n      <td>30</td>\n      <td>running</td>\n      <td>1</td>\n    </tr>\n  </tbody>\n</table>\n<p>90 rows × 6 columns</p>\n</div>"
+     },
+     "metadata": {},
+     "execution_count": 12
+    }
+   ],
+   "source": [
+    "from estimagic.inference import get_bootstrap_samples\n",
+    "\n",
+    "my_samples = get_bootstrap_samples(data=df, seed=1234)\n",
+    "\n",
+    "my_samples[0]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "name": "python3",
+   "display_name": "Python 3.8.8 64-bit ('estimagic': conda)"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.8.8"
+  },
+  "interpreter": {
+   "hash": "5cdb9867252288f10687117449de6ad870b49795ca695c868016dc0022895cce"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/docs/source/how_to_guides/inference/index.rst b/docs/source/how_to_guides/inference/index.rst
index 0e06d8d7b..d4eb7646f 100644
--- a/docs/source/how_to_guides/inference/index.rst
+++ b/docs/source/how_to_guides/inference/index.rst
@@ -7,4 +7,4 @@ Inference
 
    how_to_calculate_likelihood_standard_errors.ipynb
    how_to_calculate_msm_standard_errors.ipynb
-   how_to_calculate_bootstrap_confidence_intervals.ipynb
+   how_to_do_bootstrap_inference.ipynb
diff --git a/docs/source/reference_guides/index.rst b/docs/source/reference_guides/index.rst
index c6696d47f..a3e2276a9 100644
--- a/docs/source/reference_guides/index.rst
+++ b/docs/source/reference_guides/index.rst
@@ -7,5 +7,6 @@ API Reference
 
    optimization
    differentiation
+   inference
    batch_evaluators
    tables
diff --git a/docs/source/reference_guides/inference.rst b/docs/source/reference_guides/inference.rst
new file mode 100644
index 000000000..a97738dcb
--- /dev/null
+++ b/docs/source/reference_guides/inference.rst
@@ -0,0 +1,70 @@
+Bootstrap Inference
+========================
+
+.. currentmodule:: estimagic.inference.bootstrap
+
+In this section we document how to use the bootstrap to approximate the distribution
+of statistics of interest on a given sample.
+
+The main idea of the bootstrap is to combine three steps: Firstly, generate bootstrap
+samples by drawing from the original data set with replacement. Secondly, calculating
+the statistic of interest from these resampled data, and finally, using the various
+estimates to draw inference on the distribution of the true statistic of interest.
+
+The main function of this module takes care of all of these three steps and returns a
+table containing means, standard errors and confidence intervals for the estimated
+parameters.
+
+.. autofunction:: bootstrap
+
+However, the steps can also be called separately by the user, as described in what
+follows.
+
+.. currentmodule:: estimagic.inference.bootstrap_samples
+
+The module implements the first step of drawing  B bootstrap samples in two separate
+ways. The first, and default, method, is to simply draw observations from the original
+dataset with replacement. The second method is a cluster robust bootstrap, often called
+pairs cluster bootstrap, that draws clusters, defined by observations with the same
+value of some specified stratum variable, from the original dataset with replacement.
+Sample drawing is implemented by drawing seeds. Seeds can be re-used to calculate
+multiple statistics on the same data points.
+
+.. autofunction:: get_seeds
+
+To be as memory-efficient as possible, the actual drawing of data points is by default
+deferred to the calculation of statistics. However, it is possible to get a list of
+drawn resampled datasets using
+
+.. autofunction:: get_bootstrap_samples
+
+.. currentmodule:: estimagic.inference.bootstrap_estimates
+
+The calculation of statistics is handled by the following function:
+
+.. autofunction:: get_bootstrap_estimates
+
+.. currentmodule:: estimagic.inference.bootstrap
+
+To calculate mean, standard deviation, and a confidence interval of the statistic of
+interest, we can use
+
+.. autofunction:: get_results_table
+
+There is also a function to calculate only confidence intervals, given the estimates.
+The code of this function is an adjusted version of the code from Daniel Saxton's
+resample library :cite:`Saxton2018`. It has been adjusted to allow
+for the additional confidence interval types "bc", "basic" and "normal". Moreover,
+it is faster.
+
+.. currentmodule:: estimagic.inference.bootstrap
+
+.. autofunction:: compute_ci
+
+
+The supported types of confidence are explained in more detail
+here: :ref:`bootstrap_cis`
+
+
+.. bibliography:: ../refs.bib
+    :filter: docname in docnames
diff --git a/docs/source/refs.bib b/docs/source/refs.bib
index e4897c899..d6fcfcda2 100644
--- a/docs/source/refs.bib
+++ b/docs/source/refs.bib
@@ -1,4 +1,4 @@
-% Encoding: UTF-8
+﻿% Encoding: UTF-8
 
 
 @Book{Dennis1996,
@@ -26,6 +26,20 @@ @Book{Hansen2019
   Timestamp                = {2019.10.03}
 }
 
+@Book{Hansen2020,
+  Title                    = {Econometrics},
+  Author                   = {Bruce E. Hansen},
+  Editor                   = {Bruce E. Hansen},
+  Publisher                = {Unpublished},
+  Year                     = {2020},
+
+  Address                  = {https://www.ssc.wisc.edu/~bhansen/econometrics/},
+
+  Owner                    = {janos},
+  Timestamp                = {2020.03.04}
+}
+
+
 @Book{Verbeek2008,
   Title                    = {A Guide to Modern Econometrics},
   Author                   = {Verbeek, M.},
@@ -37,6 +51,13 @@ @Book{Verbeek2008
   Url                      = {https://books.google.com/books?id=uEFm6pAJZhoC}
 }
 
+@book{Wassermann2006,
+  title={All of nonparametric statistics},
+  author={Wasserman, Larry},
+  year={2006},
+  publisher={Springer Science \& Business Media}
+}
+
 @Article{Groeneveld1994,
   author  = {Eildert Groeneveld},
   title   = {A reparameterization to improve numerical optimization in multivariate REML (co)variance component estimation},
@@ -194,4 +215,21 @@ @Misc{Cartis2018b
   primaryclass  = {math.OC},
 }
 
-@Comment{jabref-meta: databaseType:bibtex;}
+@Unpublished{Saxton2018,
+  title  = {resample: Randomization-based inference in Python.},
+  author = {Daniel Saxton},
+  year   = {2018},
+  note = {unpublished},
+  Url    = {https://github.com/dsaxton/resample},
+}
+
+@article{CameronMiller2015,
+  title={A practitioner’s guide to cluster-robust inference},
+  author={Cameron, A Colin and Miller, Douglas L},
+  journal={Journal of human resources},
+  volume={50},
+  number={2},
+  pages={317--372},
+  year={2015},
+  publisher={University of Wisconsin Press}
+}
diff --git a/estimagic/batch_evaluators.py b/estimagic/batch_evaluators.py
index 0fff7329e..183604400 100644
--- a/estimagic/batch_evaluators.py
+++ b/estimagic/batch_evaluators.py
@@ -43,7 +43,7 @@ def pathos_mp_batch_evaluator(
             process.
         error_handling (str): Can take the values "raise" (raise the error and stop all
             tasks as soon as one task fails) and "continue" (catch exceptions and set
-            the output of failed tasks to the exception object without raising it.
+            the traceback of the raised exception.
             KeyboardInterrupt and SystemExit are always raised.
         unpack_symbol (str or None). Can be "**", "*" or None. If None, func just takes
             one argument. If "*", the elements of arguments are positional arguments for
@@ -103,7 +103,7 @@ def joblib_batch_evaluator(
             process.
         error_handling (str): Can take the values "raise" (raise the error and stop all
             tasks as soon as one task fails) and "continue" (catch exceptions and set
-            the output of failed tasks to the exception object without raising it.
+            the output of failed tasks to the traceback of the raised exception.
             KeyboardInterrupt and SystemExit are always raised.
         unpack_symbol (str or None). Can be "**", "*" or None. If None, func just takes
             one argument. If "*", the elements of arguments are positional arguments for
diff --git a/estimagic/inference/__init__.py b/estimagic/inference/__init__.py
index e69de29bb..9b6beff88 100644
--- a/estimagic/inference/__init__.py
+++ b/estimagic/inference/__init__.py
@@ -0,0 +1,5 @@
+from estimagic.inference.bootstrap import bootstrap  # noqa: F401
+from estimagic.inference.bootstrap import bootstrap_from_outcomes  # noqa: F401
+from estimagic.inference.bootstrap_outcomes import get_bootstrap_outcomes  # noqa: F401
+from estimagic.inference.bootstrap_samples import get_bootstrap_indices  # noqa: F401
+from estimagic.inference.bootstrap_samples import get_bootstrap_samples  # noqa: F401
diff --git a/estimagic/inference/bootstrap.py b/estimagic/inference/bootstrap.py
new file mode 100644
index 000000000..f68b3632e
--- /dev/null
+++ b/estimagic/inference/bootstrap.py
@@ -0,0 +1,95 @@
+import pandas as pd
+
+from estimagic.batch_evaluators import joblib_batch_evaluator
+from estimagic.inference.bootstrap_ci import compute_ci
+from estimagic.inference.bootstrap_helpers import check_inputs
+from estimagic.inference.bootstrap_outcomes import get_bootstrap_outcomes
+
+
+def bootstrap(
+    data,
+    outcome,
+    n_draws=1_000,
+    cluster_by=None,
+    ci_method="percentile",
+    alpha=0.05,
+    seed=None,
+    n_cores=1,
+    error_handling="continue",
+    batch_evaluator=joblib_batch_evaluator,
+):
+    """Calculate bootstrap estimates, standard errors and confidence intervals
+    for statistic of interest in given original sample.
+
+    Args:
+        data (pandas.DataFrame): original dataset.
+        outcome (callable): function of the data calculating statistic of interest.
+            Needs to return a pandas Series.
+        n_draws (int): number of bootstrap samples to draw.
+        cluster_by (str): column name of variable to cluster by or None.
+        ci_method (str): method of choice for confidence interval computation.
+        alpha (float): significance level of choice.
+        seeds (numpy.array): array of seeds for bootstrap samples, default is none.
+        n_cores (int): number of jobs for parallelization.
+        error_handling (str): One of "continue", "raise". Default "continue" which means
+            that bootstrap estimates are only calculated for those samples where no
+            errors occur and a warning is produced if any error occurs.
+        batch_evaluator (str or Callable): Name of a pre-implemented batch evaluator
+            (currently 'joblib' and 'pathos_mp') or Callable with the same interface
+            as the estimagic batch_evaluators. See :ref:`batch_evaluators`.
+
+    Returns:
+        results (pandas.DataFrame): DataFrame where k'th row contains mean estimate,
+        standard error, and confidence interval of k'th parameter.
+
+    """
+
+    check_inputs(data, cluster_by, ci_method, alpha)
+
+    estimates = get_bootstrap_outcomes(
+        data=data,
+        outcome=outcome,
+        cluster_by=cluster_by,
+        seed=seed,
+        n_cores=n_cores,
+        error_handling=error_handling,
+        batch_evaluator=batch_evaluator,
+    )
+
+    table = bootstrap_from_outcomes(data, outcome, estimates, ci_method, alpha, n_cores)
+
+    return table
+
+
+def bootstrap_from_outcomes(
+    data, outcome, bootstrap_outcomes, ci_method="percentile", alpha=0.05, n_cores=1
+):
+    """Set up results table containing mean, standard deviation and confidence interval
+    for each estimated parameter.
+
+    Args:
+        data (pandas.DataFrame): original dataset.
+        outcome (callable): function of the data calculating statistic of interest.
+            Needs to return a pandas Series.
+        bootstrap_outcomes (pandas.DataFrame): DataFrame of bootstrap_outcomes in the
+            bootstrap samples.
+        ci_method (str): method of choice for confidence interval computation.
+        n_cores (int): number of jobs for parallelization.
+        alpha (float): significance level of choice.
+
+    Returns:
+        results (pandas.DataFrame): table of results.
+
+    """
+
+    check_inputs(data=data, ci_method=ci_method, alpha=alpha)
+
+    results = pd.DataFrame(bootstrap_outcomes.mean(axis=0), columns=["mean"])
+
+    results["std"] = bootstrap_outcomes.std(axis=0)
+
+    cis = compute_ci(data, outcome, bootstrap_outcomes, ci_method, alpha, n_cores)
+    results["lower_ci"] = cis["lower_ci"]
+    results["upper_ci"] = cis["upper_ci"]
+
+    return results
diff --git a/estimagic/inference/bootstrap_ci.py b/estimagic/inference/bootstrap_ci.py
new file mode 100644
index 000000000..c008a5fdc
--- /dev/null
+++ b/estimagic/inference/bootstrap_ci.py
@@ -0,0 +1,289 @@
+import numpy as np
+import pandas as pd
+from joblib import delayed
+from joblib import Parallel
+from scipy.stats import norm
+
+from estimagic.inference.bootstrap_helpers import check_inputs
+
+
+def compute_ci(data, outcome, estimates, ci_method="percentile", alpha=0.05, n_cores=1):
+    """Compute confidence interval of bootstrap estimates. Parts of the code of the
+    subfunctions of this function are taken from Daniel Saxton's resample library, as
+    found on https://github.com/dsaxton/resample/ .
+
+
+    Args:
+        data (pandas.DataFrame): original dataset.
+        outcome (callable): function of the data calculating statistic of interest.
+            Needs to return a pandas Series.
+        estimates (pandas.DataFrame): DataFrame of estimates in the bootstrap samples.
+        ci_method (str): method of choice for confidence interval computation.
+        alpha (float): significance level of choice.
+        n_cores (int): number of jobs for parallelization.
+
+    Returns:
+        cis (pandas.DataFrame): DataFrame where k'th row contains CI for k'th parameter.
+
+    """
+
+    check_inputs(data=data, alpha=alpha, ci_method=ci_method)
+
+    funcname = "_ci_" + ci_method
+
+    cis = globals()[funcname](data, outcome, estimates, alpha, n_cores)
+
+    return pd.DataFrame(
+        cis, index=estimates.columns.tolist(), columns=["lower_ci", "upper_ci"]
+    )
+
+
+def _ci_percentile(data, outcome, estimates, alpha, n_cores):
+    """Compute percentile type confidence interval of bootstrap estimates.
+
+    Args:
+        data (pd.DataFrame): original dataset.
+        outcome (callable): function of the data calculating statistic of interest.
+        estimates (data.Frame): DataFrame of estimates in the bootstrap samples.
+        alpha (float): significance level of choice.
+        n_cores (int): number of jobs for parallelization.
+
+    Returns:
+        cis (np.array): array where k'th row contains CI for k'th parameter.
+
+    """
+
+    num_params = estimates.shape[1]
+    boot_est = estimates.values
+    cis = np.zeros((num_params, 2))
+
+    for k in range(num_params):
+
+        q = _eqf(boot_est[:, k])
+        cis[k, :] = np.array([q(alpha / 2), q(1 - alpha / 2)])
+
+    return cis
+
+
+def _ci_bca(data, outcome, estimates, alpha, n_cores):
+    """Compute bca type confidence interval of bootstrap estimates.
+
+    Args:
+        data (pd.DataFrame): original dataset.
+        outcome (callable): function of the data calculating statistic of interest.
+        estimates (data.Frame): DataFrame of estimates in the bootstrap samples.
+        alpha (float): significance level of choice.
+        n_cores (int): number of jobs for parallelization.
+
+    Returns:
+        cis (np.array): array where k'th row contains CI for k'th parameter.
+
+    """
+
+    num_params = estimates.shape[1]
+    boot_est = estimates.values
+    cis = np.zeros((num_params, 2))
+
+    theta = outcome(data)
+
+    jack_est = _jackknife(data, outcome, n_cores)
+    jack_mean = np.mean(jack_est, axis=0)
+
+    for k in range(num_params):
+
+        q = _eqf(boot_est[:, k])
+        params = boot_est[:, k]
+
+        # bias correction
+        z_naught = norm.ppf(np.mean(params <= theta[k]))
+        z_low = norm.ppf(alpha)
+        z_high = norm.ppf(1 - alpha)
+
+        # accelaration
+        acc = np.sum((jack_mean[k] - jack_est[k]) ** 3) / (
+            6 * np.sum((jack_mean[k] - jack_est[k]) ** 2) ** (3 / 2)
+        )
+
+        p1 = norm.cdf(z_naught + (z_naught + z_low) / (1 - acc * (z_naught + z_low)))
+        p2 = norm.cdf(z_naught + (z_naught + z_high) / (1 - acc * (z_naught + z_high)))
+
+        cis[k, :] = np.array([q(p1), q(p2)])
+
+    return cis
+
+
+def _ci_bc(data, outcome, estimates, alpha, n_cores):
+    """Compute bc type confidence interval of bootstrap estimates.
+
+    Args:
+        data (pd.DataFrame): original dataset.
+        outcome (callable): function of the data calculating statistic of interest.
+        estimates (data.Frame): DataFrame of estimates in the bootstrap samples.
+        alpha (float): significance level of choice.
+        n_cores (int): number of jobs for parallelization.
+
+    Returns:
+        cis (np.array): array where k'th row contains CI for k'th parameter.
+
+    """
+
+    num_params = estimates.shape[1]
+    boot_est = estimates.values
+    cis = np.zeros((num_params, 2))
+
+    theta = outcome(data)
+
+    for k in range(num_params):
+
+        q = _eqf(boot_est[:, k])
+        params = boot_est[:, k]
+
+        # bias correction
+        z_naught = norm.ppf(np.mean(params <= theta[k]))
+        z_low = norm.ppf(alpha)
+        z_high = norm.ppf(1 - alpha)
+
+        p1 = norm.cdf(z_naught + (z_naught + z_low))
+        p2 = norm.cdf(z_naught + (z_naught + z_high))
+
+        cis[k, :] = np.array([q(p1), q(p2)])
+
+    return cis
+
+
+def _ci_t(data, outcome, estimates, alpha, n_cores):
+    """Compute studentized confidence interval of bootstrap estimates.
+
+    Args:
+        data (pd.DataFrame): original dataset.
+        outcome (callable): function of the data calculating statistic of interest.
+        estimates (data.Frame): DataFrame of estimates in the bootstrap samples.
+        alpha (float): significance level of choice.
+        n_cores (int): number of jobs for parallelization.
+
+    Returns:
+        cis (np.array): array where k'th row contains CI for k'th parameter.
+
+    """
+
+    num_params = estimates.shape[1]
+    boot_est = estimates.values
+    cis = np.zeros((num_params, 2))
+    theta = outcome(data)
+
+    for k in range(num_params):
+
+        params = boot_est[:, k]
+
+        theta_std = np.std(params)
+
+        tq = _eqf((params - theta[k]) / theta_std)
+        t1 = tq(1 - alpha / 2)
+        t2 = tq(alpha / 2)
+
+        cis[k, :] = np.array([theta[k] - theta_std * t1, theta[k] - theta_std * t2])
+
+    return cis
+
+
+def _ci_normal(data, outcome, estimates, alpha, n_cores):
+    """Compute approximate normal confidence interval of bootstrap estimates.
+
+    Args:
+        data (pd.DataFrame): original dataset.
+        outcome (callable): function of the data calculating statistic of interest.
+        estimates (data.Frame): DataFrame of estimates in the bootstrap samples.
+        alpha (float): significance level of choice.
+        n_cores (int): number of jobs for parallelization.
+
+    Returns:
+        cis (np.array): array where k'th row contains CI for k'th parameter.
+
+    """
+
+    num_params = estimates.shape[1]
+    boot_est = estimates.values
+    cis = np.zeros((num_params, 2))
+    theta = outcome(data)
+
+    for k in range(num_params):
+
+        params = boot_est[:, k]
+        theta_std = np.std(params)
+        t = norm.ppf(alpha / 2)
+
+        cis[k, :] = np.array([theta[k] + theta_std * t, theta[k] - theta_std * t])
+
+    return cis
+
+
+def _ci_basic(data, outcome, estimates, alpha, n_cores):
+    """Compute basic bootstrap confidence interval of bootstrap estimates.
+
+    Args:
+        data (pd.DataFrame): original dataset.
+        outcome (callable): function of the data calculating statistic of interest.
+        estimates (data.Frame): DataFrame of estimates in the bootstrap samples.
+        alpha (float): significance level of choice.
+        n_cores (int): number of jobs for parallelization.
+
+    Returns:
+        cis (np.array): array where k'th row contains CI for k'th parameter.
+
+    """
+
+    num_params = estimates.shape[1]
+    boot_est = estimates.values
+    cis = np.zeros((num_params, 2))
+    theta = outcome(data)
+
+    for k in range(num_params):
+
+        q = _eqf(boot_est[:, k])
+
+        cis[k, :] = np.array(
+            [2 * theta[k] - q(1 - alpha / 2), 2 * theta[k] - q(alpha / 2)]
+        )
+
+    return cis
+
+
+def _jackknife(data, outcome, n_cores=1):
+    """Calculate leave-one-out estimator.
+
+    Args:
+        data (pd.DataFrame): original dataset.
+        n_cores (int): number of jobs for parallelization.
+
+    Returns:
+        jk_estimates (pd.DataFrame): DataFrame of estimated parameters.
+
+    """
+
+    n = len(data)
+
+    def loop(i):
+
+        df = data.drop(index=i)
+        return outcome(df)
+
+    jk_estimates = Parallel(n_jobs=n_cores)(delayed(loop)(i) for i in range(n))
+
+    return np.array(jk_estimates)
+
+
+def _eqf(sample):
+    """Return empirical quantile function of the given sample.
+
+    Args:
+        sample (pd.DataFrame): sample to base quantile function on.
+
+    Returns:
+        f (callable): quantile function for given sample.
+
+    """
+
+    def f(x):
+        return np.quantile(sample, x)
+
+    return f
diff --git a/estimagic/inference/bootstrap_helpers.py b/estimagic/inference/bootstrap_helpers.py
new file mode 100644
index 000000000..fc77f5c41
--- /dev/null
+++ b/estimagic/inference/bootstrap_helpers.py
@@ -0,0 +1,32 @@
+import pandas as pd
+
+
+def check_inputs(data, cluster_by=None, ci_method="percentile", alpha=0.05):
+    """Check validity of inputs.
+    Args:
+        data (pd.DataFrame): original dataset.
+        cluster_by (str): column name of variable to cluster by.
+        ci_method (str): method of choice for confidence interval computation.
+        alpha (float): significance level of choice.
+
+    """
+
+    ci_method_list = ["percentile", "bca", "bc", "t", "normal", "basic"]
+
+    if not isinstance(data, pd.DataFrame):
+        raise ValueError("Input 'data' must be DataFrame.")
+
+    elif (cluster_by is not None) and (cluster_by not in data.columns.tolist()):
+        raise ValueError(
+            "Input 'cluster_by' must be None or a column name of DataFrame."
+        )
+
+    elif ci_method not in ci_method_list:
+        raise ValueError(
+            "ci_method must be 'percentile', 'bc',"
+            " 'bca', 't', 'basic' or 'normal', '{method}'"
+            " was supplied".format(method=ci_method)
+        )
+
+    elif alpha > 1 or alpha < 0:
+        raise ValueError("Input 'alpha' must be in [0,1].")
diff --git a/estimagic/inference/bootstrap_outcomes.py b/estimagic/inference/bootstrap_outcomes.py
new file mode 100644
index 000000000..a6ba619ac
--- /dev/null
+++ b/estimagic/inference/bootstrap_outcomes.py
@@ -0,0 +1,105 @@
+import pandas as pd
+
+from estimagic.batch_evaluators import joblib_batch_evaluator
+from estimagic.inference.bootstrap_helpers import check_inputs
+from estimagic.inference.bootstrap_samples import get_bootstrap_indices
+
+
+def get_bootstrap_outcomes(
+    data,
+    outcome,
+    cluster_by=None,
+    seed=None,
+    n_draws=1000,
+    n_cores=1,
+    error_handling="continue",
+    batch_evaluator=joblib_batch_evaluator,
+):
+    """Draw bootstrap samples and calculate outcomes.
+
+    Args:
+        data (pandas.DataFrame): original dataset.
+        outcome (callable): function of the dataset calculating statistic of interest.
+            Needs to return array-like object or pd.Series.
+        cluster_by (str): column name of the variable to cluster by.
+        seed (int): Random seed.
+        n_draws (int): number of draws, only relevant if seeds is None.
+        n_cores (int): number of jobs for parallelization.
+        error_handling (str): One of "continue", "raise". Default "continue" which means
+            that bootstrap estimates are only calculated for those samples where no
+            errors occur and a warning is produced if any error occurs.
+        batch_evaluator (str or Callable): Name of a pre-implemented batch evaluator
+            (currently 'joblib' and 'pathos_mp') or Callable with the same interface
+            as the estimagic batch_evaluators. See :ref:`batch_evaluators`.
+
+    Returns:
+        estimates (pandas.DataFrame): Outcomes for different bootstrap samples. The
+            columns are the index of the result of ``outcome``.
+
+    """
+
+    check_inputs(data=data, cluster_by=cluster_by)
+
+    indices = get_bootstrap_indices(
+        data=data,
+        cluster_by=cluster_by,
+        seed=seed,
+        n_draws=n_draws,
+    )
+
+    estimates = _get_bootstrap_outcomes_from_indices(
+        indices=indices,
+        data=data,
+        outcome=outcome,
+        n_cores=n_cores,
+        error_handling=error_handling,
+        batch_evaluator=batch_evaluator,
+    )
+
+    return estimates
+
+
+def _get_bootstrap_outcomes_from_indices(
+    indices,
+    data,
+    outcome,
+    n_cores,
+    error_handling,
+    batch_evaluator,
+):
+
+    arguments = [{"data": data, "indices": ind, "outcome": outcome} for ind in indices]
+
+    raw_estimates = batch_evaluator(
+        _take_indices_and_calculate_outcome,
+        arguments,
+        n_cores=n_cores,
+        unpack_symbol="**",
+        error_handling=error_handling,
+    )
+
+    estimates = [est for est in raw_estimates if not isinstance(est, str)]
+    tracebacks = [est for est in raw_estimates if isinstance(est, str)]
+
+    if estimates:
+        estimates_df = pd.concat(estimates, axis=1).T
+    else:
+        msg = (
+            "Calculating of all bootstrap outcomes failed. The tracebacks of the "
+            "raised Exceptions are reproduced below:"
+        )
+        raise RuntimeError(msg + "\n\n" + "\n\n".join(tracebacks))
+
+    if tracebacks:
+        msg = (
+            "Calculating bootstrap outcomes failed for some samples. Those samples "
+            "are excluded from the calculation of bootstrap standard errors and "
+            "confidence intervals, rendering them invalid. Do not use them for "
+            "anything but diagnostic purposes. Check warnings for more information. "
+        )
+
+    return estimates_df
+
+
+def _take_indices_and_calculate_outcome(indices, data, outcome):
+    return outcome(data.iloc[indices])
diff --git a/estimagic/inference/bootstrap_samples.py b/estimagic/inference/bootstrap_samples.py
new file mode 100644
index 000000000..25385f85b
--- /dev/null
+++ b/estimagic/inference/bootstrap_samples.py
@@ -0,0 +1,91 @@
+import numpy as np
+import pandas as pd
+
+
+def get_bootstrap_indices(data, cluster_by=None, seed=None, n_draws=1000):
+    """Draw positional indices for the construction of bootstrap samples.
+
+    Storing the positional indices instead of the full bootstrap samples saves a lot
+    of memory for datasets with many variables.
+
+    Args:
+        data (pandas.DataFrame): original dataset.
+        cluster_by (str): column name of the variable to cluster by.
+        seed (int): Random seed.
+        n_draws (int): number of draws, only relevant if seeds is None.
+
+    Returns:
+        list: list of numpy arrays with positional indices
+
+    """
+    np.random.seed(seed)
+
+    n_obs = len(data)
+    if cluster_by is None:
+        bootstrap_indices = list(np.random.randint(0, n_obs, size=(n_draws, n_obs)))
+    else:
+        clusters = data[cluster_by].unique()
+        drawn_clusters = np.random.choice(
+            clusters, size=(n_draws, len(clusters)), replace=True
+        )
+
+        bootstrap_indices = _convert_cluster_ids_to_indices(
+            data[cluster_by], drawn_clusters
+        )
+
+    return bootstrap_indices
+
+
+def _convert_cluster_ids_to_indices(cluster_col, drawn_clusters):
+    """Convert the drawn clusters to positional indices of individual observations.
+
+    Args:
+        cluster_col (pandas.Series):
+
+    """
+    bootstrap_indices = []
+    cluster_to_locs = pd.Series(np.arange(len(cluster_col)), index=cluster_col)
+    for draw in drawn_clusters:
+        bootstrap_indices.append(cluster_to_locs[draw].to_numpy())
+    return bootstrap_indices
+
+
+def get_bootstrap_samples(data, cluster_by=None, seed=None, n_draws=1000):
+    """Draw bootstrap samples.
+
+    If you have memory issues you should use get_bootstrap_indices instead and construct
+    the full samples only as needed.
+
+    Args:
+        data (pandas.DataFrame): original dataset.
+        cluster_by (str): column name of the variable to cluster by.
+        seed (int): Random seed.
+        n_draws (int): number of draws, only relevant if seeds is None.
+
+    Returns:
+        list: list of resampled datasets.
+
+    """
+    indices = get_bootstrap_indices(
+        data=data,
+        cluster_by=cluster_by,
+        seed=seed,
+        n_draws=n_draws,
+    )
+    datasets = _get_bootstrap_samples_from_indices(data=data, bootstrap_indices=indices)
+    return datasets
+
+
+def _get_bootstrap_samples_from_indices(data, bootstrap_indices):
+    """convert bootstrap indices into actual bootstrap samples.
+
+    Args:
+        data (pandas.DataFrame): original dataset.
+        bootstrap_indices (list): List with numpy arrays containing positional indices
+            of observations in data.
+
+    Returns:
+        list: list of DataFrames
+    """
+    out = [data.iloc[idx] for idx in bootstrap_indices]
+    return out
diff --git a/estimagic/optimization/utilities.py b/estimagic/optimization/utilities.py
index e8a728b2c..e44e731f6 100644
--- a/estimagic/optimization/utilities.py
+++ b/estimagic/optimization/utilities.py
@@ -7,8 +7,6 @@
 from scipy.linalg import ldl
 from scipy.linalg import qr
 
-from estimagic.exceptions import get_traceback
-
 
 def chol_params_to_lower_triangular_matrix(params):
     dim = number_of_triangular_elements_to_dimension(len(params))
@@ -192,8 +190,7 @@ def robust_inverse(matrix, msg=""):
         out = np.linalg.inv(matrix)
     except np.linalg.LinAlgError:
         out = np.linalg.pinv(matrix)
-        tb = get_traceback()
-        warnings.warn(header + msg + "\n\n" + tb)
+        warnings.warn(header + msg)
     except Exception:
         raise
 


Test patch:
diff --git a/estimagic/tests/inference/test_bootstrap.py b/estimagic/tests/inference/test_bootstrap.py
new file mode 100644
index 000000000..a11cf331d
--- /dev/null
+++ b/estimagic/tests/inference/test_bootstrap.py
@@ -0,0 +1,51 @@
+import numpy as np
+import pandas as pd
+import pytest
+from pandas.testing import assert_frame_equal as afe
+
+from estimagic.inference.bootstrap import bootstrap_from_outcomes
+
+
+@pytest.fixture
+def setup():
+    out = {}
+
+    out["df"] = pd.DataFrame(
+        np.array([[1, 10], [2, 7], [3, 6], [4, 5]]), columns=["x1", "x2"]
+    )
+
+    x = np.array([[2.0, 8.0], [2.0, 8.0], [2.5, 7.0], [3.0, 6.0], [3.25, 5.75]])
+    out["estimates"] = pd.DataFrame(x, columns=["x1", "x2"])
+
+    return out
+
+
+@pytest.fixture
+def expected():
+    out = {}
+
+    z = np.array([[2.55, 0.5701, 2, 3.225], [6.95, 1.0665, 5.775, 8]])
+
+    out["results"] = pd.DataFrame(
+        z, columns=["mean", "std", "lower_ci", "upper_ci"], index=["x1", "x2"]
+    )
+
+    return out
+
+
+def g(data):
+    return data.mean(axis=0)
+
+
+def test_get_results_table(setup, expected):
+
+    results = bootstrap_from_outcomes(
+        data=setup["df"],
+        outcome=g,
+        bootstrap_outcomes=setup["estimates"],
+        ci_method="percentile",
+    )
+
+    # use rounding to adjust precision because there is no other way of handling this
+    # such that it is compatible across all supported pandas versions.
+    afe(results.round(2), expected["results"].round(2))
diff --git a/estimagic/tests/inference/test_bootstrap_ci.py b/estimagic/tests/inference/test_bootstrap_ci.py
new file mode 100644
index 000000000..9db3abb09
--- /dev/null
+++ b/estimagic/tests/inference/test_bootstrap_ci.py
@@ -0,0 +1,143 @@
+import numpy as np
+import pandas as pd
+import pytest
+from numpy.testing import assert_array_almost_equal as aaae
+
+from estimagic.inference.bootstrap_ci import _jackknife
+from estimagic.inference.bootstrap_ci import compute_ci
+from estimagic.inference.bootstrap_helpers import check_inputs
+
+
+@pytest.fixture
+def setup():
+    out = {}
+
+    out["df"] = pd.DataFrame(
+        np.array([[1, 10], [2, 7], [3, 6], [4, 5]]), columns=["x1", "x2"]
+    )
+
+    x = np.array([[2.0, 8.0], [2.0, 8.0], [2.5, 7.0], [3.0, 6.0], [3.25, 5.75]])
+    out["estimates"] = pd.DataFrame(x, columns=["x1", "x2"])
+
+    return out
+
+
+@pytest.fixture
+def expected():
+    out = {}
+
+    out["percentile_ci"] = np.array([[2, 3.225], [5.775, 8.0]])
+
+    out["normal_ci"] = np.array(
+        [
+            [1.5006105396891194, 3.499389460310881],
+            [5.130313521781885, 8.869686478218114],
+        ]
+    )
+
+    out["basic_ci"] = np.array([[1.775, 3.0], [6.0, 8.225]])
+
+    out["bc_ci"] = np.array([[2, 3.2342835077057543], [5.877526959881923, 8]])
+
+    out["bca_ci"] = np.array([[2, 3.2058815797003826], [5.9404612332752915, 8]])
+
+    out["t_ci"] = np.array([[1.775, 3], [6.0, 8.225]])
+
+    out["jk_estimates"] = np.array(
+        [
+            [3, 6],
+            [2.6666666666666665, 7],
+            [2.3333333333333335, 7.333333333333333],
+            [2, 7.666666666666667],
+        ]
+    )
+
+    return out
+
+
+def g(data):
+    return data.mean(axis=0)
+
+
+def g_arr(data):
+    return np.array(data.mean(axis=0))
+
+
+def h(data):
+    return 2 * g(data)
+
+
+def h_arr(data):
+    return 2 * g_arr(data)
+
+
+def test_percentile_ci(setup, expected):
+    percentile_ci = compute_ci(
+        setup["df"], g, setup["estimates"], ci_method="percentile"
+    )
+    aaae(percentile_ci, expected["percentile_ci"])
+
+
+def test_normal_ci(setup, expected):
+    normal_ci = compute_ci(setup["df"], g, setup["estimates"], ci_method="normal")
+    aaae(normal_ci, expected["normal_ci"])
+
+
+def test_basic_ci(setup, expected):
+    basic_ci = compute_ci(setup["df"], g, setup["estimates"], ci_method="basic")
+    aaae(basic_ci, expected["basic_ci"])
+
+
+def test_bc_ci(setup, expected):
+    bc_ci = compute_ci(setup["df"], g, setup["estimates"], ci_method="bc")
+    aaae(bc_ci, expected["bc_ci"])
+
+
+def test_bca_ci(setup, expected):
+    bca_ci = compute_ci(setup["df"], g, setup["estimates"], ci_method="bca")
+    aaae(bca_ci, expected["bca_ci"])
+
+
+def test_t_ci(setup, expected):
+    t_ci = compute_ci(setup["df"], g, setup["estimates"], ci_method="t")
+    aaae(t_ci, expected["t_ci"])
+
+
+def test_jackknife(setup, expected):
+    jk_estimates = _jackknife(setup["df"], g)
+    aaae(jk_estimates, expected["jk_estimates"])
+
+
+def test_check_inputs_data(setup, expected):
+    data = "this is not a data frame"
+    with pytest.raises(ValueError) as excinfo:
+        check_inputs(data=data)
+    assert "Input 'data' must be DataFrame." == str(excinfo.value)
+
+
+def test_check_inputs_cluster_by(setup, expected):
+    cluster_by = "this is not a column name of df"
+    with pytest.raises(ValueError) as excinfo:
+        check_inputs(data=setup["df"], cluster_by=cluster_by)
+    assert "Input 'cluster_by' must be None or a column name of DataFrame." == str(
+        excinfo.value
+    )
+
+
+def test_check_inputs_ci_method(setup, expected):
+    ci_method = 4
+    with pytest.raises(ValueError) as excinfo:
+        check_inputs(data=setup["df"], ci_method=ci_method)
+    expected_msg = (
+        "ci_method must be 'percentile', 'bc',"
+        f" 'bca', 't', 'basic' or 'normal', '{ci_method}'"
+        f" was supplied"
+    )
+    assert str(excinfo.value) == expected_msg
+
+
+def test_check_inputs_alpha(setup, expected):
+    alpha = 666
+    with pytest.raises(ValueError) as excinfo:
+        check_inputs(data=setup["df"], alpha=alpha)
+    assert "Input 'alpha' must be in [0,1]." == str(excinfo.value)
diff --git a/estimagic/tests/inference/test_bootstrap_outcomes.py b/estimagic/tests/inference/test_bootstrap_outcomes.py
new file mode 100644
index 000000000..b02bb747c
--- /dev/null
+++ b/estimagic/tests/inference/test_bootstrap_outcomes.py
@@ -0,0 +1,81 @@
+import functools
+
+import numpy as np
+import pandas as pd
+import pytest
+from pandas.testing import assert_frame_equal as afe
+
+from estimagic.batch_evaluators import joblib_batch_evaluator
+from estimagic.inference.bootstrap_outcomes import (
+    _get_bootstrap_outcomes_from_indices,
+)
+from estimagic.inference.bootstrap_outcomes import get_bootstrap_outcomes
+
+
+@pytest.fixture
+def data():
+    df = pd.DataFrame([[1, 10], [2, 7], [3, 6], [4, 5]], columns=["x1", "x2"])
+    return df
+
+
+def test_get_bootstrap_estimates_runs(data):
+    get_bootstrap_outcomes(
+        data=data,
+        outcome=functools.partial(np.mean, axis=0),
+        n_draws=5,
+    )
+
+
+def test_bootstrap_estimates_from_indices_without_errors(data):
+    calculated = _get_bootstrap_outcomes_from_indices(
+        indices=[np.array([1, 3]), np.array([0, 2])],
+        data=data,
+        outcome=functools.partial(np.mean, axis=0),
+        n_cores=1,
+        error_handling="raise",
+        batch_evaluator=joblib_batch_evaluator,
+    )
+
+    expected = pd.DataFrame([[3.0, 6.0], [2, 8]], columns=["x1", "x2"])
+    afe(calculated, expected)
+
+
+def test_get_bootstrap_estimates_with_error_and_raise(data):
+    def _raise_assertion_error(data):
+        assert 1 == 2
+
+    with pytest.raises(AssertionError):
+        get_bootstrap_outcomes(
+            data=data, outcome=_raise_assertion_error, n_draws=2, error_handling="raise"
+        )
+
+
+def test_get_bootstrap_estimates_with_all_errors_and_continue(data):
+    def _raise_assertion_error(data):
+        assert 1 == 2
+
+    with pytest.warns(UserWarning):
+        with pytest.raises(RuntimeError):
+            get_bootstrap_outcomes(
+                data=data,
+                outcome=_raise_assertion_error,
+                n_draws=2,
+                error_handling="continue",
+            )
+
+
+def test_get_bootstrap_estimates_with_some_errors_and_continue(data):
+    def _raise_assertion_error_sometimes(data):
+        assert np.random.uniform() > 0.5
+        return data.mean()
+
+    with pytest.warns(UserWarning):
+        res = get_bootstrap_outcomes(
+            data=data,
+            outcome=_raise_assertion_error_sometimes,
+            n_draws=100,
+            error_handling="continue",
+            seed=123,
+        )
+
+    assert 30 <= len(res) <= 70
diff --git a/estimagic/tests/inference/test_bootstrap_samples.py b/estimagic/tests/inference/test_bootstrap_samples.py
new file mode 100644
index 000000000..375a8014b
--- /dev/null
+++ b/estimagic/tests/inference/test_bootstrap_samples.py
@@ -0,0 +1,60 @@
+import numpy as np
+import pandas as pd
+import pytest
+from numpy.testing import assert_array_equal as aae
+from pandas.testing import assert_frame_equal as afe
+
+from estimagic.inference.bootstrap_samples import _convert_cluster_ids_to_indices
+from estimagic.inference.bootstrap_samples import _get_bootstrap_samples_from_indices
+from estimagic.inference.bootstrap_samples import get_bootstrap_indices
+from estimagic.inference.bootstrap_samples import get_bootstrap_samples
+
+
+@pytest.fixture
+def data():
+    df = pd.DataFrame()
+    df["id"] = np.arange(900)
+    df["hh"] = [3, 1, 2, 0, 0, 2, 5, 4, 5] * 100
+    return df
+
+
+def test_get_bootstrap_indices_randomization_works_without_clustering(data):
+    np.random.seed(1234)
+    res = get_bootstrap_indices(data, n_draws=2)
+    assert set(res[0]) != set(res[1])
+
+
+def test_get_bootstrap_indices_radomization_works_with_clustering(data):
+    res = get_bootstrap_indices(data, cluster_by="hh", n_draws=2, seed=12345)
+    assert set(res[0]) != set(res[1])
+
+
+def test_clustering_leaves_households_intact(data):
+    np.random.seed(1234)
+    indices = get_bootstrap_indices(data, cluster_by="hh", n_draws=1)[0]
+    sampled = data.iloc[indices]
+    sampled_households = sampled["hh"].unique()
+    for household in sampled_households:
+        expected_ids = set(data[data["hh"] == household]["id"].unique())
+        actual_ids = set(sampled[sampled["hh"] == household]["id"].unique())
+        assert expected_ids == actual_ids
+
+
+def test_convert_cluster_ids_to_indices():
+    cluster_col = pd.Series([2, 2, 0, 1, 0, 1])
+    drawn_clusters = np.array([[1, 0]])
+    expected = np.array([3, 5, 2, 4])
+    calculated = _convert_cluster_ids_to_indices(cluster_col, drawn_clusters)[0]
+    aae(calculated, expected)
+
+
+def test_get_bootstrap_samples_from_indices():
+    indices = [np.array([0, 1])]
+    data = pd.DataFrame(np.arange(6).reshape(3, 2))
+    expected = pd.DataFrame(np.arange(4).reshape(2, 2))
+    calculated = _get_bootstrap_samples_from_indices(data, indices)[0]
+    afe(calculated, expected)
+
+
+def test_get_bootstrap_samples_runs(data):
+    get_bootstrap_samples(data, n_draws=2, seed=1234)
diff --git a/estimagic/tests/test_batch_evaluators.py b/estimagic/tests/test_batch_evaluators.py
index 3ebd0a4c0..1f3c7d8fa 100644
--- a/estimagic/tests/test_batch_evaluators.py
+++ b/estimagic/tests/test_batch_evaluators.py
@@ -1,5 +1,4 @@
 import itertools
-import sys
 import warnings
 
 import pytest
@@ -28,7 +27,7 @@ def add_x_and_y(x, y):
     return x + y
 
 
-@pytest.mark.skipif(sys.platform == "darwin", reason="Too slow on Mac OS CI server.")
+@pytest.mark.slow
 @pytest.mark.parametrize("batch_evaluator, n_cores", test_cases)
 def test_batch_evaluator_without_exceptions(batch_evaluator, n_cores):
 
@@ -43,7 +42,7 @@ def test_batch_evaluator_without_exceptions(batch_evaluator, n_cores):
     assert calculated == expected
 
 
-@pytest.mark.skipif(sys.platform == "darwin", reason="Too slow on Mac OS CI server.")
+@pytest.mark.slow
 @pytest.mark.parametrize("batch_evaluator, n_cores", test_cases)
 def test_batch_evaluator_with_unhandled_exceptions(batch_evaluator, n_cores):
     with pytest.raises(AssertionError):
@@ -72,7 +71,7 @@ def test_batch_evaluator_with_handled_exceptions(batch_evaluator, n_cores):
             assert isinstance(calc, str)
 
 
-@pytest.mark.skipif(sys.platform == "darwin", reason="Too slow on Mac OS CI server.")
+@pytest.mark.slow
 @pytest.mark.parametrize("batch_evaluator, n_cores", test_cases)
 def test_batch_evaluator_with_list_unpacking(batch_evaluator, n_cores):
     calculated = batch_evaluator(
@@ -85,7 +84,7 @@ def test_batch_evaluator_with_list_unpacking(batch_evaluator, n_cores):
     assert calculated == expected
 
 
-@pytest.mark.skipif(sys.platform == "darwin", reason="Too slow on Mac OS CI server.")
+@pytest.mark.slow
 @pytest.mark.parametrize("batch_evaluator, n_cores", test_cases)
 def test_batch_evaluator_with_dict_unpacking(batch_evaluator, n_cores):
     calculated = batch_evaluator(