{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "1bba0128",
   "metadata": {},
   "source": [
    "# Central Limit Theorem example\n",
    "\n",
    "Here, we try adding uniform distributions a few times and we quickly end up with a Gaussian.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "23feddde",
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import Optional\n",
    "\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "\n",
    "import matplotlib.pylab as pylab\n",
    "params = {'legend.fontsize': 'x-large',\n",
    "          'figure.figsize': (15, 5),\n",
    "         'axes.labelsize': 'x-large',\n",
    "         'axes.titlesize':'x-large',\n",
    "         'xtick.labelsize':'x-large',\n",
    "         'ytick.labelsize':'x-large'}\n",
    "pylab.rcParams.update(params)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bb1286f0",
   "metadata": {},
   "source": [
    "The idea is simple: generate random values between $-1$ and $1$ and make a histogram of them. The histogram will look like a box.\n",
    "\n",
    "The Central Limit Theorem tells us that the mean of $N$ variables with variance $\\sigma^2$ is a Gaussian with variance $\\sigma^2/N$ in the limit that $N \\rightarrow \\infty$.\n",
    "\n",
    "Notice that the variance of this uniform distribution is not 1: calculate it, and you will see that its variance is 1/3 (so $\\sqrt{\\text{var}}=\\sqrt{3}/3\\approxeq 0.57$). We will see that below.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "aef54435-78af-4b13-aee2-2bc576c773cd",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# this generates random uniform samples\n",
    "def random_samples(n_samples: int) -> np.ndarray:\n",
    "    return (2*np.random.rand(n_samples) - 1)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "04432613-39cd-4209-8833-7af585e7eed9",
   "metadata": {},
   "source": [
    "Let's make a function to generate samples."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "7ea0322e-a35c-4603-ad46-8b9fd4c216c0",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "n_samples = 10000\n",
    "x = random_samples(n_samples)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ae05df16-29b2-4039-a6c2-db7a98e5c22f",
   "metadata": {},
   "source": [
    "x has now arbitrary numbers between $-1$ and $1$:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "3f57aeb7-4148-4ba5-b6eb-b600779ef0db",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "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>x</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>-0.436331</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>-0.639195</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0.458218</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0.248118</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>-0.769285</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9995</th>\n",
       "      <td>-0.104365</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9996</th>\n",
       "      <td>0.246559</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9997</th>\n",
       "      <td>-0.747142</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9998</th>\n",
       "      <td>-0.283905</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9999</th>\n",
       "      <td>-0.087743</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>10000 rows × 1 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "             x\n",
       "0    -0.436331\n",
       "1    -0.639195\n",
       "2     0.458218\n",
       "3     0.248118\n",
       "4    -0.769285\n",
       "...        ...\n",
       "9995 -0.104365\n",
       "9996  0.246559\n",
       "9997 -0.747142\n",
       "9998 -0.283905\n",
       "9999 -0.087743\n",
       "\n",
       "[10000 rows x 1 columns]"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.DataFrame(dict(x=x))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e6639893-7572-4e93-a13d-2851d8da624f",
   "metadata": {},
   "source": [
    "Let's check its mean and variance:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "db02f31d-3cde-4dd1-be2e-fdecaff39c2d",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "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>x</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>count</th>\n",
       "      <td>10000.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>mean</th>\n",
       "      <td>0.005463</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>std</th>\n",
       "      <td>0.581949</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>min</th>\n",
       "      <td>-0.999997</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25%</th>\n",
       "      <td>-0.502165</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>50%</th>\n",
       "      <td>0.006750</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>75%</th>\n",
       "      <td>0.515157</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>max</th>\n",
       "      <td>0.999962</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                  x\n",
       "count  10000.000000\n",
       "mean       0.005463\n",
       "std        0.581949\n",
       "min       -0.999997\n",
       "25%       -0.502165\n",
       "50%        0.006750\n",
       "75%        0.515157\n",
       "max        0.999962"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pd.DataFrame(dict(x=x)).describe()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0f63c4cd-2479-4498-8de4-bf1c378c5545",
   "metadata": {},
   "source": [
    "We can make a histogram of it to try to double check:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "fead461d-4d3a-48f2-a525-c518be4f1cf8",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.\n",
      "  with pd.option_context('mode.use_inf_as_na', True):\n",
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.\n",
      "  data_subset = grouped_data.get_group(pd_key)\n",
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.\n",
      "  data_subset = grouped_data.get_group(pd_key)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[Text(0, 0.5, 'Fraction of occurrences / bin size'), Text(0.5, 0, 'x')]"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 30092 characters]",
      "text/plain": [
       "<Figure size 1500x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "sns.histplot(pd.DataFrame(dict(x=x)), stat=\"density\")\n",
    "plt.gca().set(ylabel=\"Fraction of occurrences / bin size\", xlabel=\"x\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "00e098e8-0082-4451-927a-073cf242787e",
   "metadata": {},
   "source": [
    "It looks like the probability of getting a specific x value is indeed the same for all x in the range [-1, 1].\n",
    "\n",
    "Let's get values of x independently and sum them $N$ times:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "08d9daaf-25c5-4d06-b4a6-6cecaaa35651",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def get_many_x(N: int) -> pd.DataFrame:\n",
    "    return pd.DataFrame({f\"x{k}\": random_samples(n_samples) for k in range(N)})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "998baa6c-dc2e-42bc-85a5-295a63db95ea",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "N = 10\n",
    "data = get_many_x(N=10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "2195bfb9-acec-47e7-8bae-64a2671eb09d",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "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>x0</th>\n",
       "      <th>x1</th>\n",
       "      <th>x2</th>\n",
       "      <th>x3</th>\n",
       "      <th>x4</th>\n",
       "      <th>x5</th>\n",
       "      <th>x6</th>\n",
       "      <th>x7</th>\n",
       "      <th>x8</th>\n",
       "      <th>x9</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>-0.021048</td>\n",
       "      <td>0.624256</td>\n",
       "      <td>-0.213331</td>\n",
       "      <td>0.873981</td>\n",
       "      <td>-0.744169</td>\n",
       "      <td>-0.295821</td>\n",
       "      <td>0.033295</td>\n",
       "      <td>-0.249991</td>\n",
       "      <td>0.482630</td>\n",
       "      <td>0.892960</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>-0.481733</td>\n",
       "      <td>0.707507</td>\n",
       "      <td>0.250378</td>\n",
       "      <td>-0.289964</td>\n",
       "      <td>0.192630</td>\n",
       "      <td>-0.117562</td>\n",
       "      <td>0.553985</td>\n",
       "      <td>0.511281</td>\n",
       "      <td>-0.841345</td>\n",
       "      <td>0.200531</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>-0.317442</td>\n",
       "      <td>0.502972</td>\n",
       "      <td>0.375717</td>\n",
       "      <td>0.033442</td>\n",
       "      <td>-0.281267</td>\n",
       "      <td>0.300927</td>\n",
       "      <td>-0.598245</td>\n",
       "      <td>0.843422</td>\n",
       "      <td>-0.629739</td>\n",
       "      <td>-0.069668</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>-0.161197</td>\n",
       "      <td>0.732069</td>\n",
       "      <td>0.441334</td>\n",
       "      <td>0.868591</td>\n",
       "      <td>0.635648</td>\n",
       "      <td>-0.168180</td>\n",
       "      <td>-0.673598</td>\n",
       "      <td>-0.165261</td>\n",
       "      <td>-0.806899</td>\n",
       "      <td>-0.753438</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>-0.371950</td>\n",
       "      <td>-0.188998</td>\n",
       "      <td>-0.219916</td>\n",
       "      <td>0.815982</td>\n",
       "      <td>0.127839</td>\n",
       "      <td>-0.533913</td>\n",
       "      <td>0.075909</td>\n",
       "      <td>0.098488</td>\n",
       "      <td>0.563604</td>\n",
       "      <td>-0.334205</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",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9995</th>\n",
       "      <td>0.815217</td>\n",
       "      <td>0.136989</td>\n",
       "      <td>-0.264895</td>\n",
       "      <td>0.950940</td>\n",
       "      <td>-0.402690</td>\n",
       "      <td>0.816257</td>\n",
       "      <td>-0.848535</td>\n",
       "      <td>-0.520143</td>\n",
       "      <td>-0.564143</td>\n",
       "      <td>0.758220</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9996</th>\n",
       "      <td>-0.601188</td>\n",
       "      <td>0.329444</td>\n",
       "      <td>0.400244</td>\n",
       "      <td>-0.631055</td>\n",
       "      <td>-0.035561</td>\n",
       "      <td>-0.479244</td>\n",
       "      <td>0.151432</td>\n",
       "      <td>-0.260616</td>\n",
       "      <td>-0.735051</td>\n",
       "      <td>0.219002</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9997</th>\n",
       "      <td>-0.577752</td>\n",
       "      <td>-0.498329</td>\n",
       "      <td>-0.637509</td>\n",
       "      <td>-0.720854</td>\n",
       "      <td>0.519939</td>\n",
       "      <td>-0.315098</td>\n",
       "      <td>0.610658</td>\n",
       "      <td>-0.587285</td>\n",
       "      <td>0.542854</td>\n",
       "      <td>0.783085</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9998</th>\n",
       "      <td>-0.390503</td>\n",
       "      <td>-0.137664</td>\n",
       "      <td>-0.201412</td>\n",
       "      <td>-0.199943</td>\n",
       "      <td>-0.997903</td>\n",
       "      <td>-0.017195</td>\n",
       "      <td>-0.712091</td>\n",
       "      <td>0.725895</td>\n",
       "      <td>0.888849</td>\n",
       "      <td>-0.100168</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9999</th>\n",
       "      <td>0.551831</td>\n",
       "      <td>0.910650</td>\n",
       "      <td>-0.487670</td>\n",
       "      <td>0.332045</td>\n",
       "      <td>-0.596616</td>\n",
       "      <td>-0.212282</td>\n",
       "      <td>0.234631</td>\n",
       "      <td>-0.845725</td>\n",
       "      <td>0.166181</td>\n",
       "      <td>-0.126873</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>10000 rows × 10 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "            x0        x1        x2        x3        x4        x5        x6  \\\n",
       "0    -0.021048  0.624256 -0.213331  0.873981 -0.744169 -0.295821  0.033295   \n",
       "1    -0.481733  0.707507  0.250378 -0.289964  0.192630 -0.117562  0.553985   \n",
       "2    -0.317442  0.502972  0.375717  0.033442 -0.281267  0.300927 -0.598245   \n",
       "3    -0.161197  0.732069  0.441334  0.868591  0.635648 -0.168180 -0.673598   \n",
       "4    -0.371950 -0.188998 -0.219916  0.815982  0.127839 -0.533913  0.075909   \n",
       "...        ...       ...       ...       ...       ...       ...       ...   \n",
       "9995  0.815217  0.136989 -0.264895  0.950940 -0.402690  0.816257 -0.848535   \n",
       "9996 -0.601188  0.329444  0.400244 -0.631055 -0.035561 -0.479244  0.151432   \n",
       "9997 -0.577752 -0.498329 -0.637509 -0.720854  0.519939 -0.315098  0.610658   \n",
       "9998 -0.390503 -0.137664 -0.201412 -0.199943 -0.997903 -0.017195 -0.712091   \n",
       "9999  0.551831  0.910650 -0.487670  0.332045 -0.596616 -0.212282  0.234631   \n",
       "\n",
       "            x7        x8        x9  \n",
       "0    -0.249991  0.482630  0.892960  \n",
       "1     0.511281 -0.841345  0.200531  \n",
       "2     0.843422 -0.629739 -0.069668  \n",
       "3    -0.165261 -0.806899 -0.753438  \n",
       "4     0.098488  0.563604 -0.334205  \n",
       "...        ...       ...       ...  \n",
       "9995 -0.520143 -0.564143  0.758220  \n",
       "9996 -0.260616 -0.735051  0.219002  \n",
       "9997 -0.587285  0.542854  0.783085  \n",
       "9998  0.725895  0.888849 -0.100168  \n",
       "9999 -0.845725  0.166181 -0.126873  \n",
       "\n",
       "[10000 rows x 10 columns]"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "90c7b417-4b22-4788-9cb4-b9a63f42a1b2",
   "metadata": {},
   "source": [
    "Each x column has independent values of a uniform distribution. We can double check that:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "aa75ce65-2e94-4d64-93ca-80bb953e81d1",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.\n",
      "  with pd.option_context('mode.use_inf_as_na', True):\n",
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.\n",
      "  data_subset = grouped_data.get_group(pd_key)\n",
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.\n",
      "  data_subset = grouped_data.get_group(pd_key)\n",
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.\n",
      "  data_subset = grouped_data.get_group(pd_key)\n",
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.\n",
      "  data_subset = grouped_data.get_group(pd_key)\n",
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.\n",
      "  data_subset = grouped_data.get_group(pd_key)\n",
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.\n",
      "  data_subset = grouped_data.get_group(pd_key)\n",
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.\n",
      "  data_subset = grouped_data.get_group(pd_key)\n",
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.\n",
      "  data_subset = grouped_data.get_group(pd_key)\n",
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.\n",
      "  data_subset = grouped_data.get_group(pd_key)\n",
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.\n",
      "  data_subset = grouped_data.get_group(pd_key)\n",
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.\n",
      "  data_subset = grouped_data.get_group(pd_key)\n",
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.\n",
      "  data_subset = grouped_data.get_group(pd_key)\n",
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.\n",
      "  data_subset = grouped_data.get_group(pd_key)\n",
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.\n",
      "  data_subset = grouped_data.get_group(pd_key)\n",
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.\n",
      "  data_subset = grouped_data.get_group(pd_key)\n",
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.\n",
      "  data_subset = grouped_data.get_group(pd_key)\n",
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.\n",
      "  data_subset = grouped_data.get_group(pd_key)\n",
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.\n",
      "  data_subset = grouped_data.get_group(pd_key)\n",
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.\n",
      "  data_subset = grouped_data.get_group(pd_key)\n",
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.\n",
      "  data_subset = grouped_data.get_group(pd_key)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[Text(0, 0.5, 'Fraction of occurrences / bin size'), Text(0.5, 0, 'x')]"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 68088 characters]",
      "text/plain": [
       "<Figure size 1500x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "sns.histplot(data.loc[:, [f\"x{k}\" for k in range(N)]], stat=\"density\")\n",
    "plt.gca().set(ylabel=\"Fraction of occurrences / bin size\", xlabel=\"x\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f7b8daf9-dd92-49d2-96e7-88f8c0f2758e",
   "metadata": {},
   "source": [
    "They all look mostly flat. Now let's create a new variable, called \"mean_x_0_{k}\", which will be the mean of the x variables from 0 until the k-th element:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "a4b370e3-bd2b-4ca2-b13f-d71fe875f89f",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "for k in range(N):\n",
    "    data[f\"mean_x_0_{k}\"] = sum(data.loc[:, f\"x{i}\"] for i in range(k+1))/float(k+1)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fa184b55-e5ae-4b73-947e-747856f0ab05",
   "metadata": {},
   "source": [
    "Let's histogram these sums:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "437d8afb-414a-4ec6-8f5a-cdaf97136183",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.\n",
      "  with pd.option_context('mode.use_inf_as_na', True):\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 61196 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.\n",
      "  with pd.option_context('mode.use_inf_as_na', True):\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 60744 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.\n",
      "  with pd.option_context('mode.use_inf_as_na', True):\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 60216 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.\n",
      "  with pd.option_context('mode.use_inf_as_na', True):\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 59660 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.\n",
      "  with pd.option_context('mode.use_inf_as_na', True):\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 60016 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.\n",
      "  with pd.option_context('mode.use_inf_as_na', True):\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 61292 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.\n",
      "  with pd.option_context('mode.use_inf_as_na', True):\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 62100 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.\n",
      "  with pd.option_context('mode.use_inf_as_na', True):\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 62112 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.\n",
      "  with pd.option_context('mode.use_inf_as_na', True):\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 54384 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.\n",
      "  with pd.option_context('mode.use_inf_as_na', True):\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 54284 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "original_variance = 1/3\n",
    "for k in range(N):\n",
    "    nbins = 20\n",
    "    fig = plt.figure(figsize=(10, 8))\n",
    "    sns.histplot(data=data, x=f\"mean_x_0_{k}\", bins=nbins, stat=\"density\", label=\"Data\")\n",
    "    xg = np.linspace(-1.5, 1.5, 100)\n",
    "    yg = 1/np.sqrt(2*np.pi*original_variance/(k+1))*np.exp(-xg**2/2/(original_variance/(k+1)))\n",
    "    plt.plot(xg, yg, label=r\"Gaussian $\\left(\\sigma^2 = \\frac{1}{3 * \"+f\"{k+1}\"+r\"}\\right)$\", ls=\"--\", color=\"r\", lw=4)\n",
    "    plt.gca().set(xlabel=r\"$\\frac{1}{\"+f\"{k+1}\"+r\"}\\sum_{k=0}^{\"+f\"{k+1}\"+r\"} x_{k}$\", ylabel=\"Fraction of occurrences / bin size\", ylim=(0, np.amax(yg)*1.1))\n",
    "    plt.legend(frameon=False, loc=\"upper left\")\n",
    "    plt.savefig(f\"clt_{k}.png\")\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "a1fbd00b-e7f2-4eff-90db-e1d44d104fba",
   "metadata": {},
   "outputs": [],
   "source": [
    "# mean for 1000 variables:\n",
    "mean_many = sum(random_samples(n_samples) for k in range(1000))/1000"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "20617a26-0fd6-4b00-a096-53b917760a35",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/daniloefl/miniconda3/envs/ml/lib/python3.12/site-packages/seaborn/_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.\n",
      "  with pd.option_context('mode.use_inf_as_na', True):\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 58076 characters]",
      "text/plain": [
       "<Figure size 1000x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "nbins = 20\n",
    "fig = plt.figure(figsize=(10, 8))\n",
    "sns.histplot(data=mean_many, bins=nbins, stat=\"density\", label=\"Data\")\n",
    "xg = np.linspace(-0.1, 0.1, 100)\n",
    "yg = 1/np.sqrt(2*np.pi/3/1000)*np.exp(-xg**2/2/(1/3/1000))\n",
    "plt.plot(xg, yg, label=r\"Gaussian $\\left(\\sigma^2 = \\frac{1}{3000}\\right)$\", ls=\"--\", color=\"r\", lw=4)\n",
    "plt.gca().set(xlabel=r\"$\\frac{1}{1000}\\sum_{k=0}^{1000} x_{k}$\", ylabel=\"Fraction of occurrences / bin size\", ylim=(0, np.amax(yg)*1.1))\n",
    "plt.legend(frameon=False, loc=\"upper left\")\n",
    "plt.savefig(f\"clt_many.png\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4f2b94b4-465d-4cfc-bed9-d70813939592",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
